diff options
Diffstat (limited to 'src/engine.cpp')
| -rw-r--r-- | src/engine.cpp | 162 |
1 files changed, 136 insertions, 26 deletions
diff --git a/src/engine.cpp b/src/engine.cpp index 7af909a..8c517c0 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -326,8 +326,8 @@ constexpr bool show_fps = false; struct PhysicalDeviceEntry { uint32_t idx; VkPhysicalDevice physical_device; - const char* name; uint32_t graphics_queue_family_index, present_queue_family_index; + VkPhysicalDeviceProperties2 props; VkPhysicalDeviceFeatures2 features; }; @@ -672,10 +672,10 @@ static int main_graphical() { // TODO: verify alignment requirements // TODO: maybe move these definitions? const std::array vertices { - engine::vk::Vertex { { -.5f, -.5f }, { 1.f, 0.f, 0.f } }, - engine::vk::Vertex { { .5f, -.5f }, { 0.f, 1.f, 0.f } }, - engine::vk::Vertex { { .5f, .5f }, { 0.f, 0.f, 1.f } }, - engine::vk::Vertex { { -.5f, .5f }, { 1.f, 1.f, 1.f } }, + engine::vk::Vertex { { -.5f, -.5f }, { 1.f, 0.f, 0.f }, { 1.f, 0.f } }, + engine::vk::Vertex { { .5f, -.5f }, { 0.f, 1.f, 0.f }, { 0.f, 0.f } }, + engine::vk::Vertex { { .5f, .5f }, { 0.f, 0.f, 1.f }, { 0.f, 1.f } }, + engine::vk::Vertex { { -.5f, .5f }, { 1.f, 1.f, 1.f }, { 1.f, 1.f } }, }; const std::array<uint16_t, 6> indices { 0, 1, 2, 2, 3, 0 }; @@ -785,7 +785,7 @@ static int main_graphical() { }(); // select physical device and queues - auto [physical_device, graphics_queue_family_index, present_queue_family_index, device_features] = [&]() { + auto [physical_device, graphics_queue_family_index, present_queue_family_index, physical_device_props, physical_device_features] = [&]() { std::multimap<unsigned, PhysicalDeviceEntry> physical_devices; auto avail_physical_devices = [&]() { @@ -889,6 +889,10 @@ static int main_graphical() { != physical_device_ext_props.end(); }) != physical_device_ext_names.end()) return std::optional<unsigned> {}; + if (!physical_device_features.features.samplerAnisotropy) + return std::optional<unsigned> {}; + // TODO: lots of checks are probably missing, like checking if the swapchain is + // supported (I'm not sure if it's needed) unsigned score = 0; if (*graphics_queue_family_index == *present_queue_family_index) @@ -923,9 +927,9 @@ static int main_graphical() { { .idx = i, .physical_device = avail_physical_device, - .name = physical_device_props.properties.deviceName, .graphics_queue_family_index = *graphics_queue_family_index, .present_queue_family_index = *present_queue_family_index, + .props = physical_device_props, .features = physical_device_features, } }); @@ -940,10 +944,10 @@ static int main_graphical() { auto best = physical_devices.crbegin(); - std::cout << "picking: " << (best->second.idx + 1) << ". " << best->second.name << " (score: " << best->first << ")" << std::endl; + std::cout << "picking: " << (best->second.idx + 1) << ". " << best->second.props.properties.deviceName << " (score: " << best->first << ")" << std::endl; return std::tuple { best->second.physical_device, best->second.graphics_queue_family_index, - best->second.present_queue_family_index, best->second.features }; + best->second.present_queue_family_index, best->second.props, best->second.features }; }(); auto device = [&]() { @@ -997,7 +1001,16 @@ static int main_graphical() { .maintenance4 = {}, }; - device_features.pNext = &device_vk13_features; + // TODO: name is confusing. We can't call it physical_device_features because the name is + // already taken by features queried while selecting the physical device. But calling it + // device_features makes a bit of sense, because theses are features requested for (logical) + // device creation + VkPhysicalDeviceFeatures2 device_features { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &device_vk13_features, + .features = {}, // default to VK_FALSE for everything + }; + device_features.features.samplerAnisotropy = VK_TRUE; VkDeviceCreateInfo device_ci { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, @@ -1220,7 +1233,6 @@ static int main_graphical() { std::exit(EXIT_FAILURE); } } - return swapchain_img_views; }(); }; @@ -1228,19 +1240,28 @@ static int main_graphical() { // create descriptor set layout auto descriptor_set_layout = [&]() { - VkDescriptorSetLayoutBinding descriptor_set_layout_binding { - .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .pImmutableSamplers = {}, + std::array descriptor_set_layout_bindings { + VkDescriptorSetLayoutBinding { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = {}, + }, + VkDescriptorSetLayoutBinding { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = {}, + }, }; VkDescriptorSetLayoutCreateInfo descriptor_set_layout_ci { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = {}, - .bindingCount = 1, - .pBindings = &descriptor_set_layout_binding, + .bindingCount = descriptor_set_layout_bindings.size(), + .pBindings = descriptor_set_layout_bindings.data(), }; VkDescriptorSetLayout descriptor_set_layout; if (VkResult res = vkCreateDescriptorSetLayout(device, &descriptor_set_layout_ci, nullptr, &descriptor_set_layout); res != VK_SUCCESS) { @@ -1537,6 +1558,66 @@ static int main_graphical() { return std::tuple { texture_img, texture_img_device_mem }; }(); + // create texture image view + // TODO: this is the same code, with minor differences, than the one that create swapchain image + // views, so maybe we should create a function. The thing is, this code only call a single + // function with a single create-info, so I'm not sure if it would make sense + auto texture_img_view = [&]() { + VkImageViewCreateInfo img_view_ci { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = {}, + .flags = {}, + .image = texture_img, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = VK_FORMAT_R8G8B8A8_SRGB, + .components = {}, + .subresourceRange = { // VkImageSubresourceRange + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + VkImageView texture_img_view; + if (VkResult res = vkCreateImageView(device, &img_view_ci, nullptr, &texture_img_view); res != VK_SUCCESS) { + std::cerr << "failed to create texture image view, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return texture_img_view; + }(); + + // create texture sampler + auto sampler = [&]() { + VkSamplerCreateInfo sampler_ci { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_LINEAR, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .mipLodBias = 0.f, + .anisotropyEnable = VK_TRUE, + .maxAnisotropy = physical_device_props.properties.limits.maxSamplerAnisotropy, + .compareEnable = VK_FALSE, + // TODO: check if it has to be VK_COMPARE_OP_ALWAYS instead of VK_COMPARE_OP_NEVER + .compareOp = VK_COMPARE_OP_NEVER, + .minLod = 0.f, + .maxLod = 0.f, + .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }; + VkSampler sampler; + if (VkResult res = vkCreateSampler(device, &sampler_ci, nullptr, &sampler); res != VK_SUCCESS) { + std::cerr << "failed to create sampler, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return sampler; + }(); + // create vertex buffer auto [vertex_buf, vertex_buf_device_mem] = [&]() { VkDeviceSize vertex_buf_size = sizeof(engine::vk::Vertex) * vertices.size(); @@ -1638,9 +1719,15 @@ static int main_graphical() { // create descriptor pool auto descriptor_pool = [&]() { - VkDescriptorPoolSize descriptor_pool_size { - .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = max_frames_in_flight, + std::array descriptor_pool_sizes { + VkDescriptorPoolSize { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = max_frames_in_flight, + }, + VkDescriptorPoolSize { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = max_frames_in_flight, + }, }; VkDescriptorPoolCreateInfo descriptor_pool_ci { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, @@ -1649,8 +1736,8 @@ static int main_graphical() { // setting VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT is useless .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, .maxSets = max_frames_in_flight, - .poolSizeCount = 1, - .pPoolSizes = &descriptor_pool_size, + .poolSizeCount = descriptor_pool_sizes.size(), + .pPoolSizes = descriptor_pool_sizes.data(), }; VkDescriptorPool descriptor_pool; if (VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_ci, nullptr, &descriptor_pool); res != VK_SUCCESS) { @@ -1677,14 +1764,17 @@ static int main_graphical() { std::exit(EXIT_FAILURE); } std::array<VkDescriptorBufferInfo, max_frames_in_flight> descriptor_buffer_infos; - std::array<VkWriteDescriptorSet, max_frames_in_flight> write_descriptor_sets; + std::array<VkDescriptorImageInfo, max_frames_in_flight> descriptor_image_infos; + // the 2 comes from uniform buffer object + combined image sampler + std::array<VkWriteDescriptorSet, 2 * max_frames_in_flight> write_descriptor_sets; for (size_t i = 0; i < max_frames_in_flight; i++) { + // uniform buffer object descriptor_buffer_infos[i] = VkDescriptorBufferInfo { .buffer = uniform_bufs[i], .offset = 0, .range = sizeof(engine::vk::UniformBufferObject), }; - write_descriptor_sets[i] = VkWriteDescriptorSet { + write_descriptor_sets[2 * i + 0] = VkWriteDescriptorSet { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, .dstSet = descriptor_sets[i], @@ -1696,6 +1786,24 @@ static int main_graphical() { .pBufferInfo = &descriptor_buffer_infos[i], .pTexelBufferView = {}, }; + // combined image sampler + descriptor_image_infos[i] = VkDescriptorImageInfo { + .sampler = sampler, + .imageView = texture_img_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + write_descriptor_sets[2 * i + 1] = VkWriteDescriptorSet { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[i], + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &descriptor_image_infos[i], + .pBufferInfo = {}, + .pTexelBufferView = {}, + }; } // TODO: maybe we should call this function for each descriptor sets, which I would find // weird by the fact that it takes an array as an argument, but IDK @@ -2024,6 +2132,8 @@ static int main_graphical() { vkDestroyBuffer(device, index_buf, nullptr); vkFreeMemory(device, vertex_buf_device_mem, nullptr); vkDestroyBuffer(device, vertex_buf, nullptr); + vkDestroySampler(device, sampler, nullptr); + vkDestroyImageView(device, texture_img_view, nullptr); vkFreeMemory(device, texture_img_device_mem, nullptr); vkDestroyImage(device, texture_img, nullptr); // no need to free cmd_buf because destroying the command pool will |
