Start Rendering a debug Test Image on our Plane.
All checks were successful
ci/woodpecker/push/woodpecker.json Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker.json Pipeline was successful
This commit is contained in:
parent
18a990133f
commit
30ed1f679b
@ -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
BIN
res/debug_north.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 628 B |
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
367
src/main.cpp
367
src/main.cpp
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user