From 365df2a3ac67617e4a0771f3dadc61c1f0109606 Mon Sep 17 00:00:00 2001 From: psucien Date: Thu, 30 May 2024 16:27:39 +0200 Subject: [PATCH] video_core: renderer_vulkan: write mask fallback --- src/video_core/amdgpu/liverpool.h | 4 ++++ .../renderer_vulkan/vk_graphics_pipeline.cpp | 7 +++++-- .../renderer_vulkan/vk_graphics_pipeline.h | 5 +++++ .../renderer_vulkan/vk_instance.cpp | 7 +++++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 20 ++++++++++++++----- .../renderer_vulkan/vk_rasterizer.cpp | 19 ++++++++---------- .../renderer_vulkan/vk_rasterizer.h | 2 +- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 442a66f2..9c2b4bcd 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -416,6 +416,10 @@ struct Liverpool { BitField<20, 4, u32> output5_mask; BitField<24, 4, u32> output6_mask; BitField<28, 4, u32> output7_mask; + + [[nodiscard]] u8 GetMask(int buf_id) const { + return (raw >> (buf_id * 4)) & 0xffu; + } }; struct IndexBufferBase { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 31255a63..655dc692 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -185,8 +185,11 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul .srcAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.alpha_src_factor), .dstAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.color_dst_factor), .alphaBlendOp = LiverpoolToVK::BlendOp(control.alpha_func), - .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | - vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + .colorWriteMask = + instance.IsColorWriteEnableSupported() + ? vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA + : key.write_masks[i], }; } diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index c7e773ad..17ed225b 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -39,6 +39,7 @@ struct GraphicsPipelineKey { Liverpool::PolygonMode polygon_mode; Liverpool::CullMode cull_mode; std::array blend_controls; + std::array write_masks; bool operator==(const GraphicsPipelineKey& key) const noexcept { return std::memcmp(this, &key, sizeof(GraphicsPipelineKey)) == 0; @@ -66,6 +67,10 @@ public: return key.stage_hashes[0] == EmbeddedVsHash; } + [[nodiscard]] auto GetWriteMasks() const { + return key.write_masks; + } + private: void BuildDescSetLayout(); diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 578a8654..3cfe8c79 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -151,10 +151,11 @@ bool Instance::CreateDevice() { tooling_info = add_extension(VK_EXT_TOOLING_INFO_EXTENSION_NAME); custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); index_type_uint8 = add_extension(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME); - color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME); - add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); + // The next two extensions are required to be available together in order to support write masks + color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME); + color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); const auto family_properties = physical_device.getQueueFamilyProperties(); if (family_properties.empty()) { @@ -194,6 +195,7 @@ bool Instance::CreateDevice() { vk::PhysicalDeviceFeatures2{ .features{ .robustBufferAccess = features.robustBufferAccess, + .independentBlend = true, .geometryShader = features.geometryShader, .logicOp = features.logicOp, .samplerAnisotropy = features.samplerAnisotropy, @@ -233,6 +235,7 @@ bool Instance::CreateDevice() { if (!color_write_en) { device_chain.unlink(); + device_chain.unlink(); } try { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index d4a38308..1ddfa2fa 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -93,16 +93,26 @@ void PipelineCache::RefreshGraphicsKey() { key.stencil_ref_back = regs.stencil_ref_back; key.prim_type = regs.primitive_type; key.polygon_mode = regs.polygon_control.PolyMode(); - key.blend_controls = regs.blend_control; const auto& db = regs.depth_buffer; key.depth_format = key.depth.depth_enable ? LiverpoolToVK::DepthFormat(db.z_info.format, db.stencil_info.format) : vk::Format::eUndefined; - for (u32 i = 0; i < Liverpool::NumColorBuffers; i++) { - const auto& cb = regs.color_buffers[i]; - key.color_formats[i] = cb ? LiverpoolToVK::SurfaceFormat(cb.info.format, cb.NumFormat()) - : vk::Format::eUndefined; + // `RenderingInfo` is assumed to be initialized with a contiguous array of valid color + // attachments. This might be not a case as HW color buffers can be bound in an arbitrary order. + // We need to do some arrays compaction at this stage + int remapped_cb{}; + for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) { + auto const& col_buf = regs.color_buffers[cb]; + if (!col_buf) { + continue; + } + key.color_formats[remapped_cb] = + LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat()); + key.blend_controls[remapped_cb] = regs.blend_control[cb]; + key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)}; + + ++remapped_cb; } for (u32 i = 0; i < MaxShaderStages; i++) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index fa973ed8..d0b873fa 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -68,7 +68,7 @@ void Rasterizer::Draw(bool is_indexed) { .pColorAttachments = color_attachments.data(), }; - UpdateDynamicState(); + UpdateDynamicState(*pipeline); cmdbuf.beginRendering(rendering_info); cmdbuf.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline->Handle()); @@ -132,7 +132,7 @@ u32 Rasterizer::SetupIndexBuffer(bool& is_indexed) { return regs.num_indices; } -void Rasterizer::UpdateDynamicState() { +void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) { UpdateViewportScissorState(); auto& regs = liverpool->regs; @@ -140,16 +140,13 @@ void Rasterizer::UpdateDynamicState() { cmdbuf.setBlendConstants(®s.blend_constants.red); if (instance.IsColorWriteEnableSupported()) { - std::array write_en{}; - std::array write_mask{}; - for (int col_buf_idx = 0; col_buf_idx < Liverpool::NumColorBuffers; ++col_buf_idx) { - const auto mask = regs.color_target_mask.raw >> (col_buf_idx * 4); - write_en[col_buf_idx] = mask ? vk::True : vk::False; - write_mask[col_buf_idx] = vk::ColorComponentFlags{mask}; - } + const auto& write_masks = pipeline.GetWriteMasks(); + std::array write_ens{}; + std::transform(write_masks.cbegin(), write_masks.cend(), write_ens.begin(), + [](auto in) { return in ? vk::True : vk::False; }); - cmdbuf.setColorWriteEnableEXT(write_en); - cmdbuf.setColorWriteMaskEXT(0, write_mask); + cmdbuf.setColorWriteEnableEXT(write_ens); + cmdbuf.setColorWriteMaskEXT(0, write_masks); } } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 2678a480..a1b6a5a6 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -37,7 +37,7 @@ private: u32 SetupIndexBuffer(bool& is_indexed); void MapMemory(VAddr addr, size_t size); - void UpdateDynamicState(); + void UpdateDynamicState(const GraphicsPipeline& pipeline); void UpdateViewportScissorState(); void UpdateDepthStencilState();