diff --git a/src/fragment_simple.frag b/src/fragment_simple.frag index 7c5b0e7..873f541 100644 --- a/src/fragment_simple.frag +++ b/src/fragment_simple.frag @@ -1,9 +1,12 @@ #version 450 +layout(binding = 1) uniform sampler2D texSampler; + layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; void main() { - outColor = vec4(fragColor, 1.0); + outColor = texture(texSampler, fragTexCoord); } diff --git a/src/main.c b/src/main.c index 64566f1..51cc194 100644 --- a/src/main.c +++ b/src/main.c @@ -93,6 +93,8 @@ typedef struct ApplicationState { VkImage texture_image; VkDeviceMemory texture_image_memory; + VkImageView texture_image_view; + VkSampler texture_sampler; } ApplicationState; typedef struct QueueFamilyIndices { @@ -105,13 +107,14 @@ typedef struct QueueFamilyIndices { typedef struct Vertex { vec2 position; vec3 color; + vec2 tex_coord; } Vertex; const Vertex vertices[] = { - {{-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}} + {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}}, + {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}}, + {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, + {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}} }; const uint16_t indices[] = { @@ -335,6 +338,13 @@ void pick_physical_device(ApplicationState* state) { if (families.graphics_present && families.present_present && extensions_supported(state, device) && //we only care that at least one mode and one format exist details.num_modes != 0 && details.num_formats != 0) { + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + if (!supportedFeatures.samplerAnisotropy) { + free (details.present_modes); + free (details.formats); + continue; + } state->details = details; printf("graphics queue at %x, present queue at %x\n", families.graphics_queue, families.present_queue); break; @@ -386,6 +396,7 @@ void create_logical_device(ApplicationState* state) {; //for now we won't use any features VkPhysicalDeviceFeatures device_features = {0}; + device_features.samplerAnisotropy = VK_TRUE; //now create a logical device knowing which features and queues we need VkDeviceCreateInfo create_info = {0}; @@ -694,10 +705,19 @@ void create_descriptor_set_layout(ApplicationState* state) { ubo_layout_binding.descriptorCount = 1; ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding sampler_layout_binding = {0}; + sampler_layout_binding.binding = 1; + sampler_layout_binding.descriptorCount = 1; + sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + sampler_layout_binding.pImmutableSamplers = NULL; + sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutBinding bindings[2] = {ubo_layout_binding, sampler_layout_binding}; + VkDescriptorSetLayoutCreateInfo layout_info = {0}; layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layout_info.bindingCount = 1; - layout_info.pBindings = &ubo_layout_binding; + layout_info.bindingCount = ARRSIZE(bindings); + layout_info.pBindings = bindings; if (vkCreateDescriptorSetLayout(state->device, &layout_info, NULL, &state->descriptor_set_layout)) { printf("could not create descriptor set layout\n"); @@ -765,9 +785,10 @@ void create_graphics_pipeline(ApplicationState* state) { }; //We have position and color, so we need two descriptions - VkVertexInputAttributeDescription attribute_description[2] = { + VkVertexInputAttributeDescription attribute_description[3] = { {.binding = 0, .location = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(Vertex, position)}, {.binding = 0, .location = 1, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(Vertex, color)}, + {.binding = 0, .location = 2, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(Vertex, tex_coord)}, }; //vertex input format @@ -1239,15 +1260,67 @@ void create_texture_image(ApplicationState* state) { vkFreeMemory(state->device, staging_buffer_memory, NULL); } +void create_texture_image_view(ApplicationState* state) { + VkImageViewCreateInfo view_info = {0}; + view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_info.image = state->texture_image; + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_info.format = VK_FORMAT_R8G8B8A8_SRGB; + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.baseMipLevel = 0; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.layerCount = 1; + + if (vkCreateImageView(state->device, &view_info, NULL, &state->texture_image_view) != VK_SUCCESS) { + printf("failed to create texture image view\n"); + exit(1); + } +} + +void create_texture_image_sampler(ApplicationState* state) { + VkSamplerCreateInfo sampler_info = {0}; + sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + sampler_info.magFilter = VK_FILTER_LINEAR; + sampler_info.minFilter = VK_FILTER_LINEAR; + + sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + sampler_info.anisotropyEnable = VK_TRUE; + VkPhysicalDeviceProperties properties = {0}; + vkGetPhysicalDeviceProperties(state->physical_device, &properties); + sampler_info.maxAnisotropy = properties.limits.maxSamplerAnisotropy; + + sampler_info.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + sampler_info.unnormalizedCoordinates = VK_FALSE; + + sampler_info.compareEnable = VK_FALSE; + sampler_info.compareOp = VK_COMPARE_OP_ALWAYS; + + sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + sampler_info.mipLodBias = 0.0f; + sampler_info.minLod = 0.0f; + sampler_info.maxLod = 0.0f; + + if (vkCreateSampler(state->device, &sampler_info, NULL, &state->texture_sampler) != VK_SUCCESS) { + printf("failed to create sampler\n"); + exit(1); + } +} + void create_descriptor_pool(ApplicationState* state) { - VkDescriptorPoolSize pool_size = {0}; - pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - pool_size.descriptorCount = MAX_FRAMES_IN_FLIGHT; + VkDescriptorPoolSize pool_size[2] = {0}; + pool_size[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + pool_size[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; + pool_size[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + pool_size[1].descriptorCount = MAX_FRAMES_IN_FLIGHT; VkDescriptorPoolCreateInfo pool_info = {0}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_size; + pool_info.poolSizeCount = ARRSIZE(pool_size); + pool_info.pPoolSizes = pool_size; pool_info.maxSets = MAX_FRAMES_IN_FLIGHT; if (vkCreateDescriptorPool(state->device, &pool_info, NULL, &state->descriptor_pool) != VK_SUCCESS) { @@ -1279,18 +1352,31 @@ void create_descriptor_sets(ApplicationState* state) { buffer_info.offset = 0; buffer_info.range = sizeof(UBO); - VkWriteDescriptorSet descriptor_write = {0}; - descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_write.dstSet = state->descriptor_sets[i]; - descriptor_write.dstBinding = 0; - descriptor_write.dstArrayElement = 0; - descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptor_write.descriptorCount = 1; - descriptor_write.pBufferInfo = &buffer_info; - descriptor_write.pImageInfo = NULL; - descriptor_write.pTexelBufferView = NULL; - - vkUpdateDescriptorSets(state->device, 1, &descriptor_write, 0, NULL); + VkDescriptorImageInfo image_info = {0}; + image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_info.imageView = state->texture_image_view; + image_info.sampler = state->texture_sampler; + + VkWriteDescriptorSet descriptor_writes[2] = {0}; + descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_writes[0].dstSet = state->descriptor_sets[i]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].dstArrayElement = 0; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[0].pImageInfo = NULL; + descriptor_writes[0].pTexelBufferView = NULL; + + descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_writes[1].dstSet = state->descriptor_sets[i]; + descriptor_writes[1].dstBinding = 1; + descriptor_writes[1].dstArrayElement = 0; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].pImageInfo = &image_info; + + vkUpdateDescriptorSets(state->device, ARRSIZE(descriptor_writes), descriptor_writes, 0, NULL); } printf("created descriptor sets\n"); @@ -1413,6 +1499,8 @@ void init_vulkan(ApplicationState* state) { create_framebuffers(state); create_command_pool(state); create_texture_image(state); + create_texture_image_view(state); + create_texture_image_sampler(state); create_vertex_buffer(state); create_index_buffer(state); create_uniform_buffers(state); @@ -1534,6 +1622,8 @@ void terminate(ApplicationState* state) { vkFreeMemory(state->device, state->vertex_buffer_memory, NULL); vkDestroyBuffer(state->device, state->index_buffer, NULL); vkFreeMemory(state->device, state->index_buffer_memory, NULL); + vkDestroySampler(state->device, state->texture_sampler, NULL); + vkDestroyImageView(state->device, state->texture_image_view, NULL); vkDestroyImage(state->device, state->texture_image, NULL); vkFreeMemory(state->device, state->texture_image_memory, NULL); diff --git a/src/vertex_simple.vert b/src/vertex_simple.vert index 4aa8ad1..f44a8e1 100644 --- a/src/vertex_simple.vert +++ b/src/vertex_simple.vert @@ -8,10 +8,13 @@ layout(binding = 0) uniform UBO { layout(location = 0) in vec2 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; void main() { gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; + fragTexCoord = inTexCoord; }