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")
cmake_path(GET file_path PARENT_PATH file_parent)
cmake_path(GET file_path FILENAME file_name)
exec_program("${ImageMagick_identify_EXECUTABLE}" "${file_parent}"
ARGS -format "%[fx:w]" "${file_name}"
OUTPUT_VARIABLE image_width)
exec_program("${ImageMagick_identify_EXECUTABLE}" "${file_parent}"
ARGS -format "%[fx:h]" "${file_name}"
OUTPUT_VARIABLE image_height)
execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:w]" "${file_name}"
WORKING_DIRECTORY "${file_parent}"
OUTPUT_VARIABLE image_width
COMMAND_ERROR_IS_FATAL ANY)
execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:h]" "${file_name}"
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")
elseif (type STREQUAL "embed")
@ -206,7 +208,7 @@ public:
endforeach()
set(EMBED_OBJ_RET "${EMBED_OBJ_RET}" PARENT_SCOPE)
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_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
layout(location = 0) out vec4 out_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() {
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 = 2) in vec3 in_color;
layout(location = 4) in vec2 in_texture_coordinate;
layout(location = 0) out vec3 frag_color;
layout(location = 1) out vec2 frag_texture_coordinate;
void main() {
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_texture_coordinate = in_texture_coordinate;
}

View File

