From e55601b5a67ebff63620c0d9adb6a669b52518f9 Mon Sep 17 00:00:00 2001 From: Slendi Date: Sun, 11 Jan 2026 15:01:48 +0200 Subject: [PATCH] Add skybox Signed-off-by: Slendi --- .gitignore | 1 + meson.build | 1 + src/Application.cpp | 93 ++----------- src/Application.h | 5 +- src/Skybox.cpp | 295 +++++++++++++++++++++++++++++++++++++++++ src/Skybox.h | 32 +++++ src/VulkanRenderer.cpp | 157 ++++++++++++++++++++++ src/VulkanRenderer.h | 10 +- 8 files changed, 508 insertions(+), 86 deletions(-) create mode 100644 src/Skybox.cpp create mode 100644 src/Skybox.h diff --git a/.gitignore b/.gitignore index 3ec0b22..c17a094 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ result .cache .direnv .clangd +screenshot* diff --git a/meson.build b/meson.build index f3b6ec8..0aa7aa7 100644 --- a/meson.build +++ b/meson.build @@ -161,6 +161,7 @@ exe = executable('vr-compositor', 'src/Loader.cpp', 'src/DescriptorWriter.cpp', 'src/CPUTexture.cpp', + 'src/Skybox.cpp', 'src/VulkanRenderer.cpp', 'src/Application.cpp', ], diff --git a/src/Application.cpp b/src/Application.cpp index 76a42ae..9a4da8a 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -51,7 +51,6 @@ #include -#include "GraphicsPipelineBuilder.h" #include "Util.h" #include "VulkanRenderer.h" @@ -419,7 +418,10 @@ Application::Application() } m_renderer = std::make_unique(m_window, m_logger); - init_skybox_pipeline(); + m_renderer->set_antialiasing_immediate( + VulkanRenderer::AntiAliasingKind::MSAA_4X); + + m_skybox.init(*m_renderer, asset_directory() / "cubemap.png"); init_test_meshes(); init_input(); @@ -428,8 +430,6 @@ Application::Application() m_logger.info("App init done!"); - m_renderer->set_antialiasing(VulkanRenderer::AntiAliasingKind::MSAA_4X); - m_cursor = PolarCoordinate::from_vec3(m_camera.target - m_camera.position); } @@ -437,6 +437,7 @@ Application::~Application() { if (m_renderer) { m_renderer->device().waitIdle(); + m_skybox.destroy(*m_renderer); for (auto const &mesh : m_test_meshes) { m_renderer->destroy_buffer(mesh->mesh_buffers.index_buffer); m_renderer->destroy_buffer(mesh->mesh_buffers.vertex_buffer); @@ -444,7 +445,6 @@ Application::~Application() } m_test_meshes.clear(); - m_skybox_pipeline.reset(); m_renderer.reset(); shutdown_input(); @@ -455,83 +455,6 @@ Application::~Application() m_logger.info("App destroy done!"); } -auto Application::init_skybox_pipeline() -> void -{ - struct SkyboxPushConstants { - smath::Mat4 mvp; - }; - - Pipeline::Builder builder { m_renderer->device(), m_logger }; - - uint8_t skybox_vert_shader_data[] { -#embed "skybox_vert.spv" - }; - auto skybox_vert_shader - = vkutil::load_shader_module(std::span(skybox_vert_shader_data, - sizeof(skybox_vert_shader_data)), - m_renderer->device()); - if (!skybox_vert_shader) { - m_logger.err("Failed to load skybox vert shader"); - } - - uint8_t skybox_frag_shader_data[] { -#embed "skybox_frag.spv" - }; - auto skybox_frag_shader - = vkutil::load_shader_module(std::span(skybox_frag_shader_data, - sizeof(skybox_frag_shader_data)), - m_renderer->device()); - if (!skybox_frag_shader) { - m_logger.err("Failed to load skybox frag shader"); - } - - vk::PushConstantRange push_constant_range {}; - push_constant_range.stageFlags = vk::ShaderStageFlagBits::eVertex; - push_constant_range.offset = 0; - push_constant_range.size = sizeof(SkyboxPushConstants); - - std::array push_constant_ranges { push_constant_range }; - builder.set_push_constant_ranges(push_constant_ranges); - std::array descriptor_set_layouts { - m_renderer->single_image_descriptor_layout(), - }; - builder.set_descriptor_set_layouts(descriptor_set_layouts); - - VkVertexInputBindingDescription binding {}; - binding.binding = 0; - binding.stride = sizeof(smath::Vec3); - binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - VkVertexInputAttributeDescription attribute {}; - attribute.location = 0; - attribute.binding = 0; - attribute.format = VK_FORMAT_R32G32B32_SFLOAT; - attribute.offset = 0; - - std::array bindings { binding }; - std::array attributes { attribute }; - - m_skybox_pipeline = builder.build_graphics( - [&](GraphicsPipelineBuilder &pipeline_builder) - -> GraphicsPipelineBuilder & { - pipeline_builder.set_vertex_input(bindings, attributes); - return pipeline_builder - .set_shaders(skybox_vert_shader.get(), skybox_frag_shader.get()) - .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) - .set_polygon_mode(VK_POLYGON_MODE_FILL) - .set_cull_mode( - VK_CULL_MODE_FRONT_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE) - .set_multisampling(static_cast( - m_renderer->msaa_samples())) - .disable_blending() - .enable_depth_testing(false, VK_COMPARE_OP_LESS_OR_EQUAL) - .set_color_attachment_format( - static_cast(m_renderer->draw_image_format())) - .set_depth_format( - static_cast(m_renderer->depth_image_format())); - }); -} - auto Application::binary_directory() const -> std::filesystem::path { auto const *base_path = SDL_GetBasePath(); @@ -872,6 +795,12 @@ auto Application::run() -> void projection[1][1] *= -1; auto view_projection { projection * view }; + auto skybox_view = view; + skybox_view[3][0] = 0.0f; + skybox_view[3][1] = 0.0f; + skybox_view[3][2] = 0.0f; + m_skybox.draw(gl, projection * skybox_view); + gl.set_transform(view_projection); gl.set_texture(); diff --git a/src/Application.h b/src/Application.h index 8e71bfb..af40ce3 100644 --- a/src/Application.h +++ b/src/Application.h @@ -11,7 +11,7 @@ #include "Loader.h" #include "Logger.h" -#include "Pipeline.h" +#include "Skybox.h" #include "Types.h" struct libinput; @@ -37,7 +37,6 @@ struct Application { private: auto init_input() -> void; - auto init_skybox_pipeline() -> void; auto init_test_meshes() -> void; auto asset_directory() -> std::filesystem::path; auto shutdown_input() -> void; @@ -48,7 +47,7 @@ private: SDL_Window *m_window { nullptr }; Logger m_logger { "Lunar" }; std::unique_ptr m_renderer; - Pipeline m_skybox_pipeline; + Skybox m_skybox; std::vector> m_test_meshes; udev *m_udev { nullptr }; diff --git a/src/Skybox.cpp b/src/Skybox.cpp new file mode 100644 index 0000000..b58590b --- /dev/null +++ b/src/Skybox.cpp @@ -0,0 +1,295 @@ +#include "Skybox.h" + +#include +#include +#include +#include + +#include "CPUTexture.h" +#include "DescriptorWriter.h" +#include "GraphicsPipelineBuilder.h" +#include "Util.h" + +namespace Lunar { + +namespace { + +struct SkyboxPushConstants { + smath::Mat4 mvp; +}; + +struct FaceOffset { + uint32_t x; + uint32_t y; +}; + +constexpr std::array kCrossOffsets { + FaceOffset { 2, 1 }, // +X + FaceOffset { 0, 1 }, // -X + FaceOffset { 1, 0 }, // +Y + FaceOffset { 1, 2 }, // -Y + FaceOffset { 1, 1 }, // +Z + FaceOffset { 3, 1 }, // -Z +}; + +} // namespace + +auto Skybox::init(VulkanRenderer &renderer, std::filesystem::path const &path) + -> void +{ + if (ok) { + destroy(renderer); + ok = false; + } + + CPUTexture texture { path }; + + if (texture.width == 0 || texture.height == 0) { + renderer.logger().err("Skybox texture is empty: {}", path.string()); + ok = false; + return; + } + + if (texture.width % 4 != 0 || texture.height % 3 != 0 + || texture.width / 4 != texture.height / 3) { + renderer.logger().err( + "Skybox texture must be 4x3 faces: {}", path.string()); + ok = false; + return; + } + + uint32_t const face_size = texture.width / 4; + size_t const face_bytes = static_cast(face_size) * face_size * 4; + + std::vector cubemap_pixels(face_bytes * kCrossOffsets.size()); + + for (size_t face = 0; face < kCrossOffsets.size(); ++face) { + auto const offset = kCrossOffsets[face]; + for (uint32_t y = 0; y < face_size; ++y) { + for (uint32_t x = 0; x < face_size; ++x) { + uint32_t const src_x = offset.x * face_size + x; + uint32_t const src_y = offset.y * face_size + y; + size_t const src_index + = (static_cast(src_y) * texture.width + src_x) * 4; + size_t const dst_index = face * face_bytes + + (static_cast(y) * face_size + x) * 4; + std::copy_n(texture.pixels.data() + src_index, 4, + cubemap_pixels.data() + dst_index); + } + } + } + + m_cubemap = renderer.create_cubemap(cubemap_pixels, face_size, + texture.format, vk::ImageUsageFlagBits::eSampled); + if (!m_cubemap.image) { + renderer.logger().err("Failed to create cubemap image"); + return; + } + + vk::SamplerCreateInfo sampler_ci {}; + sampler_ci.magFilter = vk::Filter::eLinear; + sampler_ci.minFilter = vk::Filter::eLinear; + sampler_ci.mipmapMode = vk::SamplerMipmapMode::eLinear; + sampler_ci.addressModeU = vk::SamplerAddressMode::eClampToEdge; + sampler_ci.addressModeV = vk::SamplerAddressMode::eClampToEdge; + sampler_ci.addressModeW = vk::SamplerAddressMode::eClampToEdge; + m_sampler = renderer.device().createSamplerUnique(sampler_ci); + + vk::DescriptorPoolSize pool_size {}; + pool_size.type = vk::DescriptorType::eCombinedImageSampler; + pool_size.descriptorCount = 1; + + vk::DescriptorPoolCreateInfo pool_ci {}; + pool_ci.maxSets = 1; + pool_ci.poolSizeCount = 1; + pool_ci.pPoolSizes = &pool_size; + m_descriptor_pool = renderer.device().createDescriptorPoolUnique(pool_ci); + + vk::DescriptorSetAllocateInfo alloc_info {}; + alloc_info.descriptorPool = m_descriptor_pool.get(); + alloc_info.descriptorSetCount = 1; + vk::DescriptorSetLayout layout = renderer.single_image_descriptor_layout(); + alloc_info.pSetLayouts = &layout; + m_descriptor_set + = renderer.device().allocateDescriptorSets(alloc_info).front(); + + DescriptorWriter() + .write_image(0, m_cubemap.image_view, m_sampler.get(), + static_cast(vk::ImageLayout::eShaderReadOnlyOptimal), + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) + .update_set(renderer.device(), m_descriptor_set); + + std::vector vertices; + vertices.reserve(8); + + auto push_vertex = [&](smath::Vec3 const &pos) { + Vertex v {}; + v.position = pos; + v.u = 0.0f; + v.v = 0.0f; + v.normal = smath::Vec3 { 0.0f, 0.0f, 1.0f }; + v.color = smath::Vec4 { 1.0f, 1.0f, 1.0f, 1.0f }; + vertices.emplace_back(v); + }; + + push_vertex(smath::Vec3 { -1.0f, -1.0f, -1.0f }); + push_vertex(smath::Vec3 { 1.0f, -1.0f, -1.0f }); + push_vertex(smath::Vec3 { 1.0f, 1.0f, -1.0f }); + push_vertex(smath::Vec3 { -1.0f, 1.0f, -1.0f }); + push_vertex(smath::Vec3 { -1.0f, -1.0f, 1.0f }); + push_vertex(smath::Vec3 { 1.0f, -1.0f, 1.0f }); + push_vertex(smath::Vec3 { 1.0f, 1.0f, 1.0f }); + push_vertex(smath::Vec3 { -1.0f, 1.0f, 1.0f }); + + std::vector indices { + 4, + 5, + 6, + 4, + 6, + 7, // +Z + 1, + 0, + 3, + 1, + 3, + 2, // -Z + 5, + 1, + 2, + 5, + 2, + 6, // +X + 0, + 4, + 7, + 0, + 7, + 3, // -X + 7, + 6, + 2, + 7, + 2, + 3, // +Y + 0, + 1, + 5, + 0, + 5, + 4, // -Y + }; + + m_index_count = static_cast(indices.size()); + m_cube_mesh = renderer.upload_mesh(indices, vertices); + + Pipeline::Builder pipeline_builder { renderer.device(), renderer.logger() }; + + uint8_t skybox_vert_shader_data[] { +#embed "skybox_vert.spv" + }; + auto skybox_vert_shader + = vkutil::load_shader_module(std::span(skybox_vert_shader_data, + sizeof(skybox_vert_shader_data)), + renderer.device()); + if (!skybox_vert_shader) { + renderer.logger().err("Failed to load skybox vert shader"); + ok = false; + return; + } + + uint8_t skybox_frag_shader_data[] { +#embed "skybox_frag.spv" + }; + auto skybox_frag_shader + = vkutil::load_shader_module(std::span(skybox_frag_shader_data, + sizeof(skybox_frag_shader_data)), + renderer.device()); + if (!skybox_frag_shader) { + renderer.logger().err("Failed to load skybox frag shader"); + ok = false; + return; + } + + vk::PushConstantRange push_constant_range {}; + push_constant_range.stageFlags = vk::ShaderStageFlagBits::eVertex; + push_constant_range.offset = 0; + push_constant_range.size = sizeof(SkyboxPushConstants); + + std::array push_constant_ranges { push_constant_range }; + pipeline_builder.set_push_constant_ranges(push_constant_ranges); + std::array descriptor_set_layouts { + renderer.single_image_descriptor_layout() + }; + pipeline_builder.set_descriptor_set_layouts(descriptor_set_layouts); + + VkVertexInputBindingDescription binding {}; + binding.binding = 0; + binding.stride = sizeof(Vertex); + binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkVertexInputAttributeDescription attribute {}; + attribute.location = 0; + attribute.binding = 0; + attribute.format = VK_FORMAT_R32G32B32_SFLOAT; + attribute.offset = offsetof(Vertex, position); + + std::array bindings { binding }; + std::array attributes { attribute }; + + m_pipeline = pipeline_builder.build_graphics( + [&](GraphicsPipelineBuilder &builder) -> GraphicsPipelineBuilder & { + builder.set_vertex_input(bindings, attributes); + return builder + .set_shaders(skybox_vert_shader.get(), skybox_frag_shader.get()) + .set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) + .set_polygon_mode(VK_POLYGON_MODE_FILL) + .set_cull_mode( + VK_CULL_MODE_FRONT_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE) + .set_multisampling( + static_cast(renderer.msaa_samples())) + .disable_blending() + .enable_depth_testing(false, VK_COMPARE_OP_LESS_OR_EQUAL) + .set_color_attachment_format( + static_cast(renderer.draw_image_format())) + .set_depth_format( + static_cast(renderer.depth_image_format())); + }); + + ok = true; +} + +auto Skybox::destroy(VulkanRenderer &renderer) -> void +{ + if (m_cube_mesh.index_buffer.buffer) { + renderer.destroy_buffer(m_cube_mesh.index_buffer); + } + if (m_cube_mesh.vertex_buffer.buffer) { + renderer.destroy_buffer(m_cube_mesh.vertex_buffer); + } + if (m_cubemap.image) { + renderer.destroy_image(m_cubemap); + } + m_sampler.reset(); + m_descriptor_pool.reset(); + m_pipeline.reset(); + m_descriptor_set = vk::DescriptorSet {}; + m_cube_mesh = {}; + m_cubemap = {}; + m_index_count = 0; + ok = false; +} + +auto Skybox::draw(VulkanRenderer::GL &gl, smath::Mat4 const &mvp) -> void +{ + if (!ok) { + return; + } + + SkyboxPushConstants push_constants { mvp }; + auto bytes = std::as_bytes(std::span { &push_constants, 1 }); + gl.draw_indexed(m_pipeline, m_descriptor_set, m_cube_mesh.vertex_buffer, + m_cube_mesh.index_buffer, m_index_count, bytes); +} + +} // namespace Lunar diff --git a/src/Skybox.h b/src/Skybox.h new file mode 100644 index 0000000..836ed64 --- /dev/null +++ b/src/Skybox.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include + +#include "Pipeline.h" +#include "Types.h" +#include "VulkanRenderer.h" + +namespace Lunar { + +struct Skybox { + bool ok { false }; + + auto init(VulkanRenderer &renderer, std::filesystem::path const &path) + -> void; + auto destroy(VulkanRenderer &renderer) -> void; + auto draw(VulkanRenderer::GL &gl, smath::Mat4 const &mvp) -> void; + +private: + Pipeline m_pipeline {}; + GPUMeshBuffers m_cube_mesh {}; + AllocatedImage m_cubemap {}; + vk::UniqueSampler m_sampler {}; + vk::UniqueDescriptorPool m_descriptor_pool {}; + vk::DescriptorSet m_descriptor_set {}; + uint32_t m_index_count { 0 }; +}; + +} // namespace Lunar diff --git a/src/VulkanRenderer.cpp b/src/VulkanRenderer.cpp index feb4687..36e62f9 100644 --- a/src/VulkanRenderer.cpp +++ b/src/VulkanRenderer.cpp @@ -517,6 +517,36 @@ auto VulkanRenderer::GL::draw_mesh(GPUMeshBuffers const &mesh, m_cmd.drawIndexed(index_count, 1, first_index, vertex_offset, 0); } +auto VulkanRenderer::GL::draw_indexed(Pipeline &pipeline, + vk::DescriptorSet descriptor_set, AllocatedBuffer const &vertex_buffer, + AllocatedBuffer const &index_buffer, uint32_t index_count, + std::span push_constants) -> void +{ + assert(m_drawing && "begin_drawing must be called first"); + + if (m_inside_primitive) { + end(); + } + flush(); + use_pipeline(pipeline); + + auto cmd { m_cmd }; + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + pipeline.get_layout(), 0, descriptor_set, {}); + + if (!push_constants.empty()) { + cmd.pushConstants(pipeline.get_layout(), + vk::ShaderStageFlagBits::eVertex, 0, + static_cast(push_constants.size()), + push_constants.data()); + } + + vk::DeviceSize offset = 0; + cmd.bindVertexBuffers(0, vertex_buffer.buffer, offset); + cmd.bindIndexBuffer(index_buffer.buffer, 0, vk::IndexType::eUint32); + cmd.drawIndexed(index_count, 1, 0, 0, 0); +} + auto VulkanRenderer::GL::push_vertex(smath::Vec3 const &pos) -> void { assert(m_drawing && "begin_drawing must be called first"); @@ -678,6 +708,11 @@ auto VulkanRenderer::set_antialiasing(AntiAliasingKind kind) -> void }); } +auto VulkanRenderer::set_antialiasing_immediate(AntiAliasingKind kind) -> void +{ + apply_antialiasing(kind); +} + auto VulkanRenderer::apply_antialiasing(AntiAliasingKind kind) -> void { auto requested_samples = [&](AntiAliasingKind aa) { @@ -2162,6 +2197,128 @@ auto VulkanRenderer::create_image(CPUTexture const &texture, texture.pixels.data(), size, texture.format, flags, mipmapped); } +auto VulkanRenderer::create_cubemap(std::span pixels, + uint32_t face_size, vk::Format format, vk::ImageUsageFlags flags) + -> AllocatedImage +{ + size_t const face_bytes = static_cast(face_size) * face_size * 4; + if (pixels.size() < face_bytes * 6) { + m_logger.err("Cubemap data size is invalid"); + return {}; + } + + auto const upload_buffer { + create_buffer(pixels.size(), vk::BufferUsageFlagBits::eTransferSrc, + VMA_MEMORY_USAGE_CPU_TO_GPU), + }; + + VmaAllocationInfo info {}; + vmaGetAllocationInfo(m_vk.allocator, upload_buffer.allocation, &info); + + void *mapped_data { reinterpret_cast(info.pMappedData) }; + bool mapped_here { false }; + if (!mapped_data) { + VkResult res = vmaMapMemory( + m_vk.allocator, upload_buffer.allocation, (void **)&mapped_data); + assert(res == VK_SUCCESS); + mapped_here = true; + } + + memcpy(mapped_data, pixels.data(), pixels.size()); + + AllocatedImage new_image {}; + new_image.format = format; + new_image.extent = vk::Extent3D { face_size, face_size, 1 }; + + auto img_ci { vkinit::image_create_info(format, + flags | vk::ImageUsageFlagBits::eTransferDst, new_image.extent, + vk::SampleCountFlagBits::e1) }; + img_ci.arrayLayers = 6; + img_ci.flags = vk::ImageCreateFlagBits::eCubeCompatible; + + VmaAllocationCreateInfo alloc_ci {}; + alloc_ci.usage = VMA_MEMORY_USAGE_GPU_ONLY; + alloc_ci.requiredFlags + = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + VK_CHECK(m_logger, + vmaCreateImage(m_vk.allocator, + reinterpret_cast(&img_ci), &alloc_ci, + reinterpret_cast(&new_image.image), + &new_image.allocation, nullptr)); + + vk::ImageViewCreateInfo view_ci {}; + view_ci.viewType = vk::ImageViewType::eCube; + view_ci.image = new_image.image; + view_ci.format = format; + view_ci.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + view_ci.subresourceRange.baseMipLevel = 0; + view_ci.subresourceRange.levelCount = 1; + view_ci.subresourceRange.baseArrayLayer = 0; + view_ci.subresourceRange.layerCount = 6; + new_image.image_view = m_device.createImageView(view_ci); + + immediate_submit([&](vk::CommandBuffer cmd) { + vk::ImageMemoryBarrier to_transfer {}; + to_transfer.srcAccessMask = vk::AccessFlagBits::eNone; + to_transfer.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + to_transfer.oldLayout = vk::ImageLayout::eUndefined; + to_transfer.newLayout = vk::ImageLayout::eTransferDstOptimal; + to_transfer.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + to_transfer.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + to_transfer.image = new_image.image; + to_transfer.subresourceRange.aspectMask + = vk::ImageAspectFlagBits::eColor; + to_transfer.subresourceRange.baseMipLevel = 0; + to_transfer.subresourceRange.levelCount = 1; + to_transfer.subresourceRange.baseArrayLayer = 0; + to_transfer.subresourceRange.layerCount = 6; + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, + vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, to_transfer); + + std::array regions {}; + for (uint32_t layer = 0; layer < 6; ++layer) { + vk::BufferImageCopy region {}; + region.bufferOffset = face_bytes * layer; + region.imageSubresource.aspectMask + = vk::ImageAspectFlagBits::eColor; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = layer; + region.imageSubresource.layerCount = 1; + region.imageExtent = new_image.extent; + regions[layer] = region; + } + + cmd.copyBufferToImage(upload_buffer.buffer, new_image.image, + vk::ImageLayout::eTransferDstOptimal, regions); + + vk::ImageMemoryBarrier to_read {}; + to_read.srcAccessMask = vk::AccessFlagBits::eTransferWrite; + to_read.dstAccessMask = vk::AccessFlagBits::eShaderRead; + to_read.oldLayout = vk::ImageLayout::eTransferDstOptimal; + to_read.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; + to_read.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + to_read.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + to_read.image = new_image.image; + to_read.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + to_read.subresourceRange.baseMipLevel = 0; + to_read.subresourceRange.levelCount = 1; + to_read.subresourceRange.baseArrayLayer = 0; + to_read.subresourceRange.layerCount = 6; + + cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, to_read); + }); + + if (mapped_here) { + vmaUnmapMemory(m_vk.allocator, upload_buffer.allocation); + } + destroy_buffer(upload_buffer); + + return new_image; +} + auto VulkanRenderer::destroy_image(AllocatedImage const &img) -> void { if (img.image_view) { diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h index 048fd1e..baf0d5e 100644 --- a/src/VulkanRenderer.h +++ b/src/VulkanRenderer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -92,6 +93,10 @@ struct VulkanRenderer { auto draw_mesh(GPUMeshBuffers const &mesh, smath::Mat4 const &transform, uint32_t index_count, uint32_t first_index = 0, int32_t vertex_offset = 0) -> void; + auto draw_indexed(Pipeline &pipeline, vk::DescriptorSet descriptor_set, + AllocatedBuffer const &vertex_buffer, + AllocatedBuffer const &index_buffer, uint32_t index_count, + std::span push_constants) -> void; private: auto push_vertex(smath::Vec3 const &pos) -> void; @@ -131,6 +136,7 @@ struct VulkanRenderer { auto render(std::function const &record = {}) -> void; auto resize(uint32_t width, uint32_t height) -> void; auto set_antialiasing(AntiAliasingKind kind) -> void; + auto set_antialiasing_immediate(AntiAliasingKind kind) -> void; auto antialiasing() const -> AntiAliasingKind { return m_vk.antialiasing_kind; @@ -144,6 +150,9 @@ struct VulkanRenderer { auto destroy_buffer(AllocatedBuffer const &buffer) -> void; auto create_image(CPUTexture const &texture, vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage; + auto create_cubemap(std::span pixels, uint32_t face_size, + vk::Format format, vk::ImageUsageFlags flags) -> AllocatedImage; + auto destroy_image(AllocatedImage const &img) -> void; auto rectangle_mesh() const -> GPUMeshBuffers const & { return m_vk.rectangle; @@ -262,7 +271,6 @@ private: bool mipmapped = false) -> AllocatedImage; auto create_image(void const *data, vk::Extent3D size, vk::Format format, vk::ImageUsageFlags flags, bool mipmapped = false) -> AllocatedImage; - auto destroy_image(AllocatedImage const &img) -> void; auto create_buffer(size_t alloc_size, vk::BufferUsageFlags usage, VmaMemoryUsage memory_usage) -> AllocatedBuffer;