diff --git a/src/graphics/guest_gpu/tile.cpp b/src/graphics/guest_gpu/tile.cpp index 63d93be9a..87f325f00 100644 --- a/src/graphics/guest_gpu/tile.cpp +++ b/src/graphics/guest_gpu/tile.cpp @@ -1351,6 +1351,7 @@ uint32_t TileGetTexturePitch(Prospero::BufferFormat format, uint32_t width, } break; } + case Prospero::TileMode::kStandard4KB: case Prospero::TileMode::kStandard64KB: case Prospero::TileMode::kPrt: case Prospero::TileMode::kDepth: diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index dfd84c02b..1ce206272 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -130,12 +130,15 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB if (volume && samples != 1) { EXIT("multisampled 3D render targets are unsupported\n"); } - const uint32_t depth = volume ? rt.attrib3.depth + 1u : 1u; - const bool standard64 = rt.attrib3.tile_mode == Prospero::TileMode::kStandard64KB; - const bool depth_tile = rt.attrib3.tile_mode == Prospero::TileMode::kDepth; + const uint32_t depth = volume ? rt.attrib3.depth + 1u : 1u; + const bool standard4 = rt.attrib3.tile_mode == Prospero::TileMode::kStandard4KB; + const bool standard64 = rt.attrib3.tile_mode == Prospero::TileMode::kStandard64KB; + const bool depth_tile = rt.attrib3.tile_mode == Prospero::TileMode::kDepth; + const bool texture_tile = standard4 || standard64 || depth_tile; switch (rt.attrib3.tile_mode) { case Prospero::TileMode::kLinear: + case Prospero::TileMode::kStandard4KB: case Prospero::TileMode::kStandard64KB: case Prospero::TileMode::kDepth: case Prospero::TileMode::kRenderTarget: @@ -149,8 +152,8 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB if (samples > 1 && (!tile || levels != 1)) { EXIT("multisampled render targets require a single-mip tiled surface\n"); } - if (depth_tile && samples != 1) { - EXIT("depth-tiled color render targets do not support multisampling\n"); + if (texture_tile && samples != 1) { + EXIT("texture-tiled color render targets do not support multisampling\n"); } width = rt.attrib2.width + 1; @@ -162,15 +165,17 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB EXIT("render-target format has no valid element size\n"); } const auto transfer_format = ImageOps::RenderTargetTransferFormat(bytes_per_element); - if ((standard64 || depth_tile) && - (rt.attrib3.dimension != 1 || rt.attrib3.depth != 0 || view.base_layer != 0 || - view.image_layers != 1 || samples != 1 || rt.pitch.pitch_div8_minus1 != 0 || - (rt.base.addr & 0xffffu) != 0 || rt.info.fmask_compression_enable || - rt.info.fmask_data_compression_disable || rt.info.fmask_one_frag_mode || - rt.info.cmask_fast_clear_enable || rt.info.dcc_compression_enable || - rt.info.cmask_is_linear != 0 || rt.info.cmask_addr_type != 0 || rt.info.alt_tile_mode || - rt.cmask.addr != 0 || rt.fmask.addr != 0 || rt.dcc_addr.addr != 0 || - rt.dcc.data_write_on_dcc_clear_to_reg)) { + TileTextureBlockLayout texture_tile_layout {}; + if (texture_tile && + (!TileGetTextureBlockLayout(transfer_format, rt.attrib3.tile_mode, volume, + texture_tile_layout) || + rt.pitch.pitch_div8_minus1 != 0 || + (rt.base.addr & (texture_tile_layout.block.block_size - 1u)) != 0 || + rt.info.fmask_compression_enable || rt.info.fmask_data_compression_disable || + rt.info.fmask_one_frag_mode || rt.info.cmask_fast_clear_enable || + rt.info.dcc_compression_enable || rt.info.cmask_is_linear != 0 || + rt.info.cmask_addr_type != 0 || rt.info.alt_tile_mode || rt.cmask.addr != 0 || + rt.fmask.addr != 0 || rt.dcc_addr.addr != 0 || rt.dcc.data_write_on_dcc_clear_to_reg)) { EXIT("unsupported texture-tiled render target: addr=0x%016" PRIx64 " tile=%u" " dimension=%u depth=%u levels=%u layer=%u/%u samples=%u fragments=%u bpe=%u" " cmask=0x%016" PRIx64 " fmask=0x%016" PRIx64 " dcc=0x%016" PRIx64 "\n", @@ -179,12 +184,18 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB rt.attrib.num_fragments, bytes_per_element, rt.cmask.addr, rt.fmask.addr, rt.dcc_addr.addr); } + if ((standard64 || depth_tile) && (rt.attrib3.dimension != 1 || rt.attrib3.depth != 0 || + view.base_layer != 0 || view.image_layers != 1)) { + EXIT("unsupported 64KB texture-tiled render-target view: dimension=%u depth=%u" + " layer=%u/%u\n", + rt.attrib3.dimension, rt.attrib3.depth, view.base_layer, view.image_layers); + } if (rt.pitch.pitch_div8_minus1 != 0) { pitch = (rt.pitch.pitch_div8_minus1 + 1u) << 3u; } else if (tile) { if (volume) { pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode); - } else if (standard64 || depth_tile) { + } else if (texture_tile) { pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode); } else { pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments); @@ -218,10 +229,10 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB } else if (tile) { TileSizeAlign layout {}; bool valid_layout = false; - if (standard64 || depth_tile) { + if (texture_tile) { TileGetTextureSize(transfer_format, width, height, levels, rt.attrib3.tile_mode, &layout, mip_sizes, mip_padded); - valid_layout = layout.size != 0 && layout.align == 65536; + valid_layout = layout.size != 0 && layout.align == texture_tile_layout.block.block_size; } else { valid_layout = levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index f3974bbc3..d78c0d0a9 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -6266,6 +6266,109 @@ public: std::printf("[gpu] %-32s ok\n", name); } + void CheckRenderExecutorColorStandard4TileDiscovery() { + constexpr const char *name = "RenderExecutorColorStandard4Tile"; + constexpr uintptr_t base = 0x0000000203b00000ull; + constexpr uint64_t target_address = base + 0x4000; + constexpr uint64_t target_size = 0x180000; + constexpr uint64_t allocation_size = 0x184000; + constexpr uint64_t allocation_alignment = 0x4000; + constexpr auto format = Prospero::BufferFormat::k32Float; + constexpr auto tile = Prospero::TileMode::kStandard4KB; + EnsureRuntimeContext(); + + const auto pitch = TileGetTexturePitch(format, 256, tile); + TileSizeAlign slice{}; + TileGetTextureSize(format, 256, 256, 1, tile, &slice, nullptr, nullptr); + const auto odd_pitch = TileGetTexturePitch(format, 257, tile); + TileSizeAlign odd_slice{}; + TileGetTextureSize(format, 257, 131, 1, tile, &odd_slice, nullptr, nullptr); + Require(name, "tile layout", + pitch == 256 && slice.size == 0x40000 && slice.align == 0x1000 && + odd_pitch == 288 && odd_slice.size == 0x2d000 && + odd_slice.align == 0x1000, + "Standard4KB pitch, footprint, or block alignment is incorrect"); + + int64_t direct_offset = -1; + Require(name, "direct allocation", + Libs::LibKernel::Memory::KernelAllocateDirectMemory( + 0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(), + allocation_size, allocation_alignment, 0, &direct_offset) == 0, + "Standard4KB color allocation failed"); + void *mapped = reinterpret_cast(base); + Require(name, "direct mapping", + Libs::LibKernel::Memory::KernelMapDirectMemory( + &mapped, allocation_size, 0x3, 0x10, direct_offset, + allocation_alignment) == 0 && + mapped == reinterpret_cast(base), + "Standard4KB color mapping failed"); + std::memset(mapped, 0, allocation_size); + + { + RenderContext context(m_runtime_context); + auto &scheduler = context.GetCommandScheduler(); + HW::Context registers{}; + HW::UserConfig user_config{}; + HW::Shader shaders{}; + registers.SetColorBase(0, {.addr = target_address}); + registers.SetColorInfo( + 0, {.format = Prospero::ChannelLayout::k32, + .channel_type = Prospero::ChannelType::kFloat, + .channel_order = Prospero::ChannelOrder::kStandard}); + registers.SetColorView( + 0, {.base_array_slice_index = 5, .last_array_slice_index = 5}); + registers.SetColorAttrib2(0, {.height = 255, .width = 255}); + registers.SetColorAttrib3(0, {.tile_mode = tile, + .dimension = 1, + .cmask_pipe_aligned = true, + .dcc_pipe_aligned = true}); + registers.SetRenderTargetMask(0x0f); + scheduler.Begin(registers, user_config, shaders); + + auto &resources = context.GetGpuResources(); + auto &texture_cache = resources.GetTextureCache(); + auto &executor = context.GetRenderExecutor(); + resources.MapMemory(base, allocation_size); + + RenderColorInfo color{}; + RenderExecutorTestAccess::ResolveRenderColorTarget( + executor, 1, scheduler.Current(), color, 0); + const auto attachment = + texture_cache.FindRenderTarget(color.image_id, color.desc); + const auto &image = texture_cache.GetImage(color.image_id); + Require(name, "captured target", + color.image_id && attachment != nullptr && + color.base_array_layer == 5 && + color.desc.info.data.address == target_address && + color.desc.info.data.size == target_size && + color.desc.info.tile_mode == tile && + color.desc.info.extent == vk::Extent3D{256, 256, 1} && + color.desc.info.resources == ImageSubresources{1, 6} && + color.desc.info.pitch == pitch && + color.desc.info.mip_layout[0].offset == 0 && + color.desc.info.mip_layout[0].size == target_size && + color.desc.view_info.type == vk::ImageViewType::e2D && + color.desc.view_info.base_layer == 5 && + color.desc.view_info.layer_count == 1 && + (target_address & 0xffffu) == 0x4000 && + image.usage.render_target && image.IsGpuModified(), + "slice 5 Standard4KB render target was not resolved"); + + RenderExecutorTestAccess::ResetBindings(executor); + resources.UnmapMemory(base, allocation_size); + scheduler.Finish(); + } + + Require(name, "unmap direct backing", + Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0, + "Standard4KB color mapping release failed"); + Require(name, "release direct backing", + Libs::LibKernel::Memory::KernelReleaseDirectMemory( + direct_offset, allocation_size) == 0, + "Standard4KB color allocation release failed"); + std::printf("[gpu] %-32s ok\n", name); + } + void CheckRenderExecutorColorDepthTileDiscovery() { constexpr const char *name = "RenderExecutorColorDepthTile"; constexpr uintptr_t base = 0x0000000203d00000ull; @@ -21177,6 +21280,11 @@ int main(int argc, char **argv) { CheckStandard64RenderTargetTileRoundTrip(); return 0; } + if (argc == 2 && std::strcmp(argv[1], "--standard4-rt-only") == 0) { + VulkanHarness vulkan; + vulkan.CheckRenderExecutorColorStandard4TileDiscovery(); + return 0; + } if (argc == 2 && std::strcmp(argv[1], "--image-view-only") == 0) { VulkanHarness vulkan; CheckSampledColorViews(); @@ -21286,6 +21394,7 @@ int main(int argc, char **argv) { vulkan.CheckGpuTilerCpuParity(); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS vulkan.CheckRenderExecutorColorVolumeDiscovery(); + vulkan.CheckRenderExecutorColorStandard4TileDiscovery(); vulkan.CheckRenderExecutorColorDepthTileDiscovery(); vulkan.CheckRenderExecutorStencilBindingDiscovery(); vulkan.CheckUnifiedTextureCacheFlow();