|
|
|
@ -93,6 +93,8 @@ typedef struct ApplicationState {
@@ -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 {
@@ -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) {
@@ -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) {;
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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); |
|
|
|
|
|
|
|
|
|