diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 3bf96323d..8b195501a 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -48,14 +48,14 @@ 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);*/ if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) { // Usually the loading screen is hidden after the first frame is drawn. In this case @@ -488,9 +488,6 @@ bool GRenderWindow::InitRenderTarget() { break; } - // Update the Window System information with the new render target - window_info = GetWindowSystemInfo(child_widget->windowHandle()); - child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight); layout()->addWidget(child_widget); // Reset minimum required size to avoid resizing issues on the main window after restarting. @@ -498,6 +495,9 @@ bool GRenderWindow::InitRenderTarget() { resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight); + // Update the Window System information with the new render target + window_info = GetWindowSystemInfo(child_widget->windowHandle()); + OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); OnFramebufferSizeChanged(); BackupGeometry(); @@ -611,4 +611,4 @@ std::unique_ptr GRenderWindow::CreateSharedContext() } return std::make_unique(); -} \ No newline at end of file +} diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ceaa6474d..0f06a6ee1 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -713,7 +713,7 @@ VideoCore::ResultStatus RendererVulkan::Init() { auto surface = CreateSurface(instance, render_window); g_vk_instace = std::make_unique(); g_vk_task_scheduler = std::make_unique(); - g_vk_instace->Create(instance, physical_devices[0], surface, true); + g_vk_instace->Create(instance, physical_devices[1], surface, true); g_vk_task_scheduler->Create(); auto& layout = render_window.GetFramebufferLayout(); diff --git a/src/video_core/renderer_vulkan/vk_buffer.cpp b/src/video_core/renderer_vulkan/vk_buffer.cpp index ce7287aa2..c1ac78822 100644 --- a/src/video_core/renderer_vulkan/vk_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer.cpp @@ -138,24 +138,26 @@ std::tuple StreamBuffer::Map(u32 size, u32 alignment) { void StreamBuffer::Commit(u32 size, vk::AccessFlags access_to_block, vk::PipelineStageFlags stage_to_block) { - mapped_chunk.size = size; + if (size > 0) { + mapped_chunk.size = size; - auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer(); - auto& staging = g_vk_task_scheduler->GetStaging(); - cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk); + auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer(); + auto& staging = g_vk_task_scheduler->GetStaging(); + cmdbuffer.copyBuffer(staging.GetBuffer(), buffer, mapped_chunk); - vk::BufferMemoryBarrier barrier{ - vk::AccessFlagBits::eTransferWrite, access_to_block, - VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - buffer, mapped_chunk.srcOffset, mapped_chunk.size - }; + vk::BufferMemoryBarrier barrier{ + vk::AccessFlagBits::eTransferWrite, access_to_block, + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, + buffer, mapped_chunk.srcOffset, mapped_chunk.size + }; - // Add a pipeline barrier for the region modified - cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block, - vk::DependencyFlagBits::eByRegion, - 0, nullptr, 1, &barrier, 0, nullptr); + // Add a pipeline barrier for the region modified + cmdbuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, stage_to_block, + vk::DependencyFlagBits::eByRegion, + 0, nullptr, 1, &barrier, 0, nullptr); - buffer_pos += size; + buffer_pos += size; + } } } diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index e503991cb..2c76386c2 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -7,6 +7,10 @@ #include "common/logging/log.h" #include "video_core/renderer_vulkan/vk_instance.h" +#if defined(VK_EXT_color_write_enable) +PFN_vkCmdSetColorWriteEnableEXT ptr_vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ + namespace Vulkan { std::unique_ptr g_vk_instace; @@ -96,6 +100,10 @@ bool VKInstance::CreateDevice(vk::SurfaceKHR surface, bool validation_enabled) { // Create logical device device = physical_device.createDeviceUnique(device_info); +#if defined(VK_EXT_color_write_enable) + ptr_vkCmdSetColorWriteEnableEXT = reinterpret_cast(device->getProcAddr("vkCmdSetColorWriteEnableEXT")); +#endif /* defined(VK_EXT_color_write_enable) */ + // Grab the graphics and present queues. graphics_queue = device->getQueue(graphics_queue_family_index, 0); present_queue = device->getQueue(present_queue_family_index, 0); @@ -131,18 +139,19 @@ bool VKInstance::FindFeatures() { dynamic_state_features.extendedDynamicState = true; dynamic_state2_features.extendedDynamicState2 = true; dynamic_state2_features.extendedDynamicState2LogicOp = true; + color_write_features.colorWriteEnable = true; // Include features in device creation vk12_features.pNext = &vk13_features; vk13_features.pNext = &dynamic_state_features; dynamic_state_features.pNext = &dynamic_state2_features; + dynamic_state2_features.pNext = &color_write_features; features = vk::PhysicalDeviceFeatures2{vk_features, &vk12_features}; return true; } -bool VKInstance::FindExtensions() -{ +bool VKInstance::FindExtensions() { auto available = physical_device.enumerateDeviceExtensionProperties(); if (available.empty()) { LOG_CRITICAL(Render_Vulkan, "No extensions supported by device."); @@ -177,7 +186,8 @@ bool VKInstance::FindExtensions() if (!AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true) || !AddExtension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, true) || !AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, true) || - !AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, true)) { + !AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, true) || + !AddExtension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME, true)) { return false; } @@ -185,3 +195,7 @@ bool VKInstance::FindExtensions() } } // namespace Vulkan + +void vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32* pColorWriteEnables) { + ptr_vkCmdSetColorWriteEnableEXT(commandBuffer, attachmentCount, pColorWriteEnables); +} diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 7b2d8c5a9..6e726fec1 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -61,8 +61,13 @@ public: vk::PhysicalDeviceVulkan12Features vk12_features{}; vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state_features{}; vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT dynamic_state2_features{}; + vk::PhysicalDeviceColorWriteEnableFeaturesEXT color_write_features{}; }; extern std::unique_ptr g_vk_instace; } // namespace Vulkan + +#if defined(VK_EXT_color_write_enable) +extern PFN_vkCmdSetColorWriteEnableEXT ptr_vkCmdSetColorWriteEnableEXT; +#endif /* defined(VK_EXT_color_write_enable) */ diff --git a/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp b/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp index 043486656..01cde1f5e 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_builder.cpp @@ -224,7 +224,6 @@ void PipelineBuilder::SetDynamicStates(const std::span states) // Copy the state data std::copy(states.begin(), states.end(), dynamic_states.begin()); dynamic_info.dynamicStateCount = states.size(); - dynamic_info.pDynamicStates = dynamic_states.data(); pipeline_info.pDynamicState = &dynamic_info; return; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_builder.h b/src/video_core/renderer_vulkan/vk_pipeline_builder.h index 997971e66..1fd9a8660 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_builder.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_builder.h @@ -73,7 +73,7 @@ public: void SetRenderingFormats(vk::Format color, vk::Format depth_stencil = vk::Format::eUndefined); private: - static constexpr u32 MAX_DYNAMIC_STATES = 14; + static constexpr u32 MAX_DYNAMIC_STATES = 20; static constexpr u32 MAX_SHADER_STAGES = 3; static constexpr u32 MAX_VERTEX_BUFFERS = 8; static constexpr u32 MAX_VERTEX_ATTRIBUTES = 16; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 074b97cb9..dc18f0e67 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -69,7 +69,8 @@ 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::eStorageTexelBuffer | + vk::BufferUsageFlagBits::eTransferDst, }; texel_buffer_info.view_formats[0] = vk::Format::eR32G32Sfloat; @@ -82,7 +83,8 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) { VKBuffer::Info uniform_info = { .size = UNIFORM_BUFFER_SIZE, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal, - .usage = vk::BufferUsageFlagBits::eUniformBuffer + .usage = vk::BufferUsageFlagBits::eUniformBuffer | + vk::BufferUsageFlagBits::eTransferDst }; uniform_buffer.Create(uniform_info); @@ -99,13 +101,15 @@ RasterizerVulkan::RasterizerVulkan(Frontend::EmuWindow& emu_window) { VKBuffer::Info vertex_info = { .size = VERTEX_BUFFER_SIZE, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal, - .usage = vk::BufferUsageFlagBits::eVertexBuffer + .usage = vk::BufferUsageFlagBits::eVertexBuffer | + vk::BufferUsageFlagBits::eTransferDst }; VKBuffer::Info index_info = { .size = INDEX_BUFFER_SIZE, .properties = vk::MemoryPropertyFlagBits::eDeviceLocal, - .usage = vk::BufferUsageFlagBits::eIndexBuffer + .usage = vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eTransferDst }; vertex_buffer.Create(vertex_info); @@ -389,6 +393,9 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) { depth_surface); } + state.EndRendering(); + g_vk_task_scheduler->Submit(); + return true; } @@ -1240,11 +1247,18 @@ void RasterizerVulkan::SyncColorWriteMask() { return regs.framebuffer.framebuffer.allow_color_write != 0 && value != 0; }; + vk::ColorComponentFlags mask; + if (WriteEnabled(regs.framebuffer.output_merger.red_enable)) + mask |= vk::ColorComponentFlagBits::eR; + if (WriteEnabled(regs.framebuffer.output_merger.green_enable)) + mask |= vk::ColorComponentFlagBits::eG; + if (WriteEnabled(regs.framebuffer.output_merger.blue_enable)) + mask |= vk::ColorComponentFlagBits::eB; + if (WriteEnabled(regs.framebuffer.output_merger.alpha_enable)) + mask |= vk::ColorComponentFlagBits::eA; + auto& state = VulkanState::Get(); - state.SetColorMask(WriteEnabled(regs.framebuffer.output_merger.red_enable), - WriteEnabled(regs.framebuffer.output_merger.green_enable), - WriteEnabled(regs.framebuffer.output_merger.blue_enable), - WriteEnabled(regs.framebuffer.output_merger.alpha_enable)); + state.SetColorMask(mask); } void RasterizerVulkan::SyncStencilWriteMask() { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp index 366a2e0f1..4f14a1bc6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer_cache.cpp @@ -294,7 +294,8 @@ static vk::Rect2D FromRect(Common::Rectangle rect) { } // Allocate an uninitialized texture of appropriate size and format for the surface -VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 width, u32 height) { +VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(SurfaceType type, vk::Format format, + u32 width, u32 height) { // First check if the texture can be recycled auto recycled_tex = host_texture_recycler.find({format, width, height}); if (recycled_tex != host_texture_recycler.end()) { @@ -303,6 +304,28 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w return texture; } + auto GetUsage = [](SurfaceType type) { + auto usage = vk::ImageUsageFlagBits::eSampled | + vk::ImageUsageFlagBits::eTransferDst | + vk::ImageUsageFlagBits::eTransferSrc; + + switch (type) { + case SurfaceType::Color: + case SurfaceType::Fill: + case SurfaceType::Texture: + usage |= vk::ImageUsageFlagBits::eColorAttachment; + break; + case SurfaceType::Depth: + case SurfaceType::DepthStencil: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + break; + default: + break; + } + + return usage; + }; + // Otherwise create a brand new texture u32 levels = std::log2(std::max(width, height)) + 1; VKTexture::Info texture_info = { @@ -311,8 +334,7 @@ VKTexture RasterizerCacheVulkan::AllocateSurfaceTexture(vk::Format format, u32 w .format = format, .type = vk::ImageType::e2D, .view_type = vk::ImageViewType::e2D, - .usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst | - vk::ImageUsageFlagBits::eTransferSrc, + .usage = GetUsage(type), .levels = levels }; @@ -1330,7 +1352,7 @@ Surface RasterizerCacheVulkan::CreateSurface(const SurfaceParams& params) { static_cast(*surface) = params; surface->invalid_regions.insert(surface->GetInterval()); - surface->texture = AllocateSurfaceTexture(GetFormatTuple(surface->pixel_format), + surface->texture = AllocateSurfaceTexture(params.type, GetFormatTuple(surface->pixel_format), surface->GetScaledWidth(), surface->GetScaledHeight()); return surface; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer_cache.h b/src/video_core/renderer_vulkan/vk_rasterizer_cache.h index 5804d6ac1..a109374e8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer_cache.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer_cache.h @@ -342,7 +342,8 @@ private: std::recursive_mutex mutex; public: - VKTexture AllocateSurfaceTexture(vk::Format format, u32 width, u32 height); + VKTexture AllocateSurfaceTexture(SurfaceParams::SurfaceType type, vk::Format format, + u32 width, u32 height); std::unique_ptr format_reinterpreter; }; diff --git a/src/video_core/renderer_vulkan/vk_state.cpp b/src/video_core/renderer_vulkan/vk_state.cpp index 10138c645..5f321adaf 100644 --- a/src/video_core/renderer_vulkan/vk_state.cpp +++ b/src/video_core/renderer_vulkan/vk_state.cpp @@ -284,8 +284,7 @@ void VulkanState::SetFrontFace(vk::FrontFace face) { } } -void VulkanState::SetColorMask(bool red, bool green, bool blue, bool alpha) { - auto mask = static_cast(red | (green << 1) | (blue << 2) | (alpha << 3)); +void VulkanState::SetColorMask(vk::ColorComponentFlags mask) { render_pipeline_key.blend_config.colorWriteMask = mask; } @@ -412,7 +411,7 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) { auto code = GenerateFragmentShader(render_pipeline_key.fragment_config); auto module = CompileShader(code, vk::ShaderStageFlagBits::eFragment); render_fragment_shaders.emplace(render_pipeline_key.fragment_config, vk::UniqueShaderModule{module}); - render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, shader->second.get()); + render_pipeline_builder.SetShaderStage(vk::ShaderStageFlagBits::eFragment, module); } // Update pipeline builder @@ -432,6 +431,9 @@ void VulkanState::ApplyRenderState(const Pica::Regs& regs) { auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); cmdbuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + // Force set all dynamic state for new pipeline + dirty_flags.set(); + ApplyCommonState(true); // Bind render descriptor sets @@ -578,12 +580,13 @@ void VulkanState::ConfigureRenderPipeline() { // Enable every required dynamic state std::array dynamic_states{ vk::DynamicState::eDepthCompareOp, vk::DynamicState::eLineWidth, - vk::DynamicState::eDepthTestEnable, vk::DynamicState::eColorWriteEnableEXT, - vk::DynamicState::eStencilTestEnable, vk::DynamicState::eStencilOp, + vk::DynamicState::eDepthTestEnable, vk::DynamicState::eStencilTestEnable, + vk::DynamicState::eStencilOp, vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask, + vk::DynamicState::eStencilReference, vk::DynamicState::eDepthWriteEnable, vk::DynamicState::eCullMode, vk::DynamicState::eBlendConstants, vk::DynamicState::eViewport, vk::DynamicState::eScissor, - vk::DynamicState::eLogicOpEXT, vk::DynamicState::eFrontFace + vk::DynamicState::eFrontFace }; render_pipeline_builder.SetDynamicStates(dynamic_states); diff --git a/src/video_core/renderer_vulkan/vk_state.h b/src/video_core/renderer_vulkan/vk_state.h index 7eaec5d12..fdf84b100 100644 --- a/src/video_core/renderer_vulkan/vk_state.h +++ b/src/video_core/renderer_vulkan/vk_state.h @@ -83,7 +83,7 @@ public: vk::CompareOp compare, u32 ref); void SetDepthWrite(bool enable); void SetDepthTest(bool enable, vk::CompareOp compare); - void SetColorMask(bool red, bool green, bool blue, bool alpha); + void SetColorMask(vk::ColorComponentFlags mask); void SetBlendEnable(bool enable); void SetBlendCostants(float red, float green, float blue, float alpha); void SetBlendOp(vk::BlendOp rgb_op, vk::BlendOp alpha_op, vk::BlendFactor src_color, vk::BlendFactor dst_color, @@ -162,7 +162,7 @@ private: ColorWrite, CullMode, BlendConstants, - FrontFace + FrontFace, }; std::bitset<16> dirty_flags; diff --git a/src/video_core/renderer_vulkan/vk_texture.cpp b/src/video_core/renderer_vulkan/vk_texture.cpp index 09e34f701..29a31c6ef 100644 --- a/src/video_core/renderer_vulkan/vk_texture.cpp +++ b/src/video_core/renderer_vulkan/vk_texture.cpp @@ -12,6 +12,9 @@ namespace Vulkan { static int BytesPerPixel(vk::Format format) { switch (format) { + case vk::Format::eD32SfloatS8Uint: + return 5; + case vk::Format::eD32Sfloat: case vk::Format::eB8G8R8A8Unorm: case vk::Format::eR8G8B8A8Uint: case vk::Format::eR8G8B8A8Srgb: @@ -63,6 +66,12 @@ void VKTexture::Create(const Info& create_info) { info.format = vk::Format::eR8G8B8A8Srgb; } + is_d24s8 = false; + if (info.format == vk::Format::eD24UnormS8Uint) { + is_d24s8 = true; + info.format = vk::Format::eD32SfloatS8Uint; + } + // Create the texture image_size = info.width * info.height * BytesPerPixel(info.format); aspect = GetImageAspect(info.format); @@ -244,7 +253,24 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, } // Copy pixels to staging buffer - auto cmdbuffer = g_vk_task_scheduler->GetUploadCommandBuffer(); + auto& state = VulkanState::Get(); + state.EndRendering(); + + auto cmdbuffer = g_vk_task_scheduler->GetRenderCommandBuffer(); + + // Automatically convert RGB to RGBA + if (is_rgb) { + auto data = RGBToRGBA(pixels); + std::memcpy(buffer, data.data(), data.size()); + } + else if (is_d24s8) { + auto data = D24S8ToD32S8(pixels); + std::memcpy(buffer, data.data(), data.size()); + } + else { + std::memcpy(buffer, pixels.data(), pixels.size()); + } + std::memcpy(buffer, pixels.data(), pixels.size()); vk::BufferImageCopy copy_region{ @@ -266,15 +292,13 @@ void VKTexture::Upload(u32 level, u32 layer, u32 row_length, vk::Rect2D region, } void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region, std::span memory) { - u32 request_size = is_rgb ? (memory.size() / 3) * 4 : memory.size(); + u32 request_size = is_rgb ? (memory.size() / 3) * 4 : + (is_d24s8 ? (memory.size() / 4) * 5 : memory.size()); auto [buffer, offset] = g_vk_task_scheduler->RequestStaging(request_size); if (!buffer) { LOG_ERROR(Render_Vulkan, "Cannot download texture without staging buffer!"); } - // Downloads can happen after the image has been rendered to or changed by blitting - // so we must perform it in the render command buffer. However there is no guarantee - // of the rendering context so terminate the current renderpass to be sure auto& state = VulkanState::Get(); state.EndRendering(); @@ -290,7 +314,11 @@ void VKTexture::Download(u32 level, u32 layer, u32 row_length, vk::Rect2D region // Automatically convert RGB to RGBA if (is_rgb) { - auto data = RGBToRGBA(memory); + auto data = RGBAToRGB(memory); + std::memcpy(buffer, data.data(), data.size()); + } + else if (is_d24s8) { + auto data = D32S8ToD24S8(memory); std::memcpy(buffer, data.data(), data.size()); } else { @@ -318,16 +346,62 @@ std::vector VKTexture::RGBToRGBA(std::span data) { ASSERT(data.size() % 3 == 0); u32 new_size = (data.size() / 3) * 4; - std::vector rgba(new_size); + std::vector rgba(new_size, 255); - u32 dst_pos{0}; - for (int i = 0; i < data.size(); i += 3) { + 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) { + ASSERT(data.size() % 4 == 0); + + u32 new_size = (data.size() / 4) * 8; + std::vector d32s8(new_size, 0); + + 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; + } + + return d32s8; +} + +std::vector VKTexture::RGBAToRGB(std::span data) { + ASSERT(data.size() % 4 == 0); + + u32 new_size = (data.size() / 4) * 3; + std::vector rgb(new_size); + + u32 dst_pos = 0; + for (u32 i = 0; i < data.size(); i += 4) { + std::memcpy(rgb.data() + dst_pos, data.data() + i, 3); + dst_pos += 3; + } + + return rgb; +} + +std::vector VKTexture::D32S8ToD24S8(std::span data) { + ASSERT(data.size() % 8 == 0); + + u32 new_size = (data.size() / 8) * 4; + std::vector d24s8(new_size); + + 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; + } + + return d24s8; +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture.h b/src/video_core/renderer_vulkan/vk_texture.h index 60698c431..a367e9ae3 100644 --- a/src/video_core/renderer_vulkan/vk_texture.h +++ b/src/video_core/renderer_vulkan/vk_texture.h @@ -62,6 +62,10 @@ public: private: std::vector RGBToRGBA(std::span data); + std::vector D24S8ToD32S8(std::span data); + + std::vector RGBAToRGB(std::span data); + std::vector D32S8ToD24S8(std::span data); private: VKTexture::Info info{}; @@ -72,7 +76,7 @@ private: vk::DeviceMemory memory; u32 image_size{}; bool adopted{false}; - bool is_rgb{false}; + bool is_rgb{false}, is_d24s8{false}; }; } // namespace Vulkan