mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-24 04:46:56 +02:00
shader: read raw D16 depth bits through kDepth k16UInt image loads
Co-authored-by: Artyom Zabroda <artyomzabroda@proton.me>
This commit is contained in:
@@ -12478,6 +12478,123 @@ public:
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
// Cyberpunk 2077 copies its HTile D16 depth target through a kDepth k16UInt image load.
|
||||
void CheckDepthBitsCopy() {
|
||||
constexpr const char *name = "DepthBitsCopy";
|
||||
constexpr uintptr_t base = 0x0000000205000000ull;
|
||||
constexpr uint64_t allocation_size = 0x30000;
|
||||
constexpr uint64_t htile_address = base + 0x10000;
|
||||
constexpr uint64_t copy_address = base + 0x20000;
|
||||
constexpr u32 depth_code = 0x2000u;
|
||||
std::vector<u32> copy{EncodeMimg0(0x00, 0x1), EncodeMimg1(4, 0, 2),
|
||||
EncodeMimg0(0x08, 0x1), EncodeMimg1(4, 0, 0)};
|
||||
AppendEnd(©);
|
||||
ShaderMapUserData(reinterpret_cast<uint64_t>(copy.data()),
|
||||
{.type = Prospero::ShaderBinaryType::kCs,
|
||||
.code_size_bytes = static_cast<u32>(copy.size() * sizeof(u32))});
|
||||
EnsureRuntimeContext();
|
||||
int64_t direct_offset = -1;
|
||||
Require(name, "direct allocation",
|
||||
Libs::LibKernel::Memory::KernelAllocateDirectMemory(
|
||||
0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(),
|
||||
allocation_size, 0x10000, 0, &direct_offset) == 0,
|
||||
"depth allocation failed");
|
||||
void *mapped = reinterpret_cast<void *>(base);
|
||||
Require(name, "direct mapping",
|
||||
Libs::LibKernel::Memory::KernelMapDirectMemory(
|
||||
&mapped, allocation_size, 0x3, 0x10, direct_offset, 0x10000) == 0 &&
|
||||
mapped == reinterpret_cast<void *>(base),
|
||||
"depth mapping failed");
|
||||
std::memset(mapped, 0, allocation_size);
|
||||
RenderContext context(m_runtime_context);
|
||||
context.InitializeGpu(nullptr);
|
||||
LibKernel::Memory::InstallGpuResources(&context);
|
||||
context.GetGpu().SendCommandSync([&] {
|
||||
CommandProcessor processor(context, 0);
|
||||
processor.BufferInit();
|
||||
auto &scheduler = context.GetCommandScheduler();
|
||||
auto &textures = context.GetTextureCache();
|
||||
auto &shaders = processor.GetShCtx();
|
||||
context.MapMemory(base, allocation_size);
|
||||
ImageDesc depth{};
|
||||
depth.type = BindingType::DepthTarget;
|
||||
depth.info.data = {base, 0x10000};
|
||||
depth.info.pixel_format = vk::Format::eD16Unorm;
|
||||
depth.info.guest_format = Prospero::BufferFormat::k16UNorm;
|
||||
depth.info.type = Prospero::ImageType::kColor2D;
|
||||
depth.info.extent = {256, 128, 1};
|
||||
depth.info.resources = {1, 1};
|
||||
depth.info.pitch = 256;
|
||||
depth.info.bytes_per_block = 2;
|
||||
depth.info.samples = 1;
|
||||
depth.info.tile_mode = Prospero::TileMode::kDepth;
|
||||
depth.info.UpdateSize();
|
||||
depth.info.metadata.kind = ImageMetadataKind::Htile;
|
||||
depth.info.metadata.range = {htile_address, 0x8000};
|
||||
depth.info.htile_initial_clear = false;
|
||||
depth.view_info.format = vk::Format::eD16Unorm;
|
||||
depth.view_info.type = vk::ImageViewType::e2D;
|
||||
depth.view_info.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||
depth.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
const auto depth_id = textures.FindImage(depth);
|
||||
Require(name, "HTile depth target", textures.FindDepthTarget(depth_id, depth) != nullptr,
|
||||
"the D16 depth target was not created");
|
||||
vk::ClearValue clear{};
|
||||
clear.depthStencil.depth = static_cast<float>(depth_code) / 65535.0f;
|
||||
TextureCacheTestAccess::ClearImage(textures, scheduler.Current(), depth_id,
|
||||
{vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1}, clear);
|
||||
|
||||
// The captured T# with this depth target's size and HTile; the copy writes 2x2 texels.
|
||||
const ShaderTextureResource depth_bits{{static_cast<u32>(base >> 8u),
|
||||
(static_cast<u32>(Prospero::BufferFormat::k16UInt) << 20u) | (3u << 30u),
|
||||
0x3fu | (127u << 14u),
|
||||
DstSel(4, 0, 0, 1) | (static_cast<u32>(Prospero::TileMode::kDepth) << 20u) |
|
||||
(static_cast<u32>(Prospero::ImageType::kColor2D) << 28u),
|
||||
0, 0x00700000u, 0x00280000u | (static_cast<u32>(htile_address >> 8u) << 24u),
|
||||
static_cast<u32>(htile_address >> 16u)}};
|
||||
const ShaderTextureResource target{{static_cast<u32>(copy_address >> 8u),
|
||||
(static_cast<u32>(Prospero::BufferFormat::k16UInt) << 20u) | (1u << 30u), 1u << 14u,
|
||||
DstSel(4, 5, 6, 7) | (static_cast<u32>(Prospero::TileMode::kLinear) << 20u) |
|
||||
(static_cast<u32>(Prospero::ImageType::kColor2D) << 28u),
|
||||
0, 0x00700000u, 0, 0}};
|
||||
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(copy.data()),
|
||||
.num_thread_x = 2, .num_thread_y = 2, .num_thread_z = 1,
|
||||
.wave_size = 64, .user_sgpr = 16, .tidig_comp_cnt = 1});
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
shaders.SetCsUserSgpr(i, target.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(8u + i, depth_bits.fields[i], HW::UserSgprType::Unknown);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
|
||||
ShaderRecompiler::IR::DescriptorValue value{};
|
||||
value.dword_count = 8;
|
||||
std::copy_n(target.fields, 8, value.dwords.begin());
|
||||
ShaderRecompiler::IR::ImageResource resource{};
|
||||
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Storage;
|
||||
resource.numeric_class = Prospero::TextureNumericClass::Uint;
|
||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||
resource.written = true;
|
||||
const auto binding =
|
||||
RenderExecutorTestAccess::ResolveTexture(context.GetRenderExecutor(), resource, value);
|
||||
Require(name, "raw depth bits",
|
||||
ReadCachedTexel(name, context, binding.image_id, {}, {2, 2, 1}) ==
|
||||
std::vector<u32>(2, depth_code | depth_code << 16u),
|
||||
"the copy did not read the stored D16 codes");
|
||||
Require(name, "depth target retained", TextureCacheTestAccess::Contains(textures, depth_id),
|
||||
"reading depth bits replaced the HTile depth target");
|
||||
context.UnmapMemory(base, allocation_size);
|
||||
scheduler.Finish();
|
||||
});
|
||||
context.ShutdownGpu();
|
||||
LibKernel::Memory::InstallGpuResources(nullptr);
|
||||
Require(name, "unmap", Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0,
|
||||
"depth mapping release failed");
|
||||
Require(name, "release",
|
||||
Libs::LibKernel::Memory::KernelReleaseDirectMemory(direct_offset, allocation_size) == 0,
|
||||
"depth allocation release failed");
|
||||
std::printf("[gpu] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckSampledDccClear() {
|
||||
constexpr const char *name = "SampledDccClear";
|
||||
constexpr uintptr_t base = 0x0000000205000000ull;
|
||||
@@ -37773,6 +37890,39 @@ template <bool rg, bool snorm = false> TestCase ImageSamplePacked8() {
|
||||
return test;
|
||||
}
|
||||
|
||||
// A kDepth k16UInt image load returns the stored D16 codes and integer swizzle constants.
|
||||
TestCase ImageLoadDepthBits() {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = "ImageLoadDepthBits";
|
||||
constexpr std::array<u32, 4> depth{0x2000u, 0xc000u, 0xffffu, 0x0001u};
|
||||
for (u32 texel = 0; texel < depth.size(); ++texel) {
|
||||
AppendVMovU32(&test.code, 20, texel % 2u);
|
||||
AppendVMovU32(&test.code, 21, texel / 2u);
|
||||
test.code.push_back(EncodeMimg0(0x00, 0xf));
|
||||
test.code.push_back(EncodeMimg1(0, 20));
|
||||
for (u32 component = 0; component < 4; ++component) {
|
||||
AppendStoreVgpr(&test.code, component, texel * 4u + component);
|
||||
}
|
||||
test.expected.insert(test.expected.end(), {depth[texel], 0u, 0u, 1u});
|
||||
}
|
||||
AppendEnd(&test.code);
|
||||
test.image_width = test.image_height = 2;
|
||||
test.sampled_image_rgba = {depth[0] | depth[1] << 16u, depth[2] | depth[3] << 16u};
|
||||
test.sampled_image_format = vk::Format::eR16Unorm;
|
||||
test.sampled_image_dwords_per_pixel = 1;
|
||||
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k16UInt);
|
||||
test.user_data[1] |= 1u << 30u;
|
||||
test.user_data[2] = 1u << 14u;
|
||||
test.user_data[3] |= static_cast<u32>(Prospero::TileMode::kDepth) << 20u;
|
||||
test.user_data[50] = test.expected.size() * sizeof(u32);
|
||||
test.user_data[51] = 3u << 28u;
|
||||
test.has_user_data = true;
|
||||
test.image_descriptor_swizzle = DstSel(4, 0, 0, 1);
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_LOAD, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageLoadR128IgnoresAdjacentMaskSgprs() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -43679,6 +43829,7 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(ImageSamplePacked8<false>);
|
||||
AddCase(ImageSamplePacked8<true>);
|
||||
AddCase(ImageSamplePacked8<false, true>);
|
||||
AddCase(ImageLoadDepthBits);
|
||||
AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs);
|
||||
AddCase(ImageLoad1DUsesScalarCoordinate);
|
||||
AddCase(ImageGather2DInstructionWith1DDescriptor);
|
||||
@@ -49719,6 +49870,12 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, ImageSamplePacked8<false, true>());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--depth-bits-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckDepthBitsCopy();
|
||||
RunCase(&vulkan, ImageLoadDepthBits());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--packed-texture-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ImageLoadSintUsesSignedSampledImage<false>());
|
||||
@@ -50610,6 +50767,7 @@ int main(int argc, char **argv) {
|
||||
vulkan.CheckRenderExecutorColorVolumeDiscovery();
|
||||
vulkan.CheckRenderExecutorColorMetadataClear();
|
||||
vulkan.CheckSampledDccClear();
|
||||
vulkan.CheckDepthBitsCopy();
|
||||
vulkan.CheckRenderExecutorColorStandardTileDiscovery();
|
||||
vulkan.CheckRenderExecutorColorDepthTileDiscovery();
|
||||
vulkan.CheckRenderExecutorStencilBindingDiscovery();
|
||||
|
||||
Reference in New Issue
Block a user