@ -68,7 +68,8 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugCallback(
class VulkanExampleApplication {
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::Window> window;
@ -119,12 +120,13 @@ private:
} vk_physical_card_info;
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
VulkanBuffers vk_buffer_index; // used to make rendering models more efficent by sharing values
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
VulkanBuffer vk_buffer_index; // used to make rendering models more efficent by sharing values
struct Vertex {
glm::vec2 pos;
glm::vec3 color;
glm::vec2 texture_coordinates;
static constexpr vk::VertexInputBindingDescription GetBindingDescription() {
constexpr vk::VertexInputBindingDescription binding_description {
@ -134,8 +136,8 @@ public:
};
return binding_description;
}
static constexpr std::array<vk::VertexInputAttributeDescription, 2> GetAttributeDescriptions() {
constexpr std::array<vk::VertexInputAttributeDescription, 2> attribute_descriptions {
static constexpr std::array<vk::VertexInputAttributeDescription, 3> GetAttributeDescriptions() {
constexpr std::array<vk::VertexInputAttributeDescription, 3> attribute_descriptions {
vk::VertexInputAttributeDescription { // https://docs.vulkan.org/tutorial/latest/04_Vertex_buffers/00_Vertex_input_description.html
.location = 0,
.binding = 0,
@ -145,16 +147,22 @@ public:
.location = 2,
.binding = 0,
.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;
}
};
static inline const std::vector<Vertex> quad_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 } }
};
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
@ -167,9 +175,14 @@ public:
alignas(16) glm::mat4 view;
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;
public:
VulkanImage vk_texture_image;
std::unique_ptr<vk::raii::ImageView> vk_texture_view;
std::unique_ptr<vk::raii::Sampler> vk_texture_sampler;
public:
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.
@ -304,6 +317,9 @@ public:
if (!VulkanCheckDeviceExtensionSupport(gfx_card))
return ret;
if (!device_features.samplerAnisotropy)
return ret;
ret.surface_capabilities = gfx_card.getSurfaceCapabilitiesKHR(*found_screen_surface);
const auto surface_present_modes = gfx_card.getSurfacePresentModesKHR(*found_screen_surface);
const auto surface_formats = gfx_card.getSurfaceFormatsKHR(*found_screen_surface);
@ -352,7 +368,9 @@ public:
return device_queues_we_need;
}(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 {
.queueCreateInfoCount = static_cast<uint32_t>(device_queue_create_infos.size()),
.pQueueCreateInfos = device_queue_create_infos.data(),
@ -552,16 +570,25 @@ public:
};
// Descriptor Layouts, appears required.
constexpr auto descriptor_set_layout_binding_ubo = vk::DescriptorSetLayoutBinding {
constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_ubo {
.binding = 0,
.descriptorType = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eVertex,
.pImmutableSamplers = nullptr // Optional
};
const auto descriptor_set_layout_create_info = vk::DescriptorSetLayoutCreateInfo {
.bindingCount = 1,
.pBindings = &descriptor_set_layout_binding_ubo
constexpr vk::DescriptorSetLayoutBinding descriptor_set_layout_binding_sampler {
.binding = 1,
.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);
@ -575,15 +602,20 @@ public:
this->vk_pipeline_layout = std::make_unique<vk::raii::PipelineLayout>(*this->vk_gpu, pipeline_layout_create_info);
// descriptors
const vk::DescriptorPoolSize descriptor_pool_size {
const vk::DescriptorPoolSize descriptor_pool_size_ubo {
.type = vk::DescriptorType::eUniformBuffer,
.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 {
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = static_cast<uint32_t>(this->vk_max_frames_in_flight),
.poolSizeCount = 1,
.pPoolSizes = &descriptor_pool_size,
.poolSizeCount = static_cast<uint32_t>(descriptor_pool_sizes.size()),
.pPoolSizes = descriptor_pool_sizes.data(),
};
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);
@ -717,7 +749,7 @@ public:
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_mapped.empty());
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.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::WriteDescriptorSet> write_descriptor_sets;
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++) {
const vk::DescriptorBufferInfo descriptor_buffer_info {
const vk::DescriptorBufferInfo descriptor_buffer_info_ubo {
.buffer = **this->vk_buffers_uniform.at(i).first,
.offset = 0,
.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],
.dstBinding = 0,
.dstArrayElement = 0,
@ -750,8 +834,29 @@ public:
.pBufferInfo = &descriptor_buffer_info_handle,
.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);
}
} catch (const vk::SystemError& error) {
@ -769,8 +874,7 @@ public:
}
protected:
VulkanBuffers
CreateBuffer(vk::DeviceSize wanted_size, vk::BufferUsageFlags wanted_usage, vk::MemoryPropertyFlags wanted_properties) const {
VulkanBuffer CreateBuffer(vk::DeviceSize wanted_size, vk::BufferUsageFlags wanted_usage, vk::MemoryPropertyFlags wanted_properties) const {
const vk::BufferCreateInfo buffer_create_info {
.size = wanted_size,
.usage = wanted_usage,
@ -779,45 +883,107 @@ protected:
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 FindMemoryType = [this](const std::uint32_t& type_filter, const vk::MemoryPropertyFlags& wanted_properties) -> std::uint32_t {
const auto memory_properties = this->vk_gfx_card->getMemoryProperties();
const std::uint32_t memory_type_count = memory_properties.memoryTypeCount;
std::uint32_t memory_type_to_test;
for (memory_type_to_test = 0; memory_type_to_test < memory_type_count; memory_type_to_test++) {
if ((*reinterpret_cast<const std::bitset<sizeof(type_filter) * 8>*>(&type_filter))[memory_type_to_test]) {
if ((memory_properties.memoryTypes[memory_type_to_test].propertyFlags & wanted_properties) == wanted_properties) {
break;
}
}
}
if (memory_type_to_test == memory_type_count)
throw std::runtime_error("failed to find suitable memory type!");
return memory_type_to_test;
};
const vk::MemoryAllocateInfo vertex_allocate_info {
.allocationSize = memory_requirements.size,
.memoryTypeIndex = FindMemoryType(memory_requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)
.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)) };
};
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
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 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 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 std::uint32_t memory_type_count = memory_properties.memoryTypeCount;
std::uint32_t memory_type_to_test;
for (memory_type_to_test = 0; memory_type_to_test < memory_type_count; memory_type_to_test++) {
if ((*reinterpret_cast<const std::bitset<sizeof(type_filter) * 8>*>(&type_filter))[memory_type_to_test]) {
if ((memory_properties.memoryTypes[memory_type_to_test].propertyFlags & wanted_properties) == wanted_properties) {
break;
}
}
}
if (memory_type_to_test == memory_type_count)
throw std::runtime_error("failed to find suitable memory type!");
return memory_type_to_test;
}
void CopyBuffer(const vk::CommandBuffer& command_buffer, const vk::Buffer& src_buffer, const vk::Buffer& dest_buffer, const vk::DeviceSize& size) const {
const vk::BufferCopy copy_region {
//.srcOffset = 0, // Optional
//.dstOffset = 0, // Optional
.size = size
};
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();
const vk::SubmitInfo submit_queue {
@ -826,7 +992,104 @@ protected:
};
this->vk_queue_graphics->submit(submit_queue);
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:
void Run() {