From cc5c0ec6b8c6a6adfa7ae7cfa69e9d090f16b2ca Mon Sep 17 00:00:00 2001 From: nmzik Date: Thu, 27 Aug 2026 14:47:17 +0200 Subject: [PATCH] graphics: support PS5 1D color render targets --- .../host_gpu/renderer/colorRenderTarget.cpp | 29 +++-- tests/ShaderRecompilerComputeTests.cpp | 102 ++++++++++++++++++ 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index 081539098..fdd3351be 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -14,6 +14,7 @@ #include "graphics/host_gpu/vulkanCommon.h" #include +#include #include namespace Libs::Graphics { @@ -143,12 +144,23 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& uint32_t pitch = 0; uint64_t size = 0; bool tile = false; - const bool volume = rt.attrib3.dimension == 2; - if (rt.attrib3.dimension != 1 && !volume) { + static constexpr std::array image_types {Prospero::ImageType::kColor1D, + Prospero::ImageType::kColor2D, + Prospero::ImageType::kColor3D}; + if (rt.attrib3.dimension >= image_types.size()) { EXIT("unsupported render-target dimension: %u\n", rt.attrib3.dimension); } + const auto image_type = image_types[rt.attrib3.dimension]; + const bool is_1d = image_type == Prospero::ImageType::kColor1D; + const bool volume = image_type == Prospero::ImageType::kColor3D; + if (is_1d && rt.attrib2.height != 0) { + EXIT("1D render target has nonzero height: %u\n", rt.attrib2.height); + } if (!volume && rt.attrib3.depth != 0) { - EXIT("2D render target has nonzero depth: %u\n", rt.attrib3.depth); + EXIT("non-3D render target has nonzero depth: %u\n", rt.attrib3.depth); + } + if (is_1d && samples != 1) { + EXIT("multisampled 1D render targets are unsupported\n"); } if (volume && samples != 1) { EXIT("multisampled 3D render targets are unsupported\n"); @@ -325,7 +337,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& desc.info.data = {rt.base.addr, backing_size}; desc.info.pixel_format = target_format.format; desc.info.guest_format = transfer_format; - desc.info.type = volume ? Prospero::ImageType::kColor3D : Prospero::ImageType::kColor2D; + desc.info.type = image_type; desc.info.extent = {width, height, depth}; desc.info.resources = {levels, volume ? 1u : view.image_layers}; desc.info.pitch = pitch; @@ -364,8 +376,13 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& }; } desc.view_info.format = target_format.format; - desc.view_info.type = - view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray; + if (is_1d) { + desc.view_info.type = + view.layer_count == 1 ? vk::ImageViewType::e1D : vk::ImageViewType::e1DArray; + } else { + desc.view_info.type = + view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray; + } desc.view_info.aspect = vk::ImageAspectFlagBits::eColor; desc.view_info.base_level = rt.view.current_mip_level; desc.view_info.level_count = 1; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 72e6d564f..2b308a650 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -6997,6 +6997,106 @@ public: std::printf("[gpu] %-32s ok\n", name); } + void CheckRenderExecutorColor1DDiscovery() { + constexpr const char *name = "RenderExecutorColor1DDiscovery"; + constexpr uintptr_t base = 0x0000000203c00000ull; + constexpr uint32_t width = 512; + constexpr uint32_t height = 1; + constexpr uint32_t bytes_per_element = 4; + constexpr uint64_t allocation_alignment = 0x10000; + EnsureRuntimeContext(); + + const auto pitch = + TileGetRenderTargetPitch(width, bytes_per_element, 0); + TileSizeAlign layout{}; + Require(name, "tile layout", + pitch != 0 && TileGetRenderTargetSize( + width, height, pitch, bytes_per_element, layout, 0), + "1D render-target layout is unavailable"); + const auto allocation_size = + std::max(layout.size, allocation_alignment); + + 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, + "1D color direct-memory 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), + "1D color fixed 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 = base}); + registers.SetColorInfo( + 0, {.format = Prospero::ChannelLayout::k8_8_8_8, + .channel_type = Prospero::ChannelType::kSrgb, + .channel_order = Prospero::ChannelOrder::kStandard}); + registers.SetColorAttrib2(0, {.height = height - 1, .width = width - 1}); + registers.SetColorAttrib3(0, + {.tile_mode = Prospero::TileMode::kRenderTarget, + .dimension = 0, + .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); + RenderDepthInfo no_depth{}; + const auto rendering = RenderExecutorTestAccess::AcquireRenderTargets( + executor, scheduler.Current(), &color, 1, no_depth); + scheduler.Current().BeginRendering(rendering); + scheduler.Current().EndRendering(); + Require(name, "captured 1D target", + color.image_id && attachment != nullptr && + color.image_view != nullptr && + color.desc.info.type == Prospero::ImageType::kColor1D && + color.desc.info.extent == vk::Extent3D{width, height, 1} && + color.desc.info.resources == ImageSubresources{1, 1} && + color.desc.info.pitch == pitch && + color.desc.info.data.size == layout.size && + color.desc.view_info.type == vk::ImageViewType::e1D && + image.backing.image_type == vk::ImageType::e1D && + rendering.width == width && rendering.height == height && + rendering.num_layers == 1 && + rendering.num_color_attachments == 1, + "SDK dimension=0 did not create a 512x1 Vulkan attachment"); + + RenderExecutorTestAccess::ResetBindings(executor); + resources.UnmapMemory(base, allocation_size); + scheduler.Finish(); + } + + Require(name, "unmap direct backing", + Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0, + "1D color direct mapping release failed"); + Require(name, "release direct backing", + Libs::LibKernel::Memory::KernelReleaseDirectMemory( + direct_offset, allocation_size) == 0, + "1D color direct-memory allocation release failed"); + std::printf("[gpu] %-32s ok\n", name); + } + void CheckRenderExecutorColorVolumeDiscovery() { constexpr const char *name = "RenderExecutorColorVolumeDiscovery"; constexpr uintptr_t base = 0x0000000203e00000ull; @@ -24237,6 +24337,7 @@ int main(int argc, char **argv) { CheckDepthAttachmentWrites(); CheckDynamicRenderingState(); VulkanHarness vulkan; + vulkan.CheckRenderExecutorColor1DDiscovery(); vulkan.CheckRenderExecutorColorVolumeDiscovery(); vulkan.CheckRenderExecutorColorDepthTileDiscovery(); vulkan.CheckRenderExecutorStencilBindingDiscovery(); @@ -24411,6 +24512,7 @@ int main(int argc, char **argv) { vulkan.CheckStreamBufferRing(); vulkan.CheckGpuTilerCpuParity(); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS + vulkan.CheckRenderExecutorColor1DDiscovery(); vulkan.CheckRenderExecutorColorVolumeDiscovery(); vulkan.CheckRenderExecutorColorStandard4TileDiscovery(); vulkan.CheckRenderExecutorColorDepthTileDiscovery();