Start Rendering a debug Test Image on our Plane.
All checks were successful
ci/woodpecker/push/woodpecker.json Pipeline was successful

This commit is contained in:
Rebekah 2024-07-18 16:35:52 -04:00
parent 18a990133f
commit 30ed1f679b
Signed by: oneechanhax
GPG Key ID: 0074BF373B812798
5 changed files with 332 additions and 62 deletions

View File

@ -191,12 +191,14 @@ public:
if (type STREQUAL "image") if (type STREQUAL "image")
cmake_path(GET file_path PARENT_PATH file_parent) cmake_path(GET file_path PARENT_PATH file_parent)
cmake_path(GET file_path FILENAME file_name) cmake_path(GET file_path FILENAME file_name)
exec_program("${ImageMagick_identify_EXECUTABLE}" "${file_parent}" execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:w]" "${file_name}"
ARGS -format "%[fx:w]" "${file_name}" WORKING_DIRECTORY "${file_parent}"
OUTPUT_VARIABLE image_width) OUTPUT_VARIABLE image_width
exec_program("${ImageMagick_identify_EXECUTABLE}" "${file_parent}" COMMAND_ERROR_IS_FATAL ANY)
ARGS -format "%[fx:h]" "${file_name}" execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:h]" "${file_name}"
OUTPUT_VARIABLE image_height) WORKING_DIRECTORY "${file_parent}"
OUTPUT_VARIABLE image_height
COMMAND_ERROR_IS_FATAL ANY)
file(APPEND "${EMBED_HEADER_DIR}/embed_resources.hpp" "inline EmbededImage embeded_${obj_cleaned_name}(${image_width}, ${image_height}, EmbededResource(&_binary_${obj_cleaned_name}_start, &_binary_${obj_cleaned_name}_end)); \n") file(APPEND "${EMBED_HEADER_DIR}/embed_resources.hpp" "inline EmbededImage embeded_${obj_cleaned_name}(${image_width}, ${image_height}, EmbededResource(&_binary_${obj_cleaned_name}_start, &_binary_${obj_cleaned_name}_end)); \n")
elseif (type STREQUAL "embed") elseif (type STREQUAL "embed")
@ -206,7 +208,7 @@ public:
endforeach() endforeach()
set(EMBED_OBJ_RET "${EMBED_OBJ_RET}" PARENT_SCOPE) set(EMBED_OBJ_RET "${EMBED_OBJ_RET}" PARENT_SCOPE)
endfunction() endfunction()
EmbedResources(${SHADILER_OBJ_RET}) EmbedResources(${SHADILER_OBJ_RET} "${CMAKE_CURRENT_SOURCE_DIR}/res/debug_north.png")
target_sources(${PROJECT_NAME} PRIVATE ${EMBED_OBJ_RET}) target_sources(${PROJECT_NAME} PRIVATE ${EMBED_OBJ_RET})
target_include_directories(${PROJECT_NAME} PUBLIC "${EMBED_HEADER_DIR}") target_include_directories(${PROJECT_NAME} PUBLIC "${EMBED_HEADER_DIR}")

BIN
res/debug_north.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@ -19,9 +19,12 @@
#version 450 #version 450
layout(location = 0) out vec4 out_color;
layout(location = 0) in vec3 frag_color; layout(location = 0) in vec3 frag_color;
layout(location = 1) in vec2 frag_texture_coordinate;
layout(binding = 1) uniform sampler2D texture_sampler;
layout(location = 0) out vec4 out_color;
void main() { void main() {
out_color = vec4(frag_color, 1.0); out_color = texture(texture_sampler, frag_texture_coordinate);
} }

View File

@ -27,11 +27,13 @@ layout(binding = 0) uniform UniformBufferObject {
layout(location = 0) in vec2 in_position; layout(location = 0) in vec2 in_position;
layout(location = 2) in vec3 in_color; layout(location = 2) in vec3 in_color;
layout(location = 4) in vec2 in_texture_coordinate;
layout(location = 0) out vec3 frag_color; layout(location = 0) out vec3 frag_color;
layout(location = 1) out vec2 frag_texture_coordinate;
void main() { void main() {
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 0.0, 1.0); gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 0.0, 1.0);
//gl_Position = vec4(, 0.5, 1.0);
frag_color = in_color; frag_color = in_color;
frag_texture_coordinate = in_texture_coordinate;
} }

View File

@ -68,7 +68,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugCallback(
class VulkanExampleApplication { class VulkanExampleApplication {
private: private:
using VulkanBuffers = std::pair<std::unique_ptr<vk::raii::Buffer>, std::unique_ptr<vk::raii::DeviceMemory>>; using VulkanBuffer = std::pair<std::unique_ptr<vk::raii::Buffer>, std::unique_ptr<vk::raii::DeviceMemory>>;
using VulkanImage = std::pair<std::unique_ptr<vk::raii::Image>, std::unique_ptr<vk::raii::DeviceMemory>>;
std::unique_ptr<SDL2pp::SDL> libsdl; std::unique_ptr<SDL2pp::SDL> libsdl;
std::unique_ptr<SDL2pp::Window> window; std::unique_ptr<SDL2pp::Window> window;
@ -119,12 +120,13 @@ private:
} vk_physical_card_info; } vk_physical_card_info;
public: public:
VulkanBuffers vk_buffer_vertex; // in order to get a clean desctruction sequence, instantiate the DeviceMemory for the vertex buffer first // https://github.com/KhronosGroup/Vulkan-Hpp/blob/6f72ceca515d59f40d64b64cf2734f6261e1f9f2/RAII_Samples/13_InitVertexBuffer/13_InitVertexBuffer.cpp VulkanBuffer vk_buffer_vertex; // in order to get a clean desctruction sequence, instantiate the DeviceMemory for the vertex buffer first // https://github.com/KhronosGroup/Vulkan-Hpp/blob/6f72ceca515d59f40d64b64cf2734f6261e1f9f2/RAII_Samples/13_InitVertexBuffer/13_InitVertexBuffer.cpp
VulkanBuffers vk_buffer_index; // used to make rendering models more efficent by sharing values VulkanBuffer vk_buffer_index; // used to make rendering models more efficent by sharing values
struct Vertex { struct Vertex {
glm::vec2 pos; glm::vec2 pos;
glm::vec3 color; glm::vec3 color;
glm::vec2 texture_coordinates;
static constexpr vk::VertexInputBindingDescription GetBindingDescription() { static constexpr vk::VertexInputBindingDescription GetBindingDescription() {
constexpr vk::VertexInputBindingDescription binding_description { constexpr vk::VertexInputBindingDescription binding_description {
@ -134,8 +136,8 @@ public:
}; };
return binding_description; return binding_description;
} }
static constexpr std::array<vk::VertexInputAttributeDescription, 2> GetAttributeDescriptions() { static constexpr std::array<vk::VertexInputAttributeDescription, 3> GetAttributeDescriptions() {
constexpr std::array<vk::VertexInputAttributeDescription, 2> attribute_descriptions { constexpr std::array<vk::VertexInputAttributeDescription, 3> attribute_descriptions {
vk::VertexInputAttributeDescription { // https://docs.vulkan.org/tutorial/latest/04_Vertex_buffers/00_Vertex_input_description.html vk::VertexInputAttributeDescription { // https://docs.vulkan.org/tutorial/latest/04_Vertex_buffers/00_Vertex_input_description.html
.location = 0, .location = 0,
.binding = 0, .binding = 0,
@ -145,16 +147,22 @@ public:
.location = 2, .location = 2,
.binding = 0, .binding = 0,
.format = vk::Format::eR32G32B32Sfloat, .format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, color) } .offset = offsetof(Vertex, color) },
vk::VertexInputAttributeDescription {
.location = 4,
.binding = 0,
.format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, texture_coordinates) }
}; };
return attribute_descriptions; return attribute_descriptions;
} }
}; };
static inline const std::vector<Vertex> quad_vertices = { static inline const std::vector<Vertex> quad_vertices = {
{ { -0.5f, -0.5f }, { 1.0f, 0.0f, 0.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.5f, -0.5f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
{ { 0.5f, 0.5f }, { 0.0f, 0.0f, 1.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 } } { { -0.5f, 0.5f }, { 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f } }
}; };
static inline const std::vector<std::uint16_t> quad_indexes = { static inline const std::vector<std::uint16_t> quad_indexes = {
0, 1, 2, 2, 3, 0 // Wraps a quad-box's 2 triangles around itself. // https://docs.vulkan.org/tutorial/latest/04_Vertex_buffers/03_Index_buffer.html 0, 1, 2, 2, 3, 0 // Wraps a quad-box's 2 triangles around itself. // https://docs.vulkan.org/tutorial/latest/04_Vertex_buffers/03_Index_buffer.html
@ -167,9 +175,14 @@ public:
alignas(16) glm::mat4 view; alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj; alignas(16) glm::mat4 proj;
}; };
std::vector<VulkanBuffers> vk_buffers_uniform; std::vector<VulkanBuffer> vk_buffers_uniform;
std::vector<std::uint8_t*> vk_buffers_uniform_mapped; std::vector<std::uint8_t*> vk_buffers_uniform_mapped;
public:
VulkanImage vk_texture_image;
std::unique_ptr<vk::raii::ImageView> vk_texture_view;
std::unique_ptr<vk::raii::Sampler> vk_texture_sampler;
public: public:
VulkanExampleApplication() { VulkanExampleApplication() {
try { // try me // all the code is in init :O boo hoo, ill shove all ur ram out of scope ASAP i can, dont seperate them, just scope them instead dumb dumb. try { // try me // all the code is in init :O boo hoo, ill shove all ur ram out of scope ASAP i can, dont seperate them, just scope them instead dumb dumb.
@ -304,6 +317,9 @@ public:
if (!VulkanCheckDeviceExtensionSupport(gfx_card)) if (!VulkanCheckDeviceExtensionSupport(gfx_card))
return ret; return ret;
if (!device_features.samplerAnisotropy)
return ret;
ret.surface_capabilities = gfx_card.getSurfaceCapabilitiesKHR(*found_screen_surface); ret.surface_capabilities = gfx_card.getSurfaceCapabilitiesKHR(*found_screen_surface);
const auto surface_present_modes = gfx_card.getSurfacePresentModesKHR(*found_screen_surface); const auto surface_present_modes = gfx_card.getSurfacePresentModesKHR(*found_screen_surface);
const auto surface_formats = gfx_card.getSurfaceFormatsKHR(*found_screen_surface); const auto surface_formats = gfx_card.getSurfaceFormatsKHR(*found_screen_surface);
@ -352,7 +368,9 @@ public:
return device_queues_we_need; return device_queues_we_need;
}(this->vk_physical_card_info.graphics_family.value(), this->vk_physical_card_info.present_family.value()); }(this->vk_physical_card_info.graphics_family.value(), this->vk_physical_card_info.present_family.value());
constexpr vk::PhysicalDeviceFeatures device_features {}; constexpr vk::PhysicalDeviceFeatures device_features {
.samplerAnisotropy = vk::True
};
const vk::DeviceCreateInfo device_create_info { const vk::DeviceCreateInfo device_create_info {
.queueCreateInfoCount = static_cast<uint32_t>(device_queue_create_infos.size()), .queueCreateInfoCount = static_cast<uint32_t>(device_queue_create_infos.size()),
.pQueueCreateInfos = device_queue_create_infos.data(), .pQueueCreateInfos = device_queue_create_infos.data(),
@ -552,16 +570,25 @@ public:
}; };
// Descriptor Layouts, appears required. // Descriptor Layouts, appears required.
constexpr auto descriptor_set_layout_binding_ubo = vk::DescriptorSetLayoutBinding { constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_ubo {
.binding = 0, .binding = 0,
.descriptorType = vk::DescriptorType::eUniformBuffer, .descriptorType = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eVertex, .stageFlags = vk::ShaderStageFlagBits::eVertex,
.pImmutableSamplers = nullptr // Optional .pImmutableSamplers = nullptr // Optional
}; };
const auto descriptor_set_layout_create_info = vk::DescriptorSetLayoutCreateInfo { constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_sampler {
.bindingCount = 1, .binding = 1,
.pBindings = &descriptor_set_layout_binding_ubo .descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eFragment,
.pImmutableSamplers = nullptr // Optional
};
const std::array<vk::DescriptorSetLayoutBinding, 2> descriptor_set_layout_bindings = { descriptor_set_layout_binding_ubo, descriptor_set_layout_binding_sampler };
const vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info {
.bindingCount = static_cast<uint32_t>(descriptor_set_layout_bindings.size()),
.pBindings = descriptor_set_layout_bindings.data()
}; };
this->vk_descriptor_set_layout_ubo = std::make_unique<vk::raii::DescriptorSetLayout>(*this->vk_gpu, descriptor_set_layout_create_info); this->vk_descriptor_set_layout_ubo = std::make_unique<vk::raii::DescriptorSetLayout>(*this->vk_gpu, descriptor_set_layout_create_info);
@ -575,15 +602,20 @@ public:
this->vk_pipeline_layout = std::make_unique<vk::raii::PipelineLayout>(*this->vk_gpu, pipeline_layout_create_info); this->vk_pipeline_layout = std::make_unique<vk::raii::PipelineLayout>(*this->vk_gpu, pipeline_layout_create_info);
// descriptors // descriptors
const vk::DescriptorPoolSize descriptor_pool_size { const vk::DescriptorPoolSize descriptor_pool_size_ubo {
.type = vk::DescriptorType::eUniformBuffer, .type = vk::DescriptorType::eUniformBuffer,
.descriptorCount = static_cast<uint32_t>(this->vk_max_frames_in_flight) .descriptorCount = static_cast<uint32_t>(this->vk_max_frames_in_flight)
}; };
const vk::DescriptorPoolSize descriptor_pool_size_sampler {
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = static_cast<uint32_t>(this->vk_max_frames_in_flight)
};
const std::array<vk::DescriptorPoolSize, 2> descriptor_pool_sizes = { descriptor_pool_size_ubo, descriptor_pool_size_sampler };
const vk::DescriptorPoolCreateInfo descriptor_pool_create_info { const vk::DescriptorPoolCreateInfo descriptor_pool_create_info {
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, .flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = static_cast<uint32_t>(this->vk_max_frames_in_flight), .maxSets = static_cast<uint32_t>(this->vk_max_frames_in_flight),
.poolSizeCount = 1, .poolSizeCount = static_cast<uint32_t>(descriptor_pool_sizes.size()),
.pPoolSizes = &descriptor_pool_size, .pPoolSizes = descriptor_pool_sizes.data(),
}; };
assert(descriptor_pool_create_info.flags & vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet); assert(descriptor_pool_create_info.flags & vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet);
this->vk_descriptor_pool = std::make_unique<vk::raii::DescriptorPool>(*this->vk_gpu, descriptor_pool_create_info); this->vk_descriptor_pool = std::make_unique<vk::raii::DescriptorPool>(*this->vk_gpu, descriptor_pool_create_info);
@ -717,7 +749,7 @@ public:
this->vk_fences_in_flight.emplace_back(*this->vk_gpu, vk::FenceCreateInfo { .flags = vk::FenceCreateFlagBits::eSignaled }); this->vk_fences_in_flight.emplace_back(*this->vk_gpu, vk::FenceCreateInfo { .flags = vk::FenceCreateFlagBits::eSignaled });
} }
} }
{ { // uniform buffer object
assert(this->vk_buffers_uniform.empty()); assert(this->vk_buffers_uniform.empty());
assert(this->vk_buffers_uniform_mapped.empty()); assert(this->vk_buffers_uniform_mapped.empty());
this->vk_buffers_uniform.reserve(this->vk_max_frames_in_flight); this->vk_buffers_uniform.reserve(this->vk_max_frames_in_flight);
@ -728,19 +760,71 @@ public:
this->vk_buffers_uniform_mapped.emplace_back(static_cast<std::uint8_t*>(uniform_buffer.second->mapMemory(0, ubo_buffer_size))); this->vk_buffers_uniform_mapped.emplace_back(static_cast<std::uint8_t*>(uniform_buffer.second->mapMemory(0, ubo_buffer_size)));
this->vk_buffers_uniform.emplace_back(std::move(uniform_buffer)); this->vk_buffers_uniform.emplace_back(std::move(uniform_buffer));
} }
}
{ // texture
const auto texture_buffer_size = embeded_debug_north_png_rgba.data.size;
const vk::Extent2D texture_buffer_extent = { .width = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.width), .height = static_cast<std::uint32_t>(embeded_debug_north_png_rgba.height) };
const auto texture_buffer_staging = this->CreateBuffer(texture_buffer_size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
std::uint8_t* const texture_buffer_data = static_cast<std::uint8_t*>(texture_buffer_staging.second->mapMemory(0, texture_buffer_size));
memcpy(texture_buffer_data, embeded_debug_north_png_rgba.data.begin, texture_buffer_size);
texture_buffer_staging.second->unmapMemory();
this->vk_texture_image = CreateImage(texture_buffer_extent, vk::Format::eR8G8B8A8Srgb, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal);
this->SingleTimeSubmitCommand([&](const auto& command_buffer) {
this->TransitionImageLayout(command_buffer, *this->vk_texture_image.first, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
this->CopyBuffer(command_buffer, *texture_buffer_staging.first, *this->vk_texture_image.first, texture_buffer_extent);
this->TransitionImageLayout(command_buffer, *this->vk_texture_image.first, vk::Format::eR8G8B8A8Srgb, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
});
const vk::ImageViewCreateInfo imageview_create_info {
.image = **this->vk_texture_image.first,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eR8G8B8A8Srgb,
.components = {
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eIdentity },
.subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1 },
};
this->vk_texture_view = std::make_unique<vk::raii::ImageView>(*this->vk_gpu, imageview_create_info);
const vk::SamplerCreateInfo sampler_create_info {
.magFilter = vk::Filter::eLinear,
.minFilter = vk::Filter::eLinear,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.addressModeU = vk::SamplerAddressMode::eRepeat, // https://docs.vulkan.org/tutorial/latest/06_Texture_mapping/01_Image_view_and_sampler.html#_samplers
.addressModeV = vk::SamplerAddressMode::eRepeat,
.addressModeW = vk::SamplerAddressMode::eRepeat,
.mipLodBias = 0.0f,
.anisotropyEnable = vk::True,
.maxAnisotropy = std::max<float>(4.0f, this->vk_gfx_card->getProperties().limits.maxSamplerAnisotropy),
.compareEnable = vk::False,
.compareOp = vk::CompareOp::eAlways,
.minLod = 0.0f,
.maxLod = 0.0f,
.borderColor = vk::BorderColor::eIntOpaqueBlack,
.unnormalizedCoordinates = vk::False,
};
this->vk_texture_sampler = std::make_unique<vk::raii::Sampler>(*this->vk_gpu, sampler_create_info);
}
{ // update descriptors
std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
write_descriptor_sets.reserve(this->vk_max_frames_in_flight);
std::vector<vk::DescriptorBufferInfo> buffer_infos; std::vector<vk::DescriptorBufferInfo> buffer_infos;
std::vector<vk::WriteDescriptorSet> write_descriptor_sets;
buffer_infos.reserve(this->vk_max_frames_in_flight); buffer_infos.reserve(this->vk_max_frames_in_flight);
write_descriptor_sets.reserve(this->vk_max_frames_in_flight);
for (std::size_t i = 0; i < this->vk_max_frames_in_flight; i++) { for (std::size_t i = 0; i < this->vk_max_frames_in_flight; i++) {
const vk::DescriptorBufferInfo descriptor_buffer_info { const vk::DescriptorBufferInfo descriptor_buffer_info_ubo {
.buffer = **this->vk_buffers_uniform.at(i).first, .buffer = **this->vk_buffers_uniform.at(i).first,
.offset = 0, .offset = 0,
.range = sizeof(UniformBufferObject), .range = sizeof(UniformBufferObject),
}; };
const vk::DescriptorBufferInfo& descriptor_buffer_info_handle = buffer_infos.emplace_back(descriptor_buffer_info);
const vk::WriteDescriptorSet descriptor_write { const vk::DescriptorBufferInfo& descriptor_buffer_info_handle = buffer_infos.emplace_back(descriptor_buffer_info_ubo);
const vk::WriteDescriptorSet descriptor_write_ubo {
.dstSet = *this->vk_descriptor_sets[i], .dstSet = *this->vk_descriptor_sets[i],
.dstBinding = 0, .dstBinding = 0,
.dstArrayElement = 0, .dstArrayElement = 0,
@ -750,8 +834,29 @@ public:
.pBufferInfo = &descriptor_buffer_info_handle, .pBufferInfo = &descriptor_buffer_info_handle,
.pTexelBufferView = nullptr, // Optional .pTexelBufferView = nullptr, // Optional
}; };
write_descriptor_sets.emplace_back(descriptor_write); write_descriptor_sets.emplace_back(descriptor_write_ubo);
} }
std::vector<vk::DescriptorImageInfo> image_infos;
image_infos.reserve(this->vk_max_frames_in_flight);
for (std::size_t i = 0; i < this->vk_max_frames_in_flight; i++) {
const vk::DescriptorImageInfo descriptor_image_info_texture {
.sampler = **this->vk_texture_sampler,
.imageView = **this->vk_texture_view,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
const vk::DescriptorImageInfo& descriptor_image_info_handle = image_infos.emplace_back(descriptor_image_info_texture);
const vk::WriteDescriptorSet descriptor_write_texture {
.dstSet = *this->vk_descriptor_sets[i],
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &descriptor_image_info_handle // Optional
};
write_descriptor_sets.emplace_back(descriptor_write_texture);
}
this->vk_gpu->updateDescriptorSets(write_descriptor_sets, nullptr); this->vk_gpu->updateDescriptorSets(write_descriptor_sets, nullptr);
} }
} catch (const vk::SystemError& error) { } catch (const vk::SystemError& error) {
@ -769,8 +874,7 @@ public:
} }
protected: protected:
VulkanBuffers VulkanBuffer CreateBuffer(vk::DeviceSize wanted_size, vk::BufferUsageFlags wanted_usage, vk::MemoryPropertyFlags wanted_properties) const {
CreateBuffer(vk::DeviceSize wanted_size, vk::BufferUsageFlags wanted_usage, vk::MemoryPropertyFlags wanted_properties) const {
const vk::BufferCreateInfo buffer_create_info { const vk::BufferCreateInfo buffer_create_info {
.size = wanted_size, .size = wanted_size,
.usage = wanted_usage, .usage = wanted_usage,
@ -779,7 +883,45 @@ protected:
const auto allocated_buffer = std::make_unique<vk::raii::Buffer>(*this->vk_gpu, buffer_create_info); const auto allocated_buffer = std::make_unique<vk::raii::Buffer>(*this->vk_gpu, buffer_create_info);
const auto memory_requirements = allocated_buffer->getMemoryRequirements(); const auto memory_requirements = allocated_buffer->getMemoryRequirements();
const auto FindMemoryType = [this](const std::uint32_t& type_filter, const vk::MemoryPropertyFlags& wanted_properties) -> std::uint32_t {
const vk::MemoryAllocateInfo vertex_allocate_info {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = this->FindMemoryType(memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)
};
const auto allocated_buffer_memory = std::make_unique<vk::raii::DeviceMemory>(*this->vk_gpu, vertex_allocate_info);
allocated_buffer->bindMemory(**allocated_buffer_memory, 0);
return { std::make_unique<vk::raii::Buffer>(std::move(*allocated_buffer)), std::make_unique<vk::raii::DeviceMemory>(std::move(*allocated_buffer_memory)) };
};
VulkanImage CreateImage(vk::Extent2D image_size, vk::Format wanted_format, vk::ImageTiling wanted_tiling, vk::ImageUsageFlags wanted_usage, vk::MemoryPropertyFlags wanted_properties) const {
const vk::ImageCreateInfo image_create_info {
.imageType = vk::ImageType::e2D,
.format = wanted_format,
.extent {
.width = image_size.width,
.height = image_size.height,
.depth = 1,
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1,
.tiling = wanted_tiling, // https://docs.vulkan.org/tutorial/latest/06_Texture_mapping/00_Images.html#_texture_image
.usage = wanted_usage,
.sharingMode = vk::SharingMode::eExclusive,
.initialLayout = vk::ImageLayout::eUndefined,
//.flags = 0, // optional
};
const auto allocated_image_texture = std::make_unique<vk::raii::Image>(*this->vk_gpu, image_create_info);
const auto memory_requirements = allocated_image_texture->getMemoryRequirements();
const vk::MemoryAllocateInfo image_allocate_info {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = this->FindMemoryType(memory_requirements.memoryTypeBits, wanted_properties)
};
const auto allocated_image_memory = std::make_unique<vk::raii::DeviceMemory>(*this->vk_gpu, image_allocate_info);
allocated_image_texture->bindMemory(**allocated_image_memory, 0);
return { std::make_unique<vk::raii::Image>(std::move(*allocated_image_texture)), std::make_unique<vk::raii::DeviceMemory>(std::move(*allocated_image_memory)) };
}
const std::uint32_t FindMemoryType(const std::uint32_t& type_filter, const vk::MemoryPropertyFlags& wanted_properties) const {
const auto memory_properties = this->vk_gfx_card->getMemoryProperties(); const auto memory_properties = this->vk_gfx_card->getMemoryProperties();
const std::uint32_t memory_type_count = memory_properties.memoryTypeCount; const std::uint32_t memory_type_count = memory_properties.memoryTypeCount;
@ -794,30 +936,54 @@ protected:
if (memory_type_to_test == memory_type_count) if (memory_type_to_test == memory_type_count)
throw std::runtime_error("failed to find suitable memory type!"); throw std::runtime_error("failed to find suitable memory type!");
return memory_type_to_test; return memory_type_to_test;
}; }
const vk::MemoryAllocateInfo vertex_allocate_info { void CopyBuffer(const vk::CommandBuffer& command_buffer, const vk::Buffer& src_buffer, const vk::Buffer& dest_buffer, const vk::DeviceSize& size) const {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = FindMemoryType(memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)
};
const auto allocated_buffer_memory = std::make_unique<vk::raii::DeviceMemory>(*this->vk_gpu, vertex_allocate_info);
allocated_buffer->bindMemory(**allocated_buffer_memory, 0);
return { std::make_unique<vk::raii::Buffer>(std::move(*allocated_buffer)), std::make_unique<vk::raii::DeviceMemory>(std::move(*allocated_buffer_memory)) };
};
void CopyBuffer(const vk::Buffer& src_buffer, const vk::Buffer& dest_buffer, const vk::DeviceSize& size) const {
const vk::CommandBufferAllocateInfo command_buffer_allocate_info {
.commandPool = **this->vk_command_pool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1
};
const auto command_buffer = std::move(vk::raii::CommandBuffers(*this->vk_gpu, command_buffer_allocate_info).front());
command_buffer.begin(vk::CommandBufferBeginInfo { .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
const vk::BufferCopy copy_region { const vk::BufferCopy copy_region {
//.srcOffset = 0, // Optional //.srcOffset = 0, // Optional
//.dstOffset = 0, // Optional //.dstOffset = 0, // Optional
.size = size .size = size
}; };
command_buffer.copyBuffer(src_buffer, dest_buffer, { copy_region }); command_buffer.copyBuffer(src_buffer, dest_buffer, { copy_region });
}
void CopyBuffer(const vk::Buffer& src_buffer, const vk::Buffer& dest_buffer, const vk::DeviceSize& size) const {
this->SingleTimeSubmitCommand([&](const auto& command_buffer) {
this->CopyBuffer(command_buffer, src_buffer, dest_buffer, size);
});
};
void CopyBuffer(const vk::CommandBuffer& command_buffer, const vk::Buffer& src_buffer, const vk::Image& dest_buffer, const vk::Extent2D& size) const {
const vk::BufferImageCopy copy_region {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource = {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = { 0, 0, 0 },
.imageExtent = { size.width, size.height, 1 }
};
command_buffer.copyBufferToImage(src_buffer, dest_buffer, vk::ImageLayout::eTransferDstOptimal, copy_region);
}
void CopyBuffer(const vk::Buffer& src_buffer, const vk::Image& dest_buffer, const vk::Extent2D& size) const {
this->SingleTimeSubmitCommand([&](const auto& command_buffer) {
this->CopyBuffer(command_buffer, src_buffer, dest_buffer, size);
});
}
template <typename Func>
void SingleTimeSubmitCommand(const Func& single_time_function) const {
const vk::CommandBufferAllocateInfo command_buffer_allocate_info {
.commandPool = **this->vk_command_pool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1
};
auto command_buffer = std::move(vk::raii::CommandBuffers(*this->vk_gpu, command_buffer_allocate_info).front());
command_buffer.begin(vk::CommandBufferBeginInfo { .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
single_time_function(command_buffer);
command_buffer.end(); command_buffer.end();
const vk::SubmitInfo submit_queue { const vk::SubmitInfo submit_queue {
@ -826,7 +992,104 @@ protected:
}; };
this->vk_queue_graphics->submit(submit_queue); this->vk_queue_graphics->submit(submit_queue);
this->vk_queue_graphics->waitIdle(); this->vk_queue_graphics->waitIdle();
}
void TransitionImageLayout(const vk::CommandBuffer& command_buffer, const vk::Image& image, vk::Format format, const vk::ImageLayout& old_layout, const vk::ImageLayout& new_layout) const {
// https://github.com/KhronosGroup/Vulkan-Hpp/blob/main/RAII_Samples/utils/utils.hpp#L101 // credits to the vulkanhpp project for having fantastic usage examples
// https://docs.vulkan.org/tutorial/latest/06_Texture_mapping/00_Images.html#_transition_barrier_masks
const vk::AccessFlags source_access_mask = [](const vk::ImageLayout& old_layout) -> vk::AccessFlags {
switch (old_layout) {
case vk::ImageLayout::eTransferDstOptimal:
return vk::AccessFlagBits::eTransferWrite;
case vk::ImageLayout::ePreinitialized:
return vk::AccessFlagBits::eHostWrite;
case vk::ImageLayout::eGeneral: // sourceAccessMask is empty
case vk::ImageLayout::eUndefined:
break;
default:
assert(false);
break;
}
return {};
}(old_layout);
const vk::PipelineStageFlags source_stage = [](const vk::ImageLayout& old_layout) -> vk::PipelineStageFlags {
switch (old_layout) {
case vk::ImageLayout::eGeneral:
case vk::ImageLayout::ePreinitialized:
return vk::PipelineStageFlagBits::eHost;
case vk::ImageLayout::eTransferDstOptimal:
return vk::PipelineStageFlagBits::eTransfer;
case vk::ImageLayout::eUndefined:
return vk::PipelineStageFlagBits::eTopOfPipe;
default:
assert(false);
break;
}
return {};
}(old_layout);
const vk::AccessFlags destination_access_mask = [](const vk::ImageLayout& new_layout) -> vk::AccessFlags {
switch (new_layout) {
case vk::ImageLayout::eColorAttachmentOptimal:
return vk::AccessFlagBits::eColorAttachmentWrite;
case vk::ImageLayout::eDepthStencilAttachmentOptimal:
return vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
case vk::ImageLayout::eGeneral: // empty destinationAccessMask
case vk::ImageLayout::ePresentSrcKHR:
break;
case vk::ImageLayout::eShaderReadOnlyOptimal:
return vk::AccessFlagBits::eShaderRead;
case vk::ImageLayout::eTransferSrcOptimal:
return vk::AccessFlagBits::eTransferRead;
case vk::ImageLayout::eTransferDstOptimal:
return vk::AccessFlagBits::eTransferWrite;
default:
assert(false);
break;
}
return {};
}(new_layout);
const vk::PipelineStageFlags destination_stage = [](const vk::ImageLayout& new_layout) -> vk::PipelineStageFlags {
switch (new_layout) {
case vk::ImageLayout::eColorAttachmentOptimal:
return vk::PipelineStageFlagBits::eColorAttachmentOutput;
case vk::ImageLayout::eDepthStencilAttachmentOptimal:
return vk::PipelineStageFlagBits::eEarlyFragmentTests;
case vk::ImageLayout::eGeneral:
return vk::PipelineStageFlagBits::eHost;
case vk::ImageLayout::ePresentSrcKHR:
return vk::PipelineStageFlagBits::eBottomOfPipe;
case vk::ImageLayout::eShaderReadOnlyOptimal:
return vk::PipelineStageFlagBits::eFragmentShader;
case vk::ImageLayout::eTransferDstOptimal:
case vk::ImageLayout::eTransferSrcOptimal:
return vk::PipelineStageFlagBits::eTransfer;
default:
assert(false);
break;
}
return {};
}(new_layout);
const vk::ImageMemoryBarrier image_memory_barrier {
.srcAccessMask = source_access_mask,
.dstAccessMask = destination_access_mask,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = image,
.subresourceRange = {
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}
}; };
command_buffer.pipelineBarrier(source_stage, destination_stage, {}, nullptr, nullptr, image_memory_barrier);
}
public: public:
void Run() { void Run() {