diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 0647c4dbd..e3abcc6db 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -1040,7 +1040,7 @@ void TextureCache::MaterializeColorClear(ImageId id, const ImageDesc& desc, std::scoped_lock lock {m_lock}; auto& image = m_slot_images[id]; image.info.metadata = desc.info.metadata; - // Native color metadata must not retain a reused HTile/CMask/FMask clear flag. + // Native color metadata must not retain a reused HTile clear flag. m_surface_metas.erase(range.address); if (range.size == 0 || desc.info.resources.levels != 1) { return; @@ -1418,11 +1418,8 @@ vk::ImageView TextureCache::FindDepthTarget(ImageId id, const ImageDesc& desc) { image.info.metadata = desc.info.metadata; if (desc.info.HasMetadata()) { const auto [metadata, inserted] = m_surface_metas.try_emplace(desc.info.metadata.range.address); - if (inserted) { - metadata->second.type = MetaDataInfo::Type::HTile; - if (image.info.htile_initial_clear) { - metadata->second.clear_mask.set(); - } + if (inserted && image.info.htile_initial_clear) { + metadata->second.clear_mask.set(); } } RefreshImage(id); diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.h b/src/graphics/host_gpu/renderer/cache/textureCache.h index e91928f6c..ebf3b6b7b 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.h +++ b/src/graphics/host_gpu/renderer/cache/textureCache.h @@ -81,9 +81,6 @@ public: private: struct MetaDataInfo { - enum class Type : uint8_t { CMask, FMask, HTile }; - - Type type; // PS5 DB_DEPTH_VIEW encodes 13-bit base and last array-slice indices. std::bitset<8192> clear_mask; }; diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index 441ea30e5..e45c18e52 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -220,8 +220,7 @@ void RenderExecutor::ResolveRenderColorTarget(CommandBuffer& buffer, RenderColor } const bool has_dcc = rt.info.dcc_compression_enable && rt.dcc_addr.addr != 0; const bool has_cmask = !rt.info.dcc_compression_enable && rt.info.cmask_fast_clear_enable && - rt.cmask.addr != 0 && samples == 1 && - !rt.info.fmask_compression_enable && + rt.cmask.addr != 0 && !rt.attrib3.write_vrs_rate_hint_to_cmask; if (has_dcc || has_cmask) { TileSizeAlign metadata_size {}; @@ -233,7 +232,7 @@ void RenderExecutor::ResolveRenderColorTarget(CommandBuffer& buffer, RenderColor } else { (void)TileGetCmaskSize(width, height, layers, levels, metadata_size); } - // DCC owns the clear when both planes are enabled; single-sample CMASK stays expanded. + // DCC owns the clear when both planes are enabled. desc.info.metadata.kind = has_dcc ? ImageMetadataKind::Dcc : ImageMetadataKind::Cmask; desc.info.metadata.range = {has_dcc ? rt.dcc_addr.addr : rt.cmask.addr, metadata_size.size}; desc.info.metadata.clear_word = diff --git a/src/graphics/host_gpu/renderer/debug.cpp b/src/graphics/host_gpu/renderer/debug.cpp index 40bbbf824..5888fb380 100644 --- a/src/graphics/host_gpu/renderer/debug.cpp +++ b/src/graphics/host_gpu/renderer/debug.cpp @@ -294,16 +294,6 @@ static void RtCheck(const HW::RenderTarget& rt) { EXIT_NOT_IMPLEMENTED(rt.dcc.overwrite_combiner_disable != false); // EXIT_NOT_IMPLEMENTED(rt.dcc.data_write_on_dcc_clear_to_reg != false); EXIT_NOT_IMPLEMENTED(rt.dcc.dcc_clear_key_enable != false); - if (rt.cmask.addr != 0x0000000000000000 || rt.fmask.addr != 0x0000000000000000 || - rt.dcc_addr.addr != 0x0000000000000000) { - static bool logged = false; - if (!logged) { - LOGF("RenderTarget: temporary: ignoring PS5 metadata addresses cmask=0x%016" PRIx64 - " fmask=0x%016" PRIx64 " dcc=0x%016" PRIx64 "\n", - rt.cmask.addr, rt.fmask.addr, rt.dcc_addr.addr); - logged = true; - } - } } } diff --git a/src/launcher/forms/configuration_edit_dialog.ui b/src/launcher/forms/configuration_edit_dialog.ui index d00aa1ea9..e3f48e017 100644 --- a/src/launcher/forms/configuration_edit_dialog.ui +++ b/src/launcher/forms/configuration_edit_dialog.ui @@ -481,6 +481,12 @@ Rendering compatibility + + + These settings may help with rendering bugs at a slight performance cost. + true + + Can fix missing textures and incorrect transparency (Resident Evil 2). diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index e4d3ee57b..9a7e505aa 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -390,7 +390,6 @@ struct TextureCacheTestAccess { static void RegisterHtileMeta(TextureCache &cache, uint64_t address) { std::lock_guard lock(cache.m_lock); auto &metadata = cache.m_surface_metas[address]; - metadata.type = TextureCache::MetaDataInfo::Type::HTile; metadata.clear_mask.reset(); } @@ -10487,22 +10486,34 @@ public: vk::Extent3D extent = {1, 1, 1}, uint32_t layer = 0, uint32_t mip = 0) { auto &scheduler = context.GetCommandScheduler(); - auto &image = context.GetTextureCache().GetImage(id); - const auto bytes = image.info.bytes_per_block * extent.width * + auto *image = &context.GetTextureCache().GetImage(id); + std::unique_ptr resolved; + if (image->backing.samples > 1) { + auto info = image->info; + info.data = {}; + info.metadata = {}; + info.samples = 1; + info.resources = {1, 1}; + resolved = std::make_unique(m_runtime_context, scheduler, info); + resolved->Resolve(*image, {mip, 1, layer, 1}, {}); + image = resolved.get(); + layer = mip = 0; + } + const auto bytes = image->info.bytes_per_block * extent.width * extent.height * extent.depth; auto probe = CreateHostBuffer(name, bytes, vk::BufferUsageFlagBits::eTransferDst, {}); scheduler.Current().EndRendering(); - image.Transit(vk::ImageLayout::eTransferSrcOptimal, + image->Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}, scheduler.Current().Handle()); vk::BufferImageCopy copy{}; - copy.imageSubresource = {image.info.IsDepth() ? vk::ImageAspectFlagBits::eDepth + copy.imageSubresource = {image->info.IsDepth() ? vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor, mip, layer, 1}; copy.imageOffset = offset; copy.imageExtent = extent; scheduler.Current().Handle().copyImageToBuffer( - image.backing.image, vk::ImageLayout::eTransferSrcOptimal, + image->backing.image, vk::ImageLayout::eTransferSrcOptimal, probe.buffer, 1, ©); vk::BufferMemoryBarrier barrier{}; barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; @@ -11509,7 +11520,7 @@ public: clear.float32[0] == 1.0f && clear.float32[1] == 1.0f, "a repeated DWORD fill was decoded as a two-register clear"); constexpr uintptr_t base = 0x0000000204100000ull; - constexpr uint64_t allocation_size = 0x400000; + constexpr uint64_t allocation_size = 0x1000000; constexpr uint64_t allocation_alignment = 0x10000; struct FillCase { uint32_t fill; @@ -11521,6 +11532,7 @@ public: Prospero::ChannelType type = Prospero::ChannelType::kFloat; uint32_t clear_word = 0; bool eliminate_fast_clear = false; + uint32_t samples_log2 = 0; }; constexpr std::array cases{ FillCase{0x40404040u, {0, 0x3c000000u}}, @@ -11552,6 +11564,15 @@ public: FillCase{.fill = 0x20202020u, .texel = {0x0000ffffu}, .layout = Prospero::ChannelLayout::k16_16, .type = Prospero::ChannelType::kUNorm, .clear_word = 0x0000ffffu}, + FillCase{.fill = 0, .texel = {0x804020ffu, 0}, .cmask = true, + .layout = Prospero::ChannelLayout::k8_8_8_8, + .type = Prospero::ChannelType::kUNorm, .samples_log2 = 2}, + FillCase{.fill = 0, .texel = {0x804020ffu, 0}, .cmask = true, + .layout = Prospero::ChannelLayout::k8_8_8_8, + .type = Prospero::ChannelType::kUNorm, .eliminate_fast_clear = true, .samples_log2 = 2}, + FillCase{.fill = 0, .texel = {0, 0x3c000000u}, .cmask = true, + .eliminate_fast_clear = true, .samples_log2 = 2}, + FillCase{.fill = 0x40404040u, .texel = {0, 0x3c000000u}, .eliminate_fast_clear = true}, }; EnsureRuntimeContext(); // Astro's generic metadata fill, through S_ENDPGM; trailing debug data is omitted. @@ -11610,12 +11631,13 @@ public: const auto bytes_per_pixel = TextureGetRenderTargetFormat( layout, type, Prospero::ChannelOrder::kStandard).bytes_per_element; const uint32_t probe_width = bytes_per_pixel == 2 ? 2 : 1; + const uint32_t selected_layer = fill_case.cmask || fill_case.eliminate_fast_clear ? 1 : 0; TileSizeAlign dcc_size{}; - (void)TileGetDccSize(512, 256, 1, bytes_per_pixel, 1, - Prospero::TileMode::kRenderTarget, dcc_size, 0); - const uint64_t dcc_address = base + (fill_case.eliminate_fast_clear ? 0x200000 : + (void)TileGetDccSize(512, 256, selected_layer + 1, bytes_per_pixel, 1, + Prospero::TileMode::kRenderTarget, dcc_size, fill_case.samples_log2); + const uint64_t dcc_address = base + (fill_case.samples_log2 != 0 ? 0x800000 : + fill_case.eliminate_fast_clear ? 0x200000 : fill_case.reuse_mips ? 0x160000 : 0x100000); - const uint32_t selected_layer = fill_case.cmask ? 1 : 0; const uint64_t metadata_size = fill_case.cmask ? 0x2000 : dcc_size.size; const std::vector expected( fill_case.texel.begin(), fill_case.texel.begin() + std::max(bytes_per_pixel / 4u, 1u)); @@ -11629,13 +11651,16 @@ public: auto &scheduler = context.GetCommandScheduler(); registers.SetColorBase(0, {.addr = base}); registers.SetColorInfo( - 0, {.cmask_fast_clear_enable = !fill_case.reuse_unorm, + 0, {.fmask_compression_enable = fill_case.samples_log2 != 0, + .cmask_fast_clear_enable = !fill_case.reuse_unorm, .dcc_compression_enable = !fill_case.cmask, .format = layout, .channel_type = type, .channel_order = Prospero::ChannelOrder::kStandard}); registers.SetColorView(0, {.base_array_slice_index = selected_layer, .last_array_slice_index = selected_layer}); + registers.SetColorAttrib(0, {.num_samples = fill_case.samples_log2, + .num_fragments = fill_case.samples_log2}); registers.SetColorAttrib2(0, {.height = 255, .width = 511}); registers.SetColorAttrib3(0, {.tile_mode = Prospero::TileMode::kRenderTarget, @@ -11643,6 +11668,7 @@ public: .metadata_pipe_aligned = true}); registers.SetColorDccAddr(0, {.addr = dcc_address}); registers.SetColorCmask(0, {.addr = dcc_address}); + registers.SetColorFmask(0, {.addr = fill_case.samples_log2 != 0 ? base + 0xc00000 : 0}); registers.SetColorClearWord0(0, {.word0 = fill_case.cmask ? expected[0] : fill_case.clear_word}); registers.SetColorClearWord1(0, {.word1 = fill_case.cmask && expected.size() > 1u ? expected[1] : 0}); registers.SetRenderTargetMask(0x0f); @@ -11724,9 +11750,10 @@ public: Require(name, "expanded metadata readback", LibKernel::Memory::TryReadBacking(dcc_address, bytes.data(), bytes.size()), "native color metadata could not be read back"); - const auto selected = bytes.begin() + (fill_case.cmask ? 0x1000 : 0); + const auto selected = bytes.begin() + metadata_size * selected_layer / (selected_layer + 1); Require(name, "selected metadata slice expansion", - std::all_of(bytes.begin(), selected, [](uint8_t v) { return v == 0; }) && + std::all_of(bytes.begin(), selected, + [&](uint8_t v) { return v == static_cast(fill_case.fill); }) && std::all_of(selected, bytes.end(), [](uint8_t v) { return v == 0xff; }), "materialization retained a clear key or changed an unselected slice"); }; @@ -11752,7 +11779,8 @@ public: color.image_id == preexisting_id && texture_cache.FindTexture(color.image_id, sampled) != nullptr, "FCE failed to retain the sampled allocation"); - const std::vector stale = layout == Prospero::ChannelLayout::k11_11_10 + const std::vector stale = layout == Prospero::ChannelLayout::k8_8_8_8 + ? std::vector{0xffff00ffu} : layout == Prospero::ChannelLayout::k11_11_10 ? std::vector{0x780003c0u} : layout == Prospero::ChannelLayout::k32_32 ? std::vector{0x3f800000u, 0u} : std::vector{0x00003c00u, 0x3c003c00u}; Require(name, "FCE before graphics shader or target binding", @@ -11769,7 +11797,7 @@ public: Require(name, "repeated indexed FCE preserves expanded color", ReadCachedTexel(name, context, color.image_id, {}, {1, 1, 1}, 1) == stale, "FCE reapplied the consumed clear after rendering"); - WriteMetadata(context, dcc_address, metadata_size, 0); + WriteMetadata(context, dcc_address, metadata_size, fill_case.fill); RenderExecutorTestAccess::DrawIndex(executor, scheduler.Current(), {.index_count = 3, .instance_count = 1}); (void)texture_cache.FindTexture(color.image_id, sampled); @@ -11948,7 +11976,7 @@ public: ImageDesc previous_depth{}; previous_depth.type = BindingType::DepthTarget; - previous_depth.info.data = {base + 0x180000, 0x10000}; + previous_depth.info.data = {base + 0xa00000, 0x10000}; previous_depth.info.pixel_format = vk::Format::eD32Sfloat; previous_depth.info.guest_format = Prospero::BufferFormat::k32Float; previous_depth.info.type = Prospero::ImageType::kColor2D;