mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
graphics: materialize fast clears before sampling reused targets
Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
This commit is contained in:
@@ -236,7 +236,8 @@ void RenderExecutor::ResolveRenderColorTarget(CommandBuffer& buffer, RenderColor
|
|||||||
// DCC owns the clear when both planes are enabled; single-sample CMASK stays expanded.
|
// DCC owns the clear when both planes are enabled; single-sample CMASK stays expanded.
|
||||||
desc.info.metadata.kind = has_dcc ? ImageMetadataKind::Dcc : ImageMetadataKind::Cmask;
|
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.range = {has_dcc ? rt.dcc_addr.addr : rt.cmask.addr, metadata_size.size};
|
||||||
desc.info.metadata.clear_word = rt.clear_word0.word0;
|
desc.info.metadata.clear_word =
|
||||||
|
rt.clear_word0.word0 | (uint64_t {rt.clear_word1.word1} << 32u);
|
||||||
desc.info.metadata.clear_register_valid = true;
|
desc.info.metadata.clear_register_valid = true;
|
||||||
}
|
}
|
||||||
desc.view_info.format = target_format.format;
|
desc.view_info.format = target_format.format;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct ImageMetadataInfo {
|
|||||||
GuestRange range;
|
GuestRange range;
|
||||||
ImageMetadataKind kind = ImageMetadataKind::None;
|
ImageMetadataKind kind = ImageMetadataKind::None;
|
||||||
uint32_t control = 0;
|
uint32_t control = 0;
|
||||||
uint32_t clear_word = 0;
|
uint64_t clear_word = 0;
|
||||||
VideoOutCompression compression = VideoOutCompression::Uncompressed;
|
VideoOutCompression compression = VideoOutCompression::Uncompressed;
|
||||||
bool stencil_compressed = false;
|
bool stencil_compressed = false;
|
||||||
bool clear_register_valid = false;
|
bool clear_register_valid = false;
|
||||||
@@ -414,9 +414,10 @@ inline constexpr std::array<VideoOutFormatPolicy, 8> VIDEO_OUT_FORMAT_POLICIES {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint32_t packed,
|
[[nodiscard]] inline bool DecodePackedColorClear(vk::Format format, uint64_t clear_words,
|
||||||
vk::ClearColorValue& clear) {
|
vk::ClearColorValue& clear) {
|
||||||
vk::ClearColorValue next {};
|
vk::ClearColorValue next {};
|
||||||
|
const auto packed = static_cast<uint32_t>(clear_words);
|
||||||
const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; };
|
const auto unorm8 = [](uint32_t value) { return static_cast<float>(value & 0xffu) / 255.0f; };
|
||||||
const auto srgb8 = [](uint32_t value) {
|
const auto srgb8 = [](uint32_t value) {
|
||||||
const auto encoded = static_cast<float>(value & 0xffu) / 255.0f;
|
const auto encoded = static_cast<float>(value & 0xffu) / 255.0f;
|
||||||
@@ -434,6 +435,10 @@ inline constexpr std::array<VideoOutFormatPolicy, 8> VIDEO_OUT_FORMAT_POLICIES {
|
|||||||
(mantissa << 13u));
|
(mantissa << 13u));
|
||||||
};
|
};
|
||||||
switch (format) {
|
switch (format) {
|
||||||
|
case vk::Format::eR16G16B16A16Sfloat:
|
||||||
|
next.float32[2] = float16(static_cast<uint32_t>(clear_words >> 32u));
|
||||||
|
next.float32[3] = float16(static_cast<uint32_t>(clear_words >> 48u));
|
||||||
|
[[fallthrough]];
|
||||||
case vk::Format::eR16G16Sfloat:
|
case vk::Format::eR16G16Sfloat:
|
||||||
next.float32[1] = float16(packed >> 16u);
|
next.float32[1] = float16(packed >> 16u);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ private:
|
|||||||
std::span<PreparedBindings* const> stages = {});
|
std::span<PreparedBindings* const> stages = {});
|
||||||
[[nodiscard]] bool ResolveColorTargets(CommandBuffer& buffer,
|
[[nodiscard]] bool ResolveColorTargets(CommandBuffer& buffer,
|
||||||
uint32_t render_target_slice_offset);
|
uint32_t render_target_slice_offset);
|
||||||
|
[[nodiscard]] bool ConsumeMetadataColorOperation(CommandBuffer& buffer,
|
||||||
|
uint32_t render_target_slice_offset);
|
||||||
void BindImage(ImageId id, bool storage);
|
void BindImage(ImageId id, bool storage);
|
||||||
void BindRenderTarget(ImageId id);
|
void BindRenderTarget(ImageId id);
|
||||||
void ResetBindings();
|
void ResetBindings();
|
||||||
|
|||||||
@@ -608,16 +608,19 @@ enum class CbColorMode : uint8_t {
|
|||||||
DccDecompress = 6,
|
DccDecompress = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool ConsumeMetadataColorOperation(const CommandBuffer& buffer) {
|
bool RenderExecutor::ConsumeMetadataColorOperation(CommandBuffer& buffer,
|
||||||
|
uint32_t render_target_slice_offset) {
|
||||||
const auto& ctx = buffer.GetRegisters();
|
const auto& ctx = buffer.GetRegisters();
|
||||||
const auto mode = ctx.GetColorControl().mode;
|
const auto mode = ctx.GetColorControl().mode;
|
||||||
// These special modes run color-buffer metadata or decompression operations. The shader is a
|
if (mode == static_cast<uint8_t>(CbColorMode::EliminateFastClear)) {
|
||||||
// vehicle for that operation, and its exported color must not be applied as a normal draw.
|
// FCE can precede any ordinary draw. Discover the target to materialize its native
|
||||||
// Kyty stores expanded Vulkan images rather than compressed guest surfaces, so no equivalent
|
// clear metadata before the expanded image is sampled.
|
||||||
// hardware pass is emitted. Tracked DCC clear state is materialized on attachment bind;
|
RenderColorInfo target {};
|
||||||
// future CMask/FMask support can consume its state through the same TextureCache path.
|
ResolveRenderColorTarget(buffer, target, render_target_slice_offset, 0, true);
|
||||||
return mode == static_cast<uint8_t>(CbColorMode::EliminateFastClear) ||
|
return true;
|
||||||
mode == static_cast<uint8_t>(CbColorMode::FmaskDecompress) ||
|
}
|
||||||
|
// Metadata/decompression shaders must not export colors into the expanded image.
|
||||||
|
return mode == static_cast<uint8_t>(CbColorMode::FmaskDecompress) ||
|
||||||
mode == static_cast<uint8_t>(CbColorMode::DccDecompress);
|
mode == static_cast<uint8_t>(CbColorMode::DccDecompress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1257,7 +1260,8 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConsumeMetadataColorOperation(buffer) || DepthStencilCopy(buffer) ||
|
if (ConsumeMetadataColorOperation(buffer, args.render_target_slice_offset) ||
|
||||||
|
DepthStencilCopy(buffer) ||
|
||||||
ResolveColorTargets(buffer, args.render_target_slice_offset)) {
|
ResolveColorTargets(buffer, args.render_target_slice_offset)) {
|
||||||
ResetBindings();
|
ResetBindings();
|
||||||
return;
|
return;
|
||||||
@@ -1370,7 +1374,8 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConsumeMetadataColorOperation(buffer) || DepthStencilCopy(buffer) ||
|
if (ConsumeMetadataColorOperation(buffer, args.render_target_slice_offset) ||
|
||||||
|
DepthStencilCopy(buffer) ||
|
||||||
ResolveColorTargets(buffer, args.render_target_slice_offset)) {
|
ResolveColorTargets(buffer, args.render_target_slice_offset)) {
|
||||||
ResetBindings();
|
ResetBindings();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -10865,12 +10865,14 @@ public:
|
|||||||
constexpr const char *name = "RenderExecutorColorMetadataClear";
|
constexpr const char *name = "RenderExecutorColorMetadataClear";
|
||||||
struct PackedCase {
|
struct PackedCase {
|
||||||
vk::Format format;
|
vk::Format format;
|
||||||
uint32_t word;
|
uint64_t word;
|
||||||
std::array<float, 4> channels;
|
std::array<float, 4> channels;
|
||||||
};
|
};
|
||||||
const std::array packed_cases{
|
const std::array packed_cases{
|
||||||
PackedCase{vk::Format::eR16Sfloat, 0x7bff7bffu, {65504.0f}},
|
PackedCase{vk::Format::eR16Sfloat, 0x7bff7bffu, {65504.0f}},
|
||||||
PackedCase{vk::Format::eR16G16Sfloat, 0xbc003c00u, {1.0f, -1.0f}},
|
PackedCase{vk::Format::eR16G16Sfloat, 0xbc003c00u, {1.0f, -1.0f}},
|
||||||
|
PackedCase{vk::Format::eR16G16B16A16Sfloat, 0x40003800bc003c00ull,
|
||||||
|
{1.0f, -1.0f, 0.5f, 2.0f}},
|
||||||
PackedCase{vk::Format::eR16Sfloat, 0xffff0001u, {0x1p-24f}},
|
PackedCase{vk::Format::eR16Sfloat, 0xffff0001u, {0x1p-24f}},
|
||||||
PackedCase{vk::Format::eR16Sfloat, 0x00008001u, {-0x1p-24f}},
|
PackedCase{vk::Format::eR16Sfloat, 0x00008001u, {-0x1p-24f}},
|
||||||
PackedCase{vk::Format::eR16Sfloat, 0x000003ffu, {1023.0f * 0x1p-24f}},
|
PackedCase{vk::Format::eR16Sfloat, 0x000003ffu, {1023.0f * 0x1p-24f}},
|
||||||
@@ -10904,7 +10906,7 @@ public:
|
|||||||
"alternating R16 pixels were treated as a uniform clear");
|
"alternating R16 pixels were treated as a uniform clear");
|
||||||
}
|
}
|
||||||
constexpr uintptr_t base = 0x0000000204100000ull;
|
constexpr uintptr_t base = 0x0000000204100000ull;
|
||||||
constexpr uint64_t allocation_size = 0x200000;
|
constexpr uint64_t allocation_size = 0x400000;
|
||||||
constexpr uint64_t allocation_alignment = 0x10000;
|
constexpr uint64_t allocation_alignment = 0x10000;
|
||||||
struct FillCase {
|
struct FillCase {
|
||||||
uint32_t fill;
|
uint32_t fill;
|
||||||
@@ -10915,12 +10917,19 @@ public:
|
|||||||
Prospero::ChannelLayout layout = Prospero::ChannelLayout::k16_16_16_16;
|
Prospero::ChannelLayout layout = Prospero::ChannelLayout::k16_16_16_16;
|
||||||
Prospero::ChannelType type = Prospero::ChannelType::kFloat;
|
Prospero::ChannelType type = Prospero::ChannelType::kFloat;
|
||||||
uint32_t clear_word = 0;
|
uint32_t clear_word = 0;
|
||||||
|
bool eliminate_fast_clear = false;
|
||||||
};
|
};
|
||||||
constexpr std::array cases{
|
constexpr std::array cases{
|
||||||
FillCase{0x40404040u, {0, 0x3c000000u}},
|
FillCase{0x40404040u, {0, 0x3c000000u}},
|
||||||
FillCase{0x80808080u, {0x3c003c00u, 0x00003c00u}},
|
FillCase{0x80808080u, {0x3c003c00u, 0x00003c00u}},
|
||||||
FillCase{0x40404040u, {0, 0x3c000000u}, true},
|
FillCase{0x40404040u, {0, 0x3c000000u}, true},
|
||||||
FillCase{0, {0x804020ffu, 0}, false, true},
|
FillCase{.fill = 0, .texel = {0x804020ffu, 0}, .cmask = true,
|
||||||
|
.layout = Prospero::ChannelLayout::k8_8_8_8,
|
||||||
|
.type = Prospero::ChannelType::kUNorm},
|
||||||
|
FillCase{.fill = 0, .texel = {0, 0}, .cmask = true,
|
||||||
|
.eliminate_fast_clear = true},
|
||||||
|
FillCase{.fill = 0, .texel = {0, 0x3c000000u}, .cmask = true,
|
||||||
|
.eliminate_fast_clear = true},
|
||||||
FillCase{0x40404040u, {0, 0x3c000000u}, false, false, true},
|
FillCase{0x40404040u, {0, 0x3c000000u}, false, false, true},
|
||||||
FillCase{.fill = 0x20202020u, .texel = {0x7bff7bffu},
|
FillCase{.fill = 0x20202020u, .texel = {0x7bff7bffu},
|
||||||
.layout = Prospero::ChannelLayout::k16, .clear_word = 0x7bff7bffu},
|
.layout = Prospero::ChannelLayout::k16, .clear_word = 0x7bff7bffu},
|
||||||
@@ -10985,15 +10994,16 @@ public:
|
|||||||
std::memset(mapped, 0, allocation_size);
|
std::memset(mapped, 0, allocation_size);
|
||||||
|
|
||||||
for (const auto &fill_case : cases) {
|
for (const auto &fill_case : cases) {
|
||||||
const auto layout = fill_case.cmask ? Prospero::ChannelLayout::k8_8_8_8 : fill_case.layout;
|
const auto layout = fill_case.layout;
|
||||||
const auto type = fill_case.cmask ? Prospero::ChannelType::kUNorm : fill_case.type;
|
const auto type = fill_case.type;
|
||||||
const auto bytes_per_pixel = TextureGetRenderTargetFormat(
|
const auto bytes_per_pixel = TextureGetRenderTargetFormat(
|
||||||
layout, type, Prospero::ChannelOrder::kStandard).bytes_per_element;
|
layout, type, Prospero::ChannelOrder::kStandard).bytes_per_element;
|
||||||
const uint32_t probe_width = bytes_per_pixel == 2 ? 2 : 1;
|
const uint32_t probe_width = bytes_per_pixel == 2 ? 2 : 1;
|
||||||
TileSizeAlign dcc_size{};
|
TileSizeAlign dcc_size{};
|
||||||
(void)TileGetDccSize(512, 256, 1, bytes_per_pixel, 1,
|
(void)TileGetDccSize(512, 256, 1, bytes_per_pixel, 1,
|
||||||
Prospero::TileMode::kRenderTarget, dcc_size, 0);
|
Prospero::TileMode::kRenderTarget, dcc_size, 0);
|
||||||
const uint64_t dcc_address = base + (fill_case.reuse_mips ? 0x160000 : 0x100000);
|
const uint64_t dcc_address = base + (fill_case.eliminate_fast_clear ? 0x200000 :
|
||||||
|
fill_case.reuse_mips ? 0x160000 : 0x100000);
|
||||||
const uint32_t selected_layer = fill_case.cmask ? 1 : 0;
|
const uint32_t selected_layer = fill_case.cmask ? 1 : 0;
|
||||||
const uint64_t metadata_size = fill_case.cmask ? 0x2000 : dcc_size.size;
|
const uint64_t metadata_size = fill_case.cmask ? 0x2000 : dcc_size.size;
|
||||||
const std::vector<u32> expected(
|
const std::vector<u32> expected(
|
||||||
@@ -11023,7 +11033,7 @@ public:
|
|||||||
registers.SetColorDccAddr(0, {.addr = dcc_address});
|
registers.SetColorDccAddr(0, {.addr = dcc_address});
|
||||||
registers.SetColorCmask(0, {.addr = dcc_address});
|
registers.SetColorCmask(0, {.addr = dcc_address});
|
||||||
registers.SetColorClearWord0(0, {.word0 = fill_case.cmask ? expected[0] : fill_case.clear_word});
|
registers.SetColorClearWord0(0, {.word0 = fill_case.cmask ? expected[0] : fill_case.clear_word});
|
||||||
registers.SetColorClearWord1(0, {.word1 = 0});
|
registers.SetColorClearWord1(0, {.word1 = fill_case.eliminate_fast_clear ? expected[1] : 0});
|
||||||
registers.SetRenderTargetMask(0x0f);
|
registers.SetRenderTargetMask(0x0f);
|
||||||
scheduler.Begin(registers, user_config, shaders);
|
scheduler.Begin(registers, user_config, shaders);
|
||||||
|
|
||||||
@@ -11032,7 +11042,8 @@ public:
|
|||||||
auto &executor = context.GetRenderExecutor();
|
auto &executor = context.GetRenderExecutor();
|
||||||
resources.MapMemory(base, allocation_size);
|
resources.MapMemory(base, allocation_size);
|
||||||
ImageId preexisting_id{};
|
ImageId preexisting_id{};
|
||||||
if (fill_case.reuse_unorm || fill_case.reuse_mips) {
|
RenderColorInfo color{};
|
||||||
|
if (fill_case.reuse_unorm || fill_case.reuse_mips || fill_case.eliminate_fast_clear) {
|
||||||
const auto float_info = registers.GetRenderTarget(0).info;
|
const auto float_info = registers.GetRenderTarget(0).info;
|
||||||
const auto single_mip = registers.GetRenderTarget(0).attrib2;
|
const auto single_mip = registers.GetRenderTarget(0).attrib2;
|
||||||
auto initial_info = float_info;
|
auto initial_info = float_info;
|
||||||
@@ -11049,6 +11060,7 @@ public:
|
|||||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||||
executor, scheduler.Current(), preexisting, 0);
|
executor, scheduler.Current(), preexisting, 0);
|
||||||
preexisting_id = preexisting.image_id;
|
preexisting_id = preexisting.image_id;
|
||||||
|
color = preexisting;
|
||||||
(void)texture_cache.FindRenderTarget(preexisting_id, preexisting.desc);
|
(void)texture_cache.FindRenderTarget(preexisting_id, preexisting.desc);
|
||||||
if (fill_case.reuse_mips) {
|
if (fill_case.reuse_mips) {
|
||||||
Require(name, "mip chain excludes metadata",
|
Require(name, "mip chain excludes metadata",
|
||||||
@@ -11061,6 +11073,13 @@ public:
|
|||||||
texture_cache, scheduler.Current(), preexisting_id,
|
texture_cache, scheduler.Current(), preexisting_id,
|
||||||
{vk::ImageAspectFlagBits::eColor, 0, 2, 0, 1}, clear);
|
{vk::ImageAspectFlagBits::eColor, 0, 2, 0, 1}, clear);
|
||||||
}
|
}
|
||||||
|
if (fill_case.eliminate_fast_clear) {
|
||||||
|
vk::ClearValue stale{};
|
||||||
|
stale.color.float32 = std::array{1.0f, 0.0f, 1.0f, 1.0f};
|
||||||
|
TextureCacheTestAccess::ClearImage(
|
||||||
|
texture_cache, scheduler.Current(), preexisting_id,
|
||||||
|
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 2}, stale);
|
||||||
|
}
|
||||||
RenderExecutorTestAccess::ResetBindings(executor);
|
RenderExecutorTestAccess::ResetBindings(executor);
|
||||||
registers.SetColorInfo(0, float_info);
|
registers.SetColorInfo(0, float_info);
|
||||||
registers.SetColorAttrib2(0, single_mip);
|
registers.SetColorAttrib2(0, single_mip);
|
||||||
@@ -11088,7 +11107,66 @@ public:
|
|||||||
!texture_cache.IsMeta(dcc_address),
|
!texture_cache.IsMeta(dcc_address),
|
||||||
"the native fill guessed an unbound metadata allocation's type");
|
"the native fill guessed an unbound metadata allocation's type");
|
||||||
|
|
||||||
RenderColorInfo color{};
|
const auto check_expanded_metadata = [&] {
|
||||||
|
context.GetBufferCache().ReadMemory(dcc_address, metadata_size, false);
|
||||||
|
std::vector<uint8_t> bytes(metadata_size);
|
||||||
|
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);
|
||||||
|
Require(name, "selected metadata slice expansion",
|
||||||
|
std::all_of(bytes.begin(), selected, [](uint8_t v) { return v == 0; }) &&
|
||||||
|
std::all_of(selected, bytes.end(), [](uint8_t v) { return v == 0xff; }),
|
||||||
|
"materialization retained a clear key or changed an unselected slice");
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto paint = [&] {
|
||||||
|
vk::ClearValue clear{};
|
||||||
|
clear.color.float32 = std::array{1.0f, 0.0f, 1.0f, 1.0f};
|
||||||
|
TextureCacheTestAccess::ClearImage(
|
||||||
|
texture_cache, scheduler.Current(), color.image_id,
|
||||||
|
{vk::ImageAspectFlagBits::eColor, 0, 1, selected_layer, 1}, clear);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fill_case.eliminate_fast_clear) {
|
||||||
|
registers.SetRenderTargetMask(0);
|
||||||
|
registers.SetColorControl({.mode = 2});
|
||||||
|
RenderExecutorTestAccess::DrawAuto(executor, scheduler.Current(),
|
||||||
|
{.vertex_count = 3, .instance_count = 1});
|
||||||
|
auto sampled = color.desc;
|
||||||
|
sampled.type = BindingType::Texture;
|
||||||
|
sampled.view_info.usage = vk::ImageUsageFlagBits::eSampled;
|
||||||
|
color.image_id = texture_cache.FindImage(sampled);
|
||||||
|
Require(name, "FCE sampled image reuses stale target",
|
||||||
|
color.image_id == preexisting_id &&
|
||||||
|
texture_cache.FindTexture(color.image_id, sampled) != nullptr,
|
||||||
|
"FCE failed to retain the sampled allocation");
|
||||||
|
const std::vector<u32> stale{0x00003c00u, 0x3c003c00u};
|
||||||
|
Require(name, "FCE before graphics shader or target binding",
|
||||||
|
ReadCachedTexel(name, context, color.image_id, {}, {1, 1, 1}, 1) == expected &&
|
||||||
|
ReadCachedTexel(name, context, color.image_id, {511, 255, 0},
|
||||||
|
{1, 1, 1}, 1) == expected &&
|
||||||
|
ReadCachedTexel(name, context, color.image_id, {}, {1, 1, 1}, 0) == stale,
|
||||||
|
"FCE lost a clear register or changed the unselected layer");
|
||||||
|
check_expanded_metadata();
|
||||||
|
paint();
|
||||||
|
RenderExecutorTestAccess::DrawIndex(executor, scheduler.Current(),
|
||||||
|
{.index_count = 3, .instance_count = 1});
|
||||||
|
(void)texture_cache.FindTexture(color.image_id, sampled);
|
||||||
|
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);
|
||||||
|
RenderExecutorTestAccess::DrawIndex(executor, scheduler.Current(),
|
||||||
|
{.index_count = 3, .instance_count = 1});
|
||||||
|
(void)texture_cache.FindTexture(color.image_id, sampled);
|
||||||
|
Require(name, "indexed FCE consumes a new clear",
|
||||||
|
ReadCachedTexel(name, context, color.image_id, {}, {1, 1, 1}, 1) == expected,
|
||||||
|
"indexed FCE skipped a new metadata clear");
|
||||||
|
resources.UnmapMemory(base, allocation_size);
|
||||||
|
scheduler.Finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||||
executor, scheduler.Current(), color, 0);
|
executor, scheduler.Current(), color, 0);
|
||||||
RenderDepthInfo no_depth{};
|
RenderDepthInfo no_depth{};
|
||||||
@@ -11132,18 +11210,6 @@ public:
|
|||||||
std::vector<u32>{0x00003c00u, 0x00003c00u},
|
std::vector<u32>{0x00003c00u, 0x00003c00u},
|
||||||
"clearing mip zero changed its higher mip");
|
"clearing mip zero changed its higher mip");
|
||||||
}
|
}
|
||||||
const auto check_expanded_metadata = [&] {
|
|
||||||
context.GetBufferCache().ReadMemory(dcc_address, metadata_size, false);
|
|
||||||
std::vector<uint8_t> bytes(metadata_size);
|
|
||||||
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);
|
|
||||||
Require(name, "selected metadata slice expansion",
|
|
||||||
std::all_of(bytes.begin(), selected, [](uint8_t v) { return v == 0; }) &&
|
|
||||||
std::all_of(selected, bytes.end(), [](uint8_t v) { return v == 0xff; }),
|
|
||||||
"materialization retained a clear key or changed an unselected slice");
|
|
||||||
};
|
|
||||||
check_expanded_metadata();
|
check_expanded_metadata();
|
||||||
|
|
||||||
const auto bind = [&] {
|
const auto bind = [&] {
|
||||||
@@ -11151,13 +11217,6 @@ public:
|
|||||||
color.image_id = texture_cache.FindImage(color.desc);
|
color.image_id = texture_cache.FindImage(color.desc);
|
||||||
(void)texture_cache.FindRenderTarget(color.image_id, color.desc);
|
(void)texture_cache.FindRenderTarget(color.image_id, color.desc);
|
||||||
};
|
};
|
||||||
const auto paint = [&] {
|
|
||||||
vk::ClearValue clear{};
|
|
||||||
clear.color.float32 = std::array{1.0f, 0.0f, 1.0f, 1.0f};
|
|
||||||
TextureCacheTestAccess::ClearImage(
|
|
||||||
texture_cache, scheduler.Current(), color.image_id,
|
|
||||||
{vk::ImageAspectFlagBits::eColor, 0, 1, selected_layer, 1}, clear);
|
|
||||||
};
|
|
||||||
std::vector<u32> painted{0x00003c00u, 0x3c003c00u};
|
std::vector<u32> painted{0x00003c00u, 0x3c003c00u};
|
||||||
if (fill_case.reuse_unorm) {
|
if (fill_case.reuse_unorm) {
|
||||||
painted = {0x0000ffffu, 0xffffffffu};
|
painted = {0x0000ffffu, 0xffffffffu};
|
||||||
|
|||||||
Reference in New Issue
Block a user