diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 8b195501a..fd65478df 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -48,14 +48,15 @@ void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); Frontend::ScopeAcquireContext scope(core_context); - /*emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); Core::System::GetInstance().Renderer().Rasterizer()->LoadDiskResources( stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { emit LoadProgress(stage, value, total); }); - emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);*/ + emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); + emit HideLoadingScreen(); if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) { // Usually the loading screen is hidden after the first frame is drawn. In this case diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 0f06a6ee1..baea523d1 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -185,10 +185,12 @@ void RendererVulkan::PrepareRendertarget() { if (color_fill.is_enabled) { LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b, screen_infos[i]); } else { - auto extent = screen_infos[i].texture.GetArea().extent; - auto format = screen_infos[i].format; - if (extent.width != framebuffer.width || extent.height != framebuffer.height || - format != framebuffer.color_format) { + auto [width, height] = screen_infos[i].texture.GetArea().extent; + u32 fwidth = framebuffer.width; + u32 fheight = framebuffer.height; + + if (width != fwidth || height != fheight || + screen_infos[i].format != framebuffer.color_format) { // Reallocate texture if the framebuffer size has changed. // This is expected to not happen very often and hence should not be a // performance problem. @@ -271,6 +273,7 @@ void RendererVulkan::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color */ void RendererVulkan::CreateVulkanObjects() { clear_color = vk::ClearColorValue{std::array{Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f}}; + clear_color = vk::ClearColorValue(std::array{1.0f, 0.0f, 0.0, 1.0f}); //filter_sampler.Create(); //ReloadSampler(); @@ -286,7 +289,7 @@ void RendererVulkan::CreateVulkanObjects() { } void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU::Regs::FramebufferConfig& framebuffer) { - GPU::Regs::PixelFormat format = framebuffer.color_format; + screen.format = framebuffer.color_format; VKTexture::Info texture_info{ .width = framebuffer.width, @@ -298,7 +301,7 @@ void RendererVulkan::ConfigureFramebufferTexture(ScreenInfo& screen, const GPU:: vk::ImageUsageFlagBits::eSampled }; - switch (format) { + switch (screen.format) { case GPU::Regs::PixelFormat::RGBA8: texture_info.format = vk::Format::eR8G8B8A8Srgb; break; @@ -371,7 +374,9 @@ void RendererVulkan::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa state.ApplyPresentState(); auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); - cmdbuffer.bindVertexBuffers(0, vertex_buffer.GetBuffer(), {0}); + vk::DeviceSize offset = 0; + + cmdbuffer.bindVertexBuffers(0, 1, &vertex_buffer.GetBuffer(), &offset); cmdbuffer.draw(4, 1, 0, 0); } @@ -716,9 +721,9 @@ VideoCore::ResultStatus RendererVulkan::Init() { g_vk_instace->Create(instance, physical_devices[1], surface, true); g_vk_task_scheduler->Create(); - auto& layout = render_window.GetFramebufferLayout(); + //auto& layout = render_window.GetFramebufferLayout(); swapchain = std::make_shared(surface); - swapchain->Create(layout.width, layout.height, false); + //swapchain->Create(layout.width, layout.height, false); // Create Vulkan state VulkanState::Create(swapchain); diff --git a/src/video_core/renderer_vulkan/vk_buffer.cpp b/src/video_core/renderer_vulkan/vk_buffer.cpp index c1ac78822..4774fcfe8 100644 --- a/src/video_core/renderer_vulkan/vk_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer.cpp @@ -158,6 +158,9 @@ void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block, buffer_pos += size; } + else { + printf("f"); + } } } diff --git a/src/video_core/renderer_vulkan/vk_buffer.h b/src/video_core/renderer_vulkan/vk_buffer.h index 02cfbfa6a..8a997e647 100644 --- a/src/video_core/renderer_vulkan/vk_buffer.h +++ b/src/video_core/renderer_vulkan/vk_buffer.h @@ -44,7 +44,7 @@ public: /// Return a pointer to the mapped memory if the buffer is host mapped u8* GetHostPointer() const { return reinterpret_cast(host_ptr); } const vk::BufferView& GetView(u32 i = 0) const { return views[i]; } - vk::Buffer GetBuffer() const { return buffer; } + const vk::Buffer& GetBuffer() const { return buffer; } u32 GetSize() const { return buffer_info.size; } void Upload(std::span data, u32 offset, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp b/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp index 01cde1f5e..e117007d7 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp @@ -245,7 +245,7 @@ void PipelineBuilder::SetRenderingFormats(vk::Format color, vk::Format depth_ste }; const u32 color_attachment_count = color == vk::Format::eUndefined ? 0 : 1; - rendering_info = vk::PipelineRenderingCreateInfoKHR{0, color_attachment_count, &color_format, depth_stencil_format, + rendering_info = vk::PipelineRenderingCreateInfo{0, color_attachment_count, &color_format, depth_stencil_format, IsStencil(depth_stencil) ? depth_stencil : vk::Format::eUndefined}; pipeline_info.pNext = &rendering_info; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index dc18f0e67..a2ecf26f8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -69,7 +69,7 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) { VKBuffer::Info texel_buffer_info = { .size = TEXTURE_BUFFER_SIZE, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal, - .usage = vk::BufferUsageFlagBits::eStorageTexelBuffer | + .usage = vk::BufferUsageFlagBits::eUniformTexelBuffer | vk::BufferUsageFlagBits::eTransferDst, }; @@ -116,13 +116,18 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) { index_buffer.Create(index_info); // Set clear texture color - state.SetPlaceholderColor(0, 0, 0, 255); + state.SetPlaceholderColor(255, 0, 0, 255); SyncEntireState(); } RasterizerVulkan::~RasterizerVulkan() = default; +void RasterizerVulkan::LoadDiskResources(const std::atomic_bool& stop_loading, + const VideoCore::DiskResourceLoadCallback& callback) { + +} + void RasterizerVulkan::SyncEntireState() { // Sync fixed function Vulkan state SyncClipEnabled(); @@ -394,8 +399,14 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { } state.EndRendering(); + color_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal); + depth_surface->texture.Transition(cmdbuffer, vk::ImageLayout::eShaderReadOnlyOptimal); + g_vk_task_scheduler->Submit(); + auto gpu_tick = g_vk_task_scheduler->GetGPUTick(); + auto cpu_tick = g_vk_task_scheduler->GetCPUTick(); + return true; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 770977b42..3504ab985 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -117,7 +117,7 @@ public: ~RasterizerVulkan() override; void LoadDiskResources(const std::atomic_bool& stop_loading, - const VideoCore::DiskResourceLoadCallback& callback) override {} + const VideoCore::DiskResourceLoadCallback& callback) override; void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1, const Pica::Shader::OutputVertex& v2) override; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp index 4f14a1bc6..bb0689fef 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -428,6 +429,7 @@ void RasterizerCacheVulkan::CopySurface(const Surface& src_surface, const Surfac MICROPROFILE_DEFINE(Vulkan_SurfaceLoad, "Vulkan", "Surface Load", MP_RGB(128, 192, 64)); void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) { ASSERT(type != SurfaceType::Fill); + const bool need_swap = (pixel_format == PixelFormat::RGBA8 || pixel_format == PixelFormat::RGB8); const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr); if (texture_src_data == nullptr) @@ -451,8 +453,27 @@ void CachedSurface::LoadGPUBuffer(PAddr load_start, PAddr load_end) { if (!is_tiled) { ASSERT(type == SurfaceType::Color); - std::memcpy(&vk_buffer[start_offset], texture_src_data + start_offset, + if (need_swap) { + // TODO(liushuyu): check if the byteswap here is 100% correct + // cannot fully test this + if (pixel_format == PixelFormat::RGBA8) { + for (std::size_t i = start_offset; i < load_end - addr; i += 4) { + vk_buffer[i] = texture_src_data[i + 3]; + vk_buffer[i + 1] = texture_src_data[i + 2]; + vk_buffer[i + 2] = texture_src_data[i + 1]; + vk_buffer[i + 3] = texture_src_data[i]; + } + } else if (pixel_format == PixelFormat::RGB8) { + for (std::size_t i = start_offset; i < load_end - addr; i += 3) { + vk_buffer[i] = texture_src_data[i + 2]; + vk_buffer[i + 1] = texture_src_data[i + 1]; + vk_buffer[i + 2] = texture_src_data[i]; + } + } + } else { + std::memcpy(&vk_buffer[start_offset], texture_src_data + start_offset, load_end - load_start); + } } else { if (type == SurfaceType::Texture) { Pica::Texture::TextureInfo tex_info{}; diff --git a/src/video_core/renderer_vulkan/vk_shader_gen.cpp b/src/video_core/renderer_vulkan/vk_shader_gen.cpp index 0a31c90b0..fbf7334cf 100644 --- a/src/video_core/renderer_vulkan/vk_shader_gen.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_gen.cpp @@ -1677,7 +1677,7 @@ vk::ShaderModule CompileShader(const std::string& source, vk::ShaderStageFlagBit shaderc::Compiler compiler; shaderc::CompileOptions options; options.SetOptimizationLevel(shaderc_optimization_level_performance); - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1); options.SetWarningsAsErrors(); options.SetSourceLanguage(shaderc_source_language_glsl); diff --git a/src/video_core/renderer_vulkan/vk_state.cpp b/src/video_core/renderer_vulkan/vk_state.cpp index 5f321adaf..c38ddc4a9 100644 --- a/src/video_core/renderer_vulkan/vk_state.cpp +++ b/src/video_core/renderer_vulkan/vk_state.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include "video_core/renderer_vulkan/vk_state.h" #include "video_core/renderer_vulkan/renderer_vulkan.h" @@ -13,6 +14,17 @@ namespace Vulkan { std::unique_ptr s_vulkan_state{}; +auto IsStencil = [](vk::Format format) -> bool { + switch (format) { + case vk::Format::eD16UnormS8Uint: + case vk::Format::eD24UnormS8Uint: + case vk::Format::eD32SfloatS8Uint: + return true; + default: + return false; + }; +}; + void DescriptorUpdater::Update() { assert(update_count > 0); @@ -151,7 +163,7 @@ void VulkanState::SetTexture(u32 binding, const VKTexture& image) { void VulkanState::SetTexelBuffer(u32 binding, u32 offset, u32 size, const VKBuffer& buffer, u32 view_index) { auto& set = descriptor_sets[2]; updater.PushBufferUpdate(set, binding, - vk::DescriptorType::eStorageTexelBuffer, + vk::DescriptorType::eUniformTexelBuffer, offset, size, buffer.GetBuffer(), buffer.GetView(view_index)); descriptors_dirty = true; @@ -177,18 +189,24 @@ void VulkanState::UnbindTexture(const VKTexture& image) { for (int i = 0; i < 4; i++) { if (render_views[i] == image.GetView()) { render_views[i] = placeholder.GetView(); + updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], i, + render_sampler, render_views[i]); descriptors_dirty = true; } } if (present_view == image.GetView()) { present_view = placeholder.GetView(); + updater.PushCombinedImageSamplerUpdate(descriptor_sets[3], 0, + render_sampler, present_view); descriptors_dirty = true; } } void VulkanState::UnbindTexture(u32 unit) { render_views[unit] = placeholder.GetView(); + updater.PushCombinedImageSamplerUpdate(descriptor_sets[1], unit, + render_sampler, render_views[unit]); descriptors_dirty = true; } @@ -227,13 +245,17 @@ void VulkanState::BeginRendering(OptRef color, OptRef dept depth_load_op, depth_store_op, depth_clear }; - infos[2] = vk::RenderingAttachmentInfo{ - image.GetView(), image.GetLayout(), {}, {}, {}, - stencil_load_op, stencil_store_op, depth_clear - }; - render_info.pDepthAttachment = &infos[1]; - render_info.pStencilAttachment = &infos[2]; + + + if (IsStencil(image.GetFormat())) { + infos[2] = vk::RenderingAttachmentInfo{ + image.GetView(), image.GetLayout(), {}, {}, {}, + stencil_load_op, stencil_store_op, depth_clear + }; + + render_info.pStencilAttachment = &infos[2]; + } } if (update_pipeline_formats) { @@ -363,25 +385,26 @@ void VulkanState::InitDescriptorSets() { auto sets = device.allocateDescriptorSets(allocate_info); // Update them if the previous sets are valid - auto result = std::ranges::find_if(descriptor_sets, [](vk::DescriptorSet set) { return bool(set); }); - if (result != descriptor_sets.end()) { - std::array copies{{ - {descriptor_sets[0], 0, 0, sets[0], 0, 0}, // shader_data - {descriptor_sets[0], 1, 0, sets[0], 1, 0}, // pica_uniforms - {descriptor_sets[1], 0, 0, sets[1], 0, 0}, // tex0 - {descriptor_sets[1], 1, 0, sets[1], 1, 0}, // tex1 - {descriptor_sets[1], 2, 0, sets[1], 2, 0}, // tex2 - {descriptor_sets[1], 3, 0, sets[1], 3, 0}, // tex_cube - {descriptor_sets[2], 0, 0, sets[2], 0, 0}, // texture_buffer_lut_lf - {descriptor_sets[2], 1, 0, sets[2], 1, 0}, // texture_buffer_lut_rg - {descriptor_sets[2], 2, 0, sets[2], 2, 0}, // texture_buffer_lut_rgba - {descriptor_sets[3], 0, 0, sets[3], 0, 0} - }}; + u32 copy_count = 0; + std::array copies; - device.updateDescriptorSets({}, copies); + // Copy only valid descriptors + std::array binding_count{2, 4, 3, 1}; + for (int i = 0; i < descriptor_sets.size(); i++) { + if (descriptor_sets[i]) { + for (u32 binding = 0; binding < binding_count[i]; binding++) { + copies[copy_count++] = {descriptor_sets[i], binding, 0, sets[i], binding, 0, 1}; + } + } } - std::copy_n(sets.begin(), 4, descriptor_sets.begin()); + if (copy_count < 10) { + // Some descriptors weren't copied and thus need manual updating + descriptors_dirty = true; + } + + device.updateDescriptorSets(0, nullptr, copy_count, copies.data()); + std::copy_n(sets.begin(), descriptor_sets.size(), descriptor_sets.begin()); } void VulkanState::ApplyRenderState(const Pica::Regs& regs) { @@ -533,9 +556,9 @@ void VulkanState::BuildDescriptorLayouts() { {3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment}, // tex_cube }}; std::array lut_set{{ - {0, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf - {1, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg - {2, vk::DescriptorType::eStorageTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba + {0, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_lf + {1, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment}, // texture_buffer_lut_rg + {2, vk::DescriptorType::eUniformTexelBuffer, 1, vk::ShaderStageFlagBits::eFragment} // texture_buffer_lut_rgba }}; std::array present_set{{ {0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment} @@ -579,7 +602,7 @@ void VulkanState::ConfigureRenderPipeline() { // Enable every required dynamic state std::array dynamic_states{ - vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth, + vk::DynamicState::eDepthCompareOp, vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilOp, vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, @@ -614,7 +637,7 @@ void VulkanState::ConfigurePresentPipeline() { present_pipeline_builder.SetPrimitiveTopology(vk::PrimitiveTopology::eTriangleStrip); present_pipeline_builder.SetLineWidth(1.0f); present_pipeline_builder.SetNoCullRasterizationState(); - present_pipeline_builder.SetRenderingFormats(swapchain->GetCurrentImage().GetFormat()); + present_pipeline_builder.SetRenderingFormats(vk::Format::eB8G8R8A8Unorm); // Set depth, stencil tests and blending present_pipeline_builder.SetNoDepthTestState(); @@ -623,7 +646,6 @@ void VulkanState::ConfigurePresentPipeline() { // Enable every required dynamic state std::array dynamic_states{ - vk::DynamicState::eLineWidth, vk::DynamicState::eViewport, vk::DynamicState::eScissor, }; diff --git a/src/video_core/renderer_vulkan/vk_state.h b/src/video_core/renderer_vulkan/vk_state.h index fdf84b100..aed22cdac 100644 --- a/src/video_core/renderer_vulkan/vk_state.h +++ b/src/video_core/renderer_vulkan/vk_state.h @@ -125,8 +125,7 @@ private: private: // Render targets std::shared_ptr swapchain; - bool rendering{}; - VKTexture* color_render_target{}, *depth_render_target{}; + bool rendering{false}; vk::ImageView present_view; std::array render_views; DrawInfo present_data; diff --git a/src/video_core/renderer_vulkan/vk_texture.cpp b/src/video_core/renderer_vulkan/vk_texture.cpp index 29a31c6ef..1060dd06d 100644 --- a/src/video_core/renderer_vulkan/vk_texture.cpp +++ b/src/video_core/renderer_vulkan/vk_texture.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include #include "common/assert.h" #include "common/logging/log.h" #include "video_core/renderer_vulkan/vk_texture.h" @@ -26,6 +28,7 @@ static int BytesPerPixel(vk::Format format) { case vk::Format::eR5G6B5UnormPack16: case vk::Format::eR5G5B5A1UnormPack16: case vk::Format::eR4G4B4A4UnormPack16: + case vk::Format::eD16Unorm: return 2; default: UNREACHABLE(); @@ -247,7 +250,9 @@ void VKTexture::OverrideImageLayout(vk::ImageLayout new_layout) { } void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span pixels) { - auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(pixels.size_bytes()); + u32 request_size = is_rgb ? (pixels.size() / 3) * 4 : + (is_d24s8 ? (pixels.size() / 4) * 5 : pixels.size()); + auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(request_size); if (!buffer) { LOG_ERROR(Render_Vulkan, "Cannot upload pixels without staging buffer!"); } @@ -271,8 +276,6 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::memcpy(buffer, pixels.data(), pixels.size()); } - std::memcpy(buffer, pixels.data(), pixels.size()); - vk::BufferImageCopy copy_region{ offset, row_length, region.extent.height, {aspect, level, layer, 1}, @@ -342,33 +345,44 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region Transition(cmdbuffer, old_layout); } +template +std::span SpanCast(std::span span) { + return std::span(reinterpret_cast(span.data()), span.size_bytes() / sizeof(Out)); +} + std::vector VKTexture::RGBToRGBA(std::span data) { ASSERT(data.size() % 3 == 0); u32 new_size = (data.size() / 3) * 4; - std::vector rgba(new_size, 255); + std::vector rgba(new_size); u32 dst_pos = 0; for (u32 i = 0; i < data.size(); i += 3) { std::memcpy(rgba.data() + dst_pos, data.data() + i, 3); + rgba[dst_pos + 3] = 255u; dst_pos += 4; } return rgba; } -std::vector VKTexture::D24S8ToD32S8(std::span data) { +std::vector VKTexture::D24S8ToD32S8(std::span data) { ASSERT(data.size() % 4 == 0); - u32 new_size = (data.size() / 4) * 8; - std::vector d32s8(new_size, 0); + std::vector d32s8; + std::span d24s8 = SpanCast(data); - u32 dst_pos = 0; - for (u32 i = 0; i < data.size(); i += 4) { - std::memcpy(d32s8.data() + dst_pos, data.data() + i, 3); - d32s8[dst_pos + 4] = data[i + 3]; - dst_pos += 8; - } + d32s8.reserve(data.size() * 2); + std::ranges::transform(d24s8, std::back_inserter(d32s8), [](u32 comp) -> u64 { + // Convert normalized 24bit depth component to floating point + float fdepth = static_cast(comp & 0xFFFFFF) / 0xFFFFFF; + u64 result = static_cast(comp) << 8; + + // Use std::memcpy to avoid the unsafe casting required to preserve the floating + // point bits + std::memcpy(&result, &fdepth, 4); + return result; + }); return d32s8; } @@ -388,18 +402,23 @@ std::vector VKTexture::RGBAToRGB(std::span data) { return rgb; } -std::vector VKTexture::D32S8ToD24S8(std::span data) { +std::vector VKTexture::D32S8ToD24S8(std::span data) { ASSERT(data.size() % 8 == 0); - u32 new_size = (data.size() / 8) * 4; - std::vector d24s8(new_size); + std::vector d24s8; + std::span d32s8 = SpanCast(data); - u32 dst_pos = 0; - for (u32 i = 0; i < data.size(); i += 5) { - std::memcpy(d24s8.data() + dst_pos, data.data() + i, 3); - d24s8[dst_pos + 3] = data[i + 4]; - dst_pos += 4; - } + d24s8.reserve(data.size() / 2); + std::ranges::transform(d32s8, std::back_inserter(d24s8), [](u64 comp) -> u32 { + // Convert floating point to 24bit normalized depth + float fdepth = 0.f; + u32 depth = comp & 0xFFFFFFFF; + std::memcpy(&fdepth, &depth, 4); + + u32 stencil = (comp >> 32) & 0xFF; + u64 result = static_cast(fdepth * 0xFFFFFF) | (stencil << 24); + return result; + }); return d24s8; } diff --git a/src/video_core/renderer_vulkan/vk_texture.h b/src/video_core/renderer_vulkan/vk_texture.h index a367e9ae3..9a7ceb2b7 100644 --- a/src/video_core/renderer_vulkan/vk_texture.h +++ b/src/video_core/renderer_vulkan/vk_texture.h @@ -62,10 +62,10 @@ public: private: std::vector RGBToRGBA(std::span data); - std::vector D24S8ToD32S8(std::span data); + std::vector D24S8ToD32S8(std::span data); std::vector RGBAToRGB(std::span data); - std::vector D32S8ToD24S8(std::span data); + std::vector D32S8ToD24S8(std::span data); private: VKTexture::Info info{};