depth buffering
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
LDFLAGS = -lglfw -lvulkan -ldl -lpthread -lm
|
||||
|
||||
CFLAGS = -g -pedantic -Wall -Wextra -Wshadow -Wunused-macros
|
||||
CFLAGS = -g -pedantic -Wall -Wextra -Wshadow -Wunused-macros
|
||||
|
||||
VulkanApplication: main.c
|
||||
gcc $(CFLAGS) -o VulkanApplication main.c $(LDFLAGS)
|
||||
|
||||
BIN
images/statue.ppm
Normal file
BIN
images/statue.ppm
Normal file
Binary file not shown.
690
main.c
690
main.c
@@ -63,21 +63,35 @@ struct UniformBufferObject {
|
||||
} UniformBufferObject;
|
||||
|
||||
typedef struct Vertex {
|
||||
Vec2 pos;
|
||||
Vec3 pos;
|
||||
Vec3 color;
|
||||
Vec2 texCoord;
|
||||
} Vertex;
|
||||
|
||||
#define VERTEX_COUNT 4
|
||||
static const Vertex vertices[VERTEX_COUNT] = {
|
||||
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
|
||||
struct PPM {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t maxVal;
|
||||
void* pixels;
|
||||
};
|
||||
|
||||
#define INDEX_COUNT 6
|
||||
#define VERTEX_COUNT 8
|
||||
static const Vertex vertices[VERTEX_COUNT] = {
|
||||
{{0.5f, -0.5f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.0f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
|
||||
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
};
|
||||
|
||||
#define INDEX_COUNT 12
|
||||
static const uint16_t indices[INDEX_COUNT] = {
|
||||
0, 1, 2, 2, 3, 0
|
||||
0, 1, 2, 2, 3, 0,
|
||||
4, 5, 6, 6, 7, 4
|
||||
};
|
||||
|
||||
struct VulkanData {
|
||||
@@ -117,6 +131,13 @@ struct VulkanData {
|
||||
void* uniformBuffersMapped[MAX_FRAMES_IN_FLIGHT];
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkDescriptorSet descriptorSets[MAX_FRAMES_IN_FLIGHT];
|
||||
VkImage textureImage;
|
||||
VkDeviceMemory textureImageMemory;
|
||||
VkImageView textureImageView;
|
||||
VkSampler textureSampler;
|
||||
VkImage depthImage;
|
||||
VkDeviceMemory depthImageMemory;
|
||||
VkImageView depthImageView;
|
||||
};
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
@@ -127,7 +148,7 @@ struct SwapChainSupportDetails {
|
||||
|
||||
struct Optional {
|
||||
uint32_t v;
|
||||
uint32_t is_some;
|
||||
bool is_some;
|
||||
};
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
@@ -240,6 +261,73 @@ GLFWwindow* initWindow(struct VulkanData* data) {
|
||||
return window;
|
||||
}
|
||||
|
||||
static VkImageView createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, struct VulkanData* data) {
|
||||
VkImageViewCreateInfo viewInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = format,
|
||||
.subresourceRange.aspectMask = aspectFlags,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.baseArrayLayer = 0,
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
|
||||
VkImageView imageView;
|
||||
if (vkCreateImageView(data->device, &viewInfo, NULL, &imageView) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create texture image view\n");
|
||||
exit(1);
|
||||
}
|
||||
return imageView;
|
||||
}
|
||||
|
||||
static VkCommandBuffer beginSingleTimeCommands(bool graphics, struct VulkanData* data) {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
if (graphics) {
|
||||
allocInfo.commandPool = data->commandPool;
|
||||
} else {
|
||||
allocInfo.commandPool = data->transferCommandPool;
|
||||
}
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(data->device, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
static void endSingleTimeCommands(VkCommandBuffer commandBuffer, bool graphics, struct VulkanData* data) {
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &commandBuffer,
|
||||
};
|
||||
|
||||
if (graphics) {
|
||||
vkQueueSubmit(data->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(data->graphicsQueue);
|
||||
vkFreeCommandBuffers(data->device, data->commandPool, 1, &commandBuffer);
|
||||
} else {
|
||||
vkQueueSubmit(data->transferQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(data->transferQueue);
|
||||
vkFreeCommandBuffers(data->device, data->transferCommandPool, 1, &commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkValidationLayerSupport() {
|
||||
uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, NULL);
|
||||
@@ -323,6 +411,20 @@ static void createInstance(struct VulkanData* data) {
|
||||
printf("\t%s\n", extensions[i]);
|
||||
}
|
||||
|
||||
// const VkBool32 setting_validate_core = VK_TRUE;
|
||||
// const VkBool32 setting_validate_best_practices = VK_TRUE;
|
||||
// const VkLayerSettingEXT settings[] = {
|
||||
// {VALIDATION_LAYERS[0], "validate_core", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &setting_validate_core},
|
||||
// {VALIDATION_LAYERS[0], "validate_best_practices", VK_LAYER_SETTING_TYPE_BOOL32_EXT, 1, &setting_validate_best_practices}
|
||||
// };
|
||||
// const VkLayerSettingsCreateInfoEXT layer_settings_create_info = {
|
||||
// VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
|
||||
// NULL,
|
||||
// 1,
|
||||
// settings
|
||||
// };
|
||||
|
||||
|
||||
VkInstanceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pApplicationInfo = &appInfo,
|
||||
@@ -341,7 +443,7 @@ static void createInstance(struct VulkanData* data) {
|
||||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||
.pfnUserCallback = debugCallback,
|
||||
};
|
||||
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
|
||||
createInfo.pNext = &debugCreateInfo;
|
||||
} else {
|
||||
createInfo.enabledLayerCount = 0;
|
||||
createInfo.pNext = NULL;
|
||||
@@ -494,7 +596,7 @@ static bool isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surfa
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
||||
printf("GPU: %s\n", deviceProperties.deviceName);
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
int featureCount = sizeof(deviceFeatures) / 4;
|
||||
int featureCount = sizeof(deviceFeatures) / sizeof(deviceFeatures.robustBufferAccess);
|
||||
VkBool32* p = &deviceFeatures.robustBufferAccess;
|
||||
for (int i = 0; i < featureCount; i++) {
|
||||
*p = VK_FALSE;
|
||||
@@ -512,7 +614,7 @@ static bool isDeviceSuitable(VkPhysicalDevice physicalDevice, VkSurfaceKHR surfa
|
||||
|
||||
return
|
||||
deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
|
||||
deviceFeatures.geometryShader &&
|
||||
deviceFeatures.geometryShader && deviceFeatures.samplerAnisotropy &&
|
||||
swapChainAdequate &&
|
||||
familyIndices.graphicsFamily.is_some && familyIndices.presentFamily.is_some && familyIndices.transferFamily.is_some;
|
||||
}
|
||||
@@ -583,6 +685,7 @@ static void createLogicalDevice(struct VulkanData* data) {
|
||||
*p = VK_FALSE;
|
||||
p++;
|
||||
}
|
||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
@@ -708,24 +811,7 @@ static void createSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
|
||||
static void createImageViews(struct VulkanData* data) {
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
VkImageViewCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = data->swapChainImages[i],
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = data->swapChainImageFormat,
|
||||
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.components.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.baseArrayLayer = 0,
|
||||
.subresourceRange.layerCount = 1,
|
||||
};
|
||||
if (vkCreateImageView(data->device, &createInfo, NULL, &data->swapChainImageViews[i]) != VK_SUCCESS) {
|
||||
fprintf(stderr, "failed to create image views!");
|
||||
}
|
||||
data->swapChainImageViews[i] = createImageView(data->swapChainImages[i], data->swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,6 +839,34 @@ static uint32_t fileSize(const char* fileName) {
|
||||
return size;
|
||||
}
|
||||
|
||||
VkFormat findSupportedFormat(const VkFormat* candidates, int candidateCount, VkImageTiling tiling, VkFormatFeatureFlags features, struct VulkanData* data) {
|
||||
for (int i = 0; i < candidateCount; i++) {
|
||||
VkFormat format = candidates[i];
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(data->physicalDevice, format, &props);
|
||||
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
|
||||
return format;
|
||||
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "ERROR: Failed to find supported format\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
VkFormat findDepthFormat(struct VulkanData* data) {
|
||||
const VkFormat candidates[] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
|
||||
return findSupportedFormat(
|
||||
candidates,
|
||||
3,
|
||||
VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
static VkShaderModule createShaderModule(const char* code, uint32_t size, VkDevice device) {
|
||||
VkShaderModuleCreateInfo createInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
@@ -795,6 +909,19 @@ static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.pSpecializationInfo = NULL,
|
||||
};
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencil = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.depthTestEnable = VK_TRUE,
|
||||
.depthWriteEnable = VK_TRUE,
|
||||
.depthCompareOp = VK_COMPARE_OP_LESS,
|
||||
.depthBoundsTestEnable = VK_FALSE,
|
||||
.minDepthBounds = 0., // Optional
|
||||
.maxDepthBounds = 1., // Optional
|
||||
.stencilTestEnable = VK_FALSE,
|
||||
// .front = NULL, // Optional
|
||||
// .back = NULL, // Optional
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo shaderStages[2] = {vertShaderStageInfo, fragShaderStageInfo};
|
||||
|
||||
uint32_t dynamicStateCount = 2;
|
||||
@@ -810,11 +937,11 @@ static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
};
|
||||
|
||||
VkVertexInputBindingDescription bindingDescription = getBindingDescription();
|
||||
VkVertexInputAttributeDescription attributeDescriptions[2] = {
|
||||
VkVertexInputAttributeDescription attributeDescriptions[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = offsetof(Vertex, pos),
|
||||
},
|
||||
{
|
||||
@@ -822,13 +949,19 @@ static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.location = 1,
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = offsetof(Vertex, color),
|
||||
},
|
||||
{
|
||||
.binding = 0,
|
||||
.location = 2,
|
||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.offset = offsetof(Vertex, texCoord),
|
||||
}
|
||||
};
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.vertexAttributeDescriptionCount = 2,
|
||||
.vertexAttributeDescriptionCount = 3,
|
||||
.pVertexBindingDescriptions = &bindingDescription,
|
||||
.pVertexAttributeDescriptions = attributeDescriptions,
|
||||
};
|
||||
@@ -867,8 +1000,7 @@ static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.lineWidth = 1.0f,
|
||||
// .cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
.cullMode = 0,
|
||||
.cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f, // Optional
|
||||
@@ -931,7 +1063,7 @@ static void createGraphicsPipeline(struct VulkanData* data) {
|
||||
.pViewportState = &viewportState,
|
||||
.pRasterizationState = &rasterizer,
|
||||
.pMultisampleState = &multisampling,
|
||||
.pDepthStencilState = NULL, // Optional
|
||||
.pDepthStencilState = &depthStencil,
|
||||
.pColorBlendState = &colorBlending,
|
||||
.pDynamicState = &dynamicState,
|
||||
.layout = data->pipelineLayout,
|
||||
@@ -966,26 +1098,44 @@ static void createRenderPass(struct VulkanData* data) {
|
||||
.attachment = 0,
|
||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
VkAttachmentDescription depthAttachment = {
|
||||
.format = findDepthFormat(data),
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
VkAttachmentReference depthAttachmentRef = {
|
||||
.attachment = 1,
|
||||
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
VkSubpassDescription subpass = {
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.colorAttachmentCount = 1,
|
||||
.pColorAttachments = &colorAttachmentRef,
|
||||
.pDepthStencilAttachment = &depthAttachmentRef,
|
||||
};
|
||||
|
||||
VkSubpassDependency dependency = {
|
||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
||||
.dstSubpass = 0,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
};
|
||||
|
||||
VkAttachmentDescription attachments[2] = {colorAttachment, depthAttachment};
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorAttachment,
|
||||
.attachmentCount = 2,
|
||||
.pAttachments = attachments,
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpass,
|
||||
.dependencyCount = 1,
|
||||
@@ -1001,13 +1151,14 @@ static void createRenderPass(struct VulkanData* data) {
|
||||
static void createFramebuffers(struct VulkanData* data) {
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
VkImageView attachments[] = {
|
||||
data->swapChainImageViews[i]
|
||||
data->swapChainImageViews[i],
|
||||
data->depthImageView,
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = data->renderPass,
|
||||
.attachmentCount = 1,
|
||||
.attachmentCount = 2,
|
||||
.pAttachments = attachments,
|
||||
.width = data->swapChainExtent.width,
|
||||
.height = data->swapChainExtent.height,
|
||||
@@ -1021,6 +1172,59 @@ static void createFramebuffers(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, struct VulkanData* data) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(data->physicalDevice, &memProperties);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "ERROR: Failed to find suitable memory type\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage* image, VkDeviceMemory* imageMemory, struct VulkanData* data) {
|
||||
VkImageCreateInfo imageInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.extent.width = width,
|
||||
.extent.height = height,
|
||||
.extent.depth = 1,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.format = format,
|
||||
.tiling = tiling,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.usage = usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
if (vkCreateImage(data->device, &imageInfo, NULL, image) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create image\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(data->device, *image, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memRequirements.size,
|
||||
.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties, data),
|
||||
};
|
||||
|
||||
if (vkAllocateMemory(data->device, &allocInfo, NULL, imageMemory) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to allocate image memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vkBindImageMemory(data->device, *image, *imageMemory, 0);
|
||||
}
|
||||
|
||||
static void createCommandPool(struct VulkanData* data) {
|
||||
struct QueueFamilyIndices queueFamilyIndices = findQueueFamilies(data->physicalDevice, data->surface);
|
||||
|
||||
@@ -1074,7 +1278,10 @@ static void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageInd
|
||||
exit(1);
|
||||
}
|
||||
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkClearValue clearValues[] = {
|
||||
{ .color = {{0.0f, 0.0f, 0.0f, 1.0f}}, },
|
||||
{ .depthStencil = {1., 0}, }
|
||||
};
|
||||
|
||||
VkRenderPassBeginInfo renderPassInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
@@ -1082,8 +1289,8 @@ static void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageInd
|
||||
.framebuffer = data->swapChainFramebuffers[imageIndex],
|
||||
.renderArea.offset = {0, 0},
|
||||
.renderArea.extent = data->swapChainExtent,
|
||||
.clearValueCount = 1,
|
||||
.pClearValues = &clearColor,
|
||||
.clearValueCount = 2,
|
||||
.pClearValues = clearValues,
|
||||
};
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
@@ -1119,6 +1326,9 @@ static void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageInd
|
||||
}
|
||||
|
||||
static void cleanupSwapChain(struct VulkanData* data) {
|
||||
vkDestroyImageView(data->device, data->depthImageView, NULL);
|
||||
vkDestroyImage(data->device, data->depthImage, NULL);
|
||||
vkFreeMemory(data->device, data->depthImageMemory, NULL);
|
||||
for (int i = 0; i < data->imageCount; i++) {
|
||||
vkDestroyFramebuffer(data->device, data->swapChainFramebuffers[i], NULL);
|
||||
}
|
||||
@@ -1130,6 +1340,22 @@ static void cleanupSwapChain(struct VulkanData* data) {
|
||||
vkDestroySwapchainKHR(data->device, data->swapChain, NULL);
|
||||
}
|
||||
|
||||
static void createDepthResources(struct VulkanData* data) {
|
||||
VkFormat depthFormat = findDepthFormat(data);
|
||||
createImage(
|
||||
data->swapChainExtent.width,
|
||||
data->swapChainExtent.height,
|
||||
depthFormat,
|
||||
VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&data->depthImage,
|
||||
&data->depthImageMemory,
|
||||
data
|
||||
);
|
||||
data->depthImageView = createImageView(data->depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, data);
|
||||
}
|
||||
|
||||
static void recreateSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
int width = 0, height = 0;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
@@ -1141,6 +1367,7 @@ static void recreateSwapChain(struct VulkanData* data, GLFWwindow* window) {
|
||||
cleanupSwapChain(data);
|
||||
createSwapChain(data, window);
|
||||
createImageViews(data);
|
||||
createDepthResources(data);
|
||||
createFramebuffers(data);
|
||||
}
|
||||
|
||||
@@ -1246,17 +1473,81 @@ static void createSyncObjects(struct VulkanData* data) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties, struct VulkanData* data) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(data->physicalDevice, &memProperties);
|
||||
static void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, struct VulkanData* data) {
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands(false, data);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties)) {
|
||||
return i;
|
||||
}
|
||||
VkBufferImageCopy region = {
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.imageSubresource.mipLevel = 0,
|
||||
.imageSubresource.baseArrayLayer = 0,
|
||||
.imageSubresource.layerCount = 1,
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = {width, height, 1},
|
||||
};
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
commandBuffer,
|
||||
buffer,
|
||||
image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
®ion
|
||||
);
|
||||
|
||||
endSingleTimeCommands(commandBuffer, false, data);
|
||||
}
|
||||
|
||||
static void transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, struct VulkanData* data) {
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands(true, data);
|
||||
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.oldLayout = oldLayout,
|
||||
.newLayout = newLayout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.subresourceRange.baseMipLevel = 0,
|
||||
.subresourceRange.levelCount = 1,
|
||||
.subresourceRange.baseArrayLayer = 0,
|
||||
.subresourceRange.layerCount = 1,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = 0,
|
||||
};
|
||||
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Unsupported layout transition\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "ERROR: Failed to find suitable memory type\n");
|
||||
exit(1);
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
sourceStage, destinationStage,
|
||||
0,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
1, &barrier
|
||||
);
|
||||
|
||||
endSingleTimeCommands(commandBuffer, true, data);
|
||||
}
|
||||
|
||||
static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer* buffer, VkDeviceMemory* bufferMemory, struct VulkanData* data) {
|
||||
@@ -1294,21 +1585,7 @@ static void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPr
|
||||
}
|
||||
|
||||
static void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size, struct VulkanData* data) {
|
||||
VkCommandBufferAllocateInfo allocInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandPool = data->transferCommandPool,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(data->device, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands(false, data);
|
||||
|
||||
VkBufferCopy copyRegion = {
|
||||
.srcOffset = 0,
|
||||
@@ -1316,16 +1593,8 @@ static void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size
|
||||
.size = size,
|
||||
};
|
||||
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &commandBuffer,
|
||||
};
|
||||
vkQueueSubmit(data->transferQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(data->transferQueue);
|
||||
vkFreeCommandBuffers(data->device, data->transferCommandPool, 1, &commandBuffer);
|
||||
endSingleTimeCommands(commandBuffer, false, data);
|
||||
}
|
||||
|
||||
static void createIndexBuffer(struct VulkanData* data) {
|
||||
@@ -1374,10 +1643,20 @@ static void createDescriptorSetLayout(struct VulkanData* data) {
|
||||
.pImmutableSamplers = NULL,
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutBinding samplerLayoutBinding = {
|
||||
.binding = 1,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImmutableSamplers = NULL,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
};
|
||||
|
||||
VkDescriptorSetLayoutBinding bindings[2] = {uboLayoutBinding, samplerLayoutBinding};
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindings = &uboLayoutBinding,
|
||||
.bindingCount = 2,
|
||||
.pBindings = bindings,
|
||||
};
|
||||
|
||||
if (vkCreateDescriptorSetLayout(data->device, &layoutInfo, NULL, &data->descriptorSetLayout) != VK_SUCCESS) {
|
||||
@@ -1396,19 +1675,25 @@ static void createUniformBuffers(struct VulkanData* data) {
|
||||
}
|
||||
|
||||
static void createDescriptorPool(struct VulkanData* data) {
|
||||
VkDescriptorPoolSize poolSize = {
|
||||
VkDescriptorPoolSize uboPoolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = MAX_FRAMES_IN_FLIGHT,
|
||||
};
|
||||
|
||||
VkDescriptorPoolSize samplerPoolSize = {
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = MAX_FRAMES_IN_FLIGHT,
|
||||
};
|
||||
|
||||
VkDescriptorPoolSize poolSizes[2] = {uboPoolSize, samplerPoolSize};
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1,
|
||||
.pPoolSizes = &poolSize,
|
||||
.poolSizeCount = 2,
|
||||
.pPoolSizes = poolSizes,
|
||||
.maxSets = MAX_FRAMES_IN_FLIGHT,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
|
||||
if (vkCreateDescriptorPool(data->device, &poolInfo, NULL, &data->descriptorPool) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create descriptor pool\n");
|
||||
@@ -1440,25 +1725,221 @@ static void createDescriptorSets(struct VulkanData* data) {
|
||||
.range = sizeof(UniformBufferObject),
|
||||
};
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = data->descriptorSets[i],
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.pBufferInfo = &bufferInfo,
|
||||
.pImageInfo = NULL,
|
||||
.pTexelBufferView = NULL,
|
||||
VkDescriptorImageInfo imageInfo = {
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.imageView = data->textureImageView,
|
||||
.sampler = data->textureSampler,
|
||||
};
|
||||
|
||||
vkUpdateDescriptorSets(data->device, 1, &descriptorWrite, 0, NULL);
|
||||
VkWriteDescriptorSet descriptorWrites[2] = {
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = data->descriptorSets[i],
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = 1,
|
||||
.pBufferInfo = &bufferInfo,
|
||||
.pImageInfo = NULL,
|
||||
.pTexelBufferView = NULL,
|
||||
},
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = data->descriptorSets[i],
|
||||
.dstBinding = 1,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = 1,
|
||||
.pBufferInfo = NULL,
|
||||
.pImageInfo = &imageInfo,
|
||||
.pTexelBufferView = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
vkUpdateDescriptorSets(data->device, 2, descriptorWrites, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Because of the format support and alpha of 1 is added
|
||||
static struct PPM readPPM(char* fileName) {
|
||||
FILE* file = fopen(fileName, "r");
|
||||
char header[2];
|
||||
fread(header, sizeof(header[0]), 2, file);
|
||||
if (header[0] != 'P' || header[1] != '6') {
|
||||
fprintf(stderr, "ERROR: Unrecognized file format\n");
|
||||
exit(1);
|
||||
}
|
||||
if (fseek(file, 1, SEEK_CUR)) {
|
||||
fprintf(stderr, "ERROR: Failed to read image: \"%s\"\n", fileName);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
char c = '0';
|
||||
while (true) {
|
||||
if (fread(&c, 1, 1, file) != 1) {
|
||||
fprintf(stderr, "ERROR: Failed to read width of image: \"%s\" with char: %c\n", fileName, c);
|
||||
exit(1);
|
||||
}
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
fseek(file, -len - 1, SEEK_CUR);
|
||||
char widthStr[len + 1];
|
||||
fread(widthStr, sizeof(widthStr[0]), len, file);
|
||||
widthStr[len] = 0;
|
||||
int width = atoi(widthStr);
|
||||
fseek(file, 1, SEEK_CUR);
|
||||
|
||||
len = 0;
|
||||
c = '0';
|
||||
while (true) {
|
||||
if (fread(&c, 1, 1, file) != 1) {
|
||||
fprintf(stderr, "ERROR: Failed to read height of image: \"%s\"\n", fileName);
|
||||
exit(1);
|
||||
}
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
fseek(file, -len - 1, SEEK_CUR);
|
||||
char heightStr[len + 1];
|
||||
fread(heightStr, sizeof(heightStr[0]), len, file);
|
||||
heightStr[len] = 0;
|
||||
int height = atoi(heightStr);
|
||||
|
||||
fseek(file, 1, SEEK_CUR);
|
||||
len = 0;
|
||||
c = '0';
|
||||
while (true) {
|
||||
if (fread(&c, 1, 1, file) != 1) {
|
||||
fprintf(stderr, "ERROR: Failed to read maximum value for pixels in image: \"%s\"\n", fileName);
|
||||
exit(1);
|
||||
}
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
fseek(file, -len - 1, SEEK_CUR);
|
||||
char maxValStr[len + 1];
|
||||
fread(maxValStr, sizeof(maxValStr[0]), len, file);
|
||||
maxValStr[len] = 0;
|
||||
int maxVal = atoi(maxValStr);
|
||||
|
||||
printf("INFO: Image \"%s\" has a width and height of (%d, %d) and maximum value for pixels of %d\n", fileName, width, height, maxVal);
|
||||
fseek(file, 1, SEEK_CUR);
|
||||
|
||||
int pixelCount = width * height;
|
||||
|
||||
struct PPM ppm = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.maxVal = maxVal,
|
||||
.pixels = NULL,
|
||||
};
|
||||
|
||||
if (maxVal <= UCHAR_MAX) {
|
||||
uint8_t* pixels = malloc(pixelCount * 4);
|
||||
uint8_t* pixel_p = pixels;
|
||||
for (int i = 0; i < pixelCount; i++) {
|
||||
fread(pixel_p, sizeof(uint8_t), 3, file);
|
||||
pixel_p += 3;
|
||||
*pixel_p = UCHAR_MAX;
|
||||
pixel_p++;
|
||||
}
|
||||
ppm.pixels = pixels;
|
||||
} else if (maxVal <= USHRT_MAX) {
|
||||
uint16_t* pixels = malloc(pixelCount * sizeof(uint16_t) * 4);
|
||||
uint16_t* pixel_p = pixels;
|
||||
for (int i = 0; i < pixelCount; i++) {
|
||||
fread(pixel_p, sizeof(uint16_t), 3, file);
|
||||
pixel_p += 3;
|
||||
*pixel_p = USHRT_MAX;
|
||||
pixel_p++;
|
||||
}
|
||||
ppm.pixels = pixels;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: Specified maximum value for pixels is too large\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ppm;
|
||||
}
|
||||
|
||||
static void createTextureImage(struct VulkanData* data) {
|
||||
struct PPM ppm = readPPM("images/statue.ppm");
|
||||
int nSize = 1;
|
||||
VkFormat format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
if (ppm.maxVal > 255) {
|
||||
nSize = 2;
|
||||
format = VK_FORMAT_R16G16B16_UINT;
|
||||
}
|
||||
VkDeviceSize imageSize = ppm.width * ppm.height * nSize * 4;
|
||||
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingBufferMemory;
|
||||
|
||||
createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &stagingBuffer, &stagingBufferMemory, data);
|
||||
|
||||
void* imageData;
|
||||
vkMapMemory(data->device, stagingBufferMemory, 0, imageSize, 0, &imageData);
|
||||
memcpy(imageData, ppm.pixels, imageSize);
|
||||
vkUnmapMemory(data->device, stagingBufferMemory);
|
||||
|
||||
free(ppm.pixels);
|
||||
|
||||
createImage(ppm.width, ppm.height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &data->textureImage, &data->textureImageMemory, data);
|
||||
|
||||
transitionImageLayout(data->textureImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, data);
|
||||
copyBufferToImage(stagingBuffer, data->textureImage, ppm.width, ppm.height, data);
|
||||
transitionImageLayout(data->textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, data);
|
||||
vkDestroyBuffer(data->device, stagingBuffer, NULL);
|
||||
vkFreeMemory(data->device, stagingBufferMemory, NULL);
|
||||
}
|
||||
|
||||
static void createTextureImageView(struct VulkanData* data) {
|
||||
data->textureImageView = createImageView(data->textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, data);
|
||||
}
|
||||
|
||||
static void createTextureSampler(struct VulkanData* data) {
|
||||
VkPhysicalDeviceProperties properties;
|
||||
vkGetPhysicalDeviceProperties(data->physicalDevice, &properties);
|
||||
VkSamplerCreateInfo samplerInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = VK_FILTER_LINEAR,
|
||||
.minFilter = VK_FILTER_LINEAR,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
.anisotropyEnable = VK_TRUE,
|
||||
.maxAnisotropy = properties.limits.maxSamplerAnisotropy, // set to 1 to disable
|
||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||
.unnormalizedCoordinates = VK_FALSE,
|
||||
.compareEnable = VK_FALSE,
|
||||
.compareOp = VK_COMPARE_OP_ALWAYS,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
||||
.mipLodBias = 0.,
|
||||
.minLod = 0.,
|
||||
.maxLod = 0.,
|
||||
};
|
||||
|
||||
if (vkCreateSampler(data->device, &samplerInfo, NULL, &data->textureSampler) != VK_SUCCESS) {
|
||||
fprintf(stderr, "ERROR: Failed to create texture sampler\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool hasStencilComponent(VkFormat format) {
|
||||
return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
}
|
||||
|
||||
static void initVulkan(GLFWwindow* window, struct VulkanData* data) {
|
||||
data->currentFrame = 0;
|
||||
data->framebufferResized = 0;
|
||||
data->framebufferResized = false;
|
||||
createInstance(data);
|
||||
setupDebugMessenger(data);
|
||||
createSurface(data, window);
|
||||
@@ -1469,8 +1950,12 @@ static void initVulkan(GLFWwindow* window, struct VulkanData* data) {
|
||||
createRenderPass(data);
|
||||
createDescriptorSetLayout(data);
|
||||
createGraphicsPipeline(data);
|
||||
createFramebuffers(data);
|
||||
createCommandPool(data);
|
||||
createDepthResources(data);
|
||||
createFramebuffers(data);
|
||||
createTextureImage(data);
|
||||
createTextureImageView(data);
|
||||
createTextureSampler(data);
|
||||
createVertexBuffer(data);
|
||||
createIndexBuffer(data);
|
||||
createUniformBuffers(data);
|
||||
@@ -1497,6 +1982,11 @@ static void mainLoop(GLFWwindow* window, struct VulkanData* data, struct timespe
|
||||
static void cleanup(GLFWwindow* window, struct VulkanData* data) {
|
||||
cleanupSwapChain(data);
|
||||
|
||||
vkDestroySampler(data->device, data->textureSampler, NULL);
|
||||
vkDestroyImageView(data->device, data->textureImageView, NULL);
|
||||
vkDestroyImage(data->device, data->textureImage, NULL);
|
||||
vkFreeMemory(data->device, data->textureImageMemory, NULL);
|
||||
|
||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
vkDestroyBuffer(data->device, data->uniformBuffers[i], NULL);
|
||||
vkFreeMemory(data->device, data->uniformBuffersMemory[i], NULL);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
layout(binding = 1) uniform sampler2D texSampler;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
outColor = texture(texSampler, fragTexCoord);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 2) in vec2 inTexCoord;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject {
|
||||
mat4 model;
|
||||
@@ -12,6 +14,7 @@ layout(binding = 0) uniform UniformBufferObject {
|
||||
} ubo;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
||||
fragColor = inColor;
|
||||
fragTexCoord = inTexCoord;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user