aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/engine.cpp162
-rw-r--r--src/shaders/shader.slang7
-rw-r--r--src/vulkan_utils.hpp9
3 files changed, 150 insertions, 28 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
diff --git a/src/shaders/shader.slang b/src/shaders/shader.slang
index 24d9946..6bf9ca7 100644
--- a/src/shaders/shader.slang
+++ b/src/shaders/shader.slang
@@ -1,6 +1,7 @@
struct VertexInput {
float2 pos;
float3 col;
+ float2 uv;
};
struct UniformBuffer {
@@ -12,6 +13,7 @@ ConstantBuffer<UniformBuffer> ubo;
struct VertexOutput {
float4 pos : SV_Position;
float3 col;
+ float2 uv;
};
[shader("vertex")]
@@ -20,10 +22,13 @@ VertexOutput vert_main(VertexInput vi) {
// vo.pos = float4(vi.pos, 0., 1.);
vo.pos = mul(ubo.proj, mul(ubo.view, mul(ubo.model, float4(vi.pos, 0., 1.))));
vo.col = vi.col;
+ vo.uv = vi.uv;
return vo;
}
+Sampler2D texture;
+
[shader("fragment")]
float4 frag_main(VertexOutput vo) : SV_Target {
- return float4(vo.col, 1.);
+ return texture.Sample(vo.uv);
}
diff --git a/src/vulkan_utils.hpp b/src/vulkan_utils.hpp
index 1efc73e..99fd912 100644
--- a/src/vulkan_utils.hpp
+++ b/src/vulkan_utils.hpp
@@ -39,7 +39,7 @@ struct Vertex {
};
}
- static constexpr std::array<VkVertexInputAttributeDescription, 2> get_attr_descs() {
+ static constexpr std::array<VkVertexInputAttributeDescription, 3> get_attr_descs() {
return {
VkVertexInputAttributeDescription {
.location = 0,
@@ -53,11 +53,18 @@ struct Vertex {
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(Vertex, col),
},
+ VkVertexInputAttributeDescription {
+ .location = 2,
+ .binding = 0,
+ .format = VK_FORMAT_R32G32_SFLOAT,
+ .offset = offsetof(Vertex, uv),
+ },
};
}
engine::math::Vector2 pos;
engine::math::Vector3 col;
+ engine::math::Vector2 uv;
};
// TODO: move to a better place. Also, see TODOs for struct Vertex