From dda628ca8174a6ff52e2fdac4304c2213a4fea79 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 6 Sep 2026 04:05:35 +0400 Subject: [PATCH] render: simplify command and resource ownership --- .../host_gpu/renderer/colorRenderTarget.cpp | 40 +-- .../host_gpu/renderer/colorRenderTarget.h | 24 +- .../host_gpu/renderer/commandScheduler.cpp | 14 +- .../host_gpu/renderer/commandScheduler.h | 6 +- src/graphics/host_gpu/renderer/debug.cpp | 10 +- .../host_gpu/renderer/depthRenderTarget.cpp | 39 +-- .../host_gpu/renderer/depthRenderTarget.h | 21 +- .../renderer/pipeline/descriptors.cpp | 91 +++--- .../host_gpu/renderer/pipeline/descriptors.h | 34 ++- .../renderer/pipeline/pipelineCache.cpp | 77 ++--- .../renderer/pipeline/pipelineCache.h | 51 +--- .../pipeline/shaderResourceBarrier.cpp | 29 +- .../renderer/pipeline/shaderResourceBarrier.h | 12 - .../host_gpu/renderer/pipeline/shaders.cpp | 39 +-- src/graphics/host_gpu/renderer/renderDraw.cpp | 144 ++++------ src/graphics/host_gpu/vma.cpp | 4 +- tests/ShaderRecompilerComputeTests.cpp | 268 ++++++++++-------- tests/shaderCfgTests.cpp | 21 +- 18 files changed, 386 insertions(+), 538 deletions(-) diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index 81f118118..9fd0e66c3 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -75,8 +75,8 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& mask = 0x0f; } - r.target_slot = rt_slot; - r.export_mapping = {}; + r = {}; + r.target_slot = rt_slot; if (rt.base.addr == 0 || mask == 0) { if (graphics_debug_dump_enabled()) { @@ -91,23 +91,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& } } - // No color output - r.type = RenderColorType::NoColorOutput; - r.desc = {}; - r.base_addr = 0; - r.image_id = {}; - r.image_view = nullptr; - r.format = vk::Format::eUndefined; - r.extent = {}; - r.base_mip_level = 0; - r.base_array_layer = 0; - r.buffer_size = 0; - r.samples = 1; - r.export_mapping = {}; - r.color_clear_enable = false; - r.metadata_clear_supported = false; - r.metadata_fixed_clear_supported = false; - r.color_clear_value = {}; return; } const auto samples = render_sample_count(rt.attrib.num_fragments); @@ -158,7 +141,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& rt.view.base_array_slice_index, rt.view.last_array_slice_index, render_target_slice_offset); } - r.base_array_layer = view.base_layer; if (graphics_debug_dump_enabled()) { static std::atomic_uint log_count = 0; const auto log_id = log_count.fetch_add(1, std::memory_order_relaxed); @@ -179,9 +161,6 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& // Nonlinear clear values are still stored as normalized components. // Fast color clears are metadata driven and must be handled explicitly when // that metadata path is implemented; render-pass load must preserve contents. - r.color_clear_enable = false; - r.color_clear_value = {}; - uint32_t width = 0; uint32_t height = 0; uint32_t pitch = 0; @@ -246,9 +225,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& rt.attrib3.dimension, rt.attrib3.depth, view.base_layer, view.image_layers); } if (tile) { - if (volume) { - pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode); - } else if (texture_tile) { + if (volume || texture_tile) { pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode); } else { pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments); @@ -397,17 +374,10 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer& desc.view_info.usage = vk::ImageUsageFlagBits::eColorAttachment; auto& texture_cache = m_context.GetTextureCache(); r.desc = std::move(desc); + r.guest_mip_level = rt.view.current_mip_level; + r.guest_array_layer = view.base_layer; r.image_id = texture_cache.FindImage(r.desc, exact_format); - r.type = RenderColorType::RenderTexture; - r.base_addr = rt.base.addr; - r.image_view = nullptr; - r.format = r.desc.view_info.format; - r.extent = view_extent; - r.base_mip_level = rt.view.current_mip_level; - r.buffer_size = backing_size; - r.samples = samples; r.export_mapping = target_format.export_mapping; - r.color_clear_enable = false; ResolveDccClearInfo(r, target_format.format, has_dcc, rt.clear_word0.word0); BindRenderTarget(r.image_id); } diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.h b/src/graphics/host_gpu/renderer/colorRenderTarget.h index 7b3b24eb0..6a02634d9 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.h +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.h @@ -6,33 +6,27 @@ #include "graphics/host_gpu/renderer/renderTarget.h" #include "graphics/host_gpu/vulkanCommon.h" +#include #include namespace Libs::Graphics { -enum class RenderColorType { - NoColorOutput, - RenderTexture, -}; - struct RenderColorInfo { - RenderColorType type = RenderColorType::NoColorOutput; + // Discovery keeps guest image information but can remap the view into a larger cache image. TextureCache::ImageDesc desc; ImageId image_id; - vk::ImageView image_view = nullptr; - vk::Format format = vk::Format::eUndefined; - vk::Extent2D extent = {}; - uint32_t base_mip_level = 0; - uint32_t base_array_layer = 0; - uint64_t base_addr = 0; - uint64_t buffer_size = 0; uint32_t target_slot = 0; - uint32_t samples = 1; + uint32_t guest_mip_level = 0; + uint32_t guest_array_layer = 0; Prospero::ColorComponentMapping export_mapping; - bool color_clear_enable = false; bool metadata_clear_supported = false; bool metadata_fixed_clear_supported = false; vk::ClearColorValue color_clear_value {}; + + [[nodiscard]] vk::Extent2D Extent() const { + return {std::max(desc.info.extent.width >> guest_mip_level, 1u), + std::max(desc.info.extent.height >> guest_mip_level, 1u)}; + } }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/commandScheduler.cpp b/src/graphics/host_gpu/renderer/commandScheduler.cpp index bc3664574..231948d86 100644 --- a/src/graphics/host_gpu/renderer/commandScheduler.cpp +++ b/src/graphics/host_gpu/renderer/commandScheduler.cpp @@ -148,14 +148,10 @@ void CommandScheduler::Begin(HW::Context& registers, HW::UserConfig& user_config std::lock_guard lock(m_operation_mutex); EXIT_IF(m_operation_state != OperationState::Open); } - m_registers = ®isters; - m_user_config = &user_config; - m_shaders = &shaders; + m_command.Bind(registers, user_config, shaders); if (m_command.IsInvalid()) { BeginNext(); - } else { - BindCurrent(); } } @@ -346,11 +342,6 @@ CommandBuffer& CommandScheduler::Current() { return m_command; } -void CommandScheduler::BindCurrent() { - EXIT_IF(m_registers == nullptr || m_user_config == nullptr || m_shaders == nullptr); - m_command.Bind(*m_registers, *m_user_config, *m_shaders); -} - CommandBuffer& CommandScheduler::BeginCommand() { EXIT_IF(!m_command.IsInvalid()); m_command.m_buffer = m_command_pool.Commit(); @@ -407,8 +398,7 @@ uint64_t CommandScheduler::Submit(SubmitInfo submit) { } void CommandScheduler::BeginNext() { - EXIT_IF(!m_command.IsInvalid()); - BindCurrent(); + CheckActive(); BeginCommand(); } diff --git a/src/graphics/host_gpu/renderer/commandScheduler.h b/src/graphics/host_gpu/renderer/commandScheduler.h index 48afb1af8..8b4030eba 100644 --- a/src/graphics/host_gpu/renderer/commandScheduler.h +++ b/src/graphics/host_gpu/renderer/commandScheduler.h @@ -42,7 +42,7 @@ public: void DeferPriorityOperation(Common::UniqueFunction&& operation); [[nodiscard]] static bool InDeferredOperation() noexcept; - [[nodiscard]] bool Active() const noexcept { return m_registers != nullptr; } + [[nodiscard]] bool Active() const noexcept { return m_command.m_registers != nullptr; } void CheckActive() const; CommandBuffer& Current(); [[nodiscard]] uint64_t CurrentTick() const noexcept { return m_master.CurrentTick(); } @@ -80,7 +80,6 @@ private: uint64_t tick = 0; }; - void BindCurrent(); void BeginNext(); void PopPendingOperations(bool refresh_gpu_tick); void PriorityOperationsThread(std::stop_token stop); @@ -99,9 +98,6 @@ private: bool m_priority_active = false; uint64_t m_priority_active_tick = 0; OperationState m_operation_state = OperationState::Open; - HW::Context* m_registers = nullptr; - HW::UserConfig* m_user_config = nullptr; - HW::Shader* m_shaders = nullptr; }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/debug.cpp b/src/graphics/host_gpu/renderer/debug.cpp index 1857800a4..e42bca445 100644 --- a/src/graphics/host_gpu/renderer/debug.cpp +++ b/src/graphics/host_gpu/renderer/debug.cpp @@ -402,7 +402,6 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc, EXIT_NOT_IMPLEMENTED(!z.z_info.HasValidTextureCompatibility()); EXIT_NOT_IMPLEMENTED(!z.stencil_info.HasValidTextureCompatibility()); if (z.z_info.format == Prospero::DepthFormat::kInvalid) { - EXIT_NOT_IMPLEMENTED(z.z_info.format != Prospero::DepthFormat::kInvalid); EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0); EXIT_NOT_IMPLEMENTED(z.z_info.htile_acceleration != false); EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); @@ -424,14 +423,11 @@ static void ZCheck(const HW::DepthRenderTarget& z, const HW::DepthControl& dc, EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0); } - if (z.stencil_info.format == Prospero::StencilFormat::kInvalid) { - EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); - EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false); - } else { + if (z.stencil_info.format != Prospero::StencilFormat::kInvalid) { EXIT_NOT_IMPLEMENTED(z.stencil_info.format != Prospero::StencilFormat::k8UInt); - EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); - EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false); } + EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); + EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false); if (z.z_info.format != Prospero::DepthFormat::kInvalid || z.stencil_info.format != Prospero::StencilFormat::kInvalid) { diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index a137a7787..810b379e8 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -203,8 +203,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer& DepthFatal("unsupported depth/stencil format pair"); } const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil); - r.format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples); - if (r.format == vk::Format::eUndefined) { + const auto format = ResolveHostDepthAttachmentFormat(buffer, *policy, has_stencil, samples); + if (format == vk::Format::eUndefined) { DepthFatal("no host depth/stencil format supports required usage for %s", VulkanToString(ideal_format).c_str()); } @@ -234,16 +234,6 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer& (has_htile && !GuestRange {z.htile_data_base_addr, htile_backing_size}.Valid())) { DepthFatal("layered depth backing range is invalid"); } - r.htile = has_htile; - r.width = width; - r.height = height; - r.samples = samples; - r.depth_buffer_size = depth_backing_size; - r.depth_buffer_vaddr = z.z_read_base_addr; - r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0; - r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0; - r.htile_buffer_size = has_htile ? htile_backing_size : 0; - r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; r.depth_clear_enable = rc.depth_clear_enable; r.depth_meta_clear_enable = false; r.depth_load_clear_enable = r.depth_clear_enable; @@ -294,18 +284,12 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer& r.stencil_dynamic_back = r.stencil_dynamic_front; } } - r.vaddr_num = has_stencil ? 2 : 1; - r.vaddr[0] = r.depth_buffer_vaddr; - r.size[0] = r.depth_buffer_size; - if (has_stencil) { - r.vaddr[1] = r.stencil_buffer_vaddr; - r.size[1] = r.stencil_buffer_size; - } TextureCache::ImageDesc desc {}; desc.type = TextureCache::BindingType::DepthTarget; - desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size}; - desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size}; - desc.info.pixel_format = r.format; + desc.info.data = {z.z_read_base_addr, depth_backing_size}; + desc.info.stencil = + has_stencil ? GuestRange {z.stencil_read_base_addr, stencil_backing_size} : GuestRange {}; + desc.info.pixel_format = format; desc.info.guest_format = guest_format; desc.info.type = Prospero::ImageType::kColor2D; desc.info.extent = {width, height, 1}; @@ -314,15 +298,16 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer& desc.info.bytes_per_block = bytes; desc.info.samples = samples; desc.info.tile_mode = Prospero::TileMode::kDepth; - desc.info.mip_layout[0] = {0, r.depth_buffer_size, pitch, height}; - desc.info.metadata.range = {r.htile_buffer_vaddr, r.htile_buffer_size}; + desc.info.mip_layout[0] = {0, depth_backing_size, pitch, height}; + desc.info.metadata.range = + has_htile ? GuestRange {z.htile_data_base_addr, htile_backing_size} : GuestRange {}; desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None; desc.info.metadata.stencil_compressed = has_stencil && has_htile && !z.stencil_info.htile_stencil_disabled; - desc.view_info.format = r.format; + desc.view_info.format = format; desc.view_info.type = view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray; - desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format); + desc.view_info.aspect = ImageViewOps::DepthAspectMask(format); desc.view_info.base_level = 0; desc.view_info.level_count = 1; desc.view_info.base_layer = view.base_layer; @@ -331,11 +316,11 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer& r.desc = std::move(desc); auto& cache = m_context.GetTextureCache(); r.image_id = cache.FindImage(r.desc); - r.image_view = nullptr; BindRenderTarget(r.image_id); } vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const { + const auto format = desc.view_info.format; if (format == vk::Format::eUndefined) { return {}; } diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.h b/src/graphics/host_gpu/renderer/depthRenderTarget.h index 8892a366a..65500ee8b 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.h +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.h @@ -19,21 +19,8 @@ inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stenc } struct RenderDepthInfo { + // Discovery keeps guest image information but can remap the view into a larger cache image. TextureCache::ImageDesc desc; - vk::Format format = vk::Format::eUndefined; - uint32_t width = 0; - uint32_t height = 0; - uint32_t samples = 1; - bool htile = false; - uint64_t depth_buffer_size = 0; - uint64_t depth_buffer_vaddr = 0; - uint64_t depth_tile_swizzle = 0; - uint64_t stencil_buffer_size = 0; - uint64_t stencil_buffer_vaddr = 0; - uint64_t stencil_tile_swizzle = 0; - uint64_t htile_buffer_size = 0; - uint64_t htile_buffer_vaddr = 0; - uint64_t htile_tile_swizzle = 0; bool depth_clear_enable = false; bool depth_load_clear_enable = false; bool depth_meta_clear_enable = false; @@ -52,10 +39,6 @@ struct RenderDepthInfo { PipelineStencilDynamicState stencil_dynamic_front; PipelineStencilDynamicState stencil_dynamic_back; ImageId image_id; - vk::ImageView image_view = nullptr; - uint64_t vaddr[3] = {}; - uint64_t size[3] = {}; - int vaddr_num = 0; [[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const; }; @@ -65,7 +48,7 @@ inline bool depth_attachment_read_only(const RenderDepthInfo& depth) { } inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) { - const auto available = ImageViewOps::DepthAspectMask(depth.format); + const auto available = ImageViewOps::DepthAspectMask(depth.desc.view_info.format); const auto writes = depth.AttachmentWriteAspects(); const bool has_depth = static_cast(available & vk::ImageAspectFlagBits::eDepth); const bool has_stencil = static_cast(available & vk::ImageAspectFlagBits::eStencil); diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 4329e38fa..b2667132c 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -108,12 +108,6 @@ static vk::ShaderStageFlags NativeShaderStage(ShaderType stage) { } } -static void BindNullStorageBuffer(RenderContext& context, BufferView& dst) { - dst.buffer = context.GetBufferCache().GetBuffer(NULL_BUFFER_ID).Handle(); - dst.offset = 0; - dst.range = 16; -} - static Prospero::ImageType TextureType(const ShaderTextureResource& descriptor) { const auto type = descriptor.Type(); return type == Prospero::ImageType::kCube ? Prospero::ImageType::kColor2DArray : type; @@ -134,31 +128,20 @@ static bool IsMultisampledTexture(Prospero::ImageType type) { type == Prospero::ImageType::kColor2DMsaaArray; } -static BufferView NativeStorageBuffer(RenderContext& context, - const ShaderBufferResource& descriptor, - const ShaderRecompiler::IR::BufferResource& resource, - ShaderType stage, uint32_t slot, uint32_t& buffer_offset, - BufferId id) { - BufferView result; +static vk::DescriptorBufferInfo +NativeStorageBuffer(RenderContext& context, const PreparedBindings::BufferSource& source, + const ShaderRecompiler::IR::BufferResource& resource, ShaderType stage, + uint32_t slot, uint32_t& buffer_offset) { buffer_offset = 0; - const auto address = descriptor.Base48(); - const auto stride = descriptor.Stride(); - const auto records = descriptor.NumRecords(); - if (stride != 0 && records > UINT64_MAX / stride) { - EXIT("storage buffer descriptor footprint overflow\n"); + const auto& [address, size, id] = source; + if (address == 0 || size == 0) { + return {context.GetBufferCache().GetBuffer(NULL_BUFFER_ID).Handle(), 0, 16}; } - const auto requested_size = stride != 0 ? static_cast(stride) * records : records; - if (address == 0 || requested_size == 0) { - BindNullStorageBuffer(context, result); - return result; - } - const auto size = Libs::LibKernel::Memory::ClampRangeSize(address, requested_size); const auto& graphics = context.GetGraphics(); const auto alignment = graphics.StorageMinAlignment(); - if (alignment == 0 || - size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) { - EXIT("storage buffer range or device alignment is unsupported\n"); + if (size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) { + EXIT("storage buffer range is unsupported\n"); } auto [buffer, offset] = context.GetBufferCache().ObtainBuffer(address, size, resource.written, resource.formatted, id); @@ -169,9 +152,7 @@ static BufferView NativeStorageBuffer(RenderContext& EXIT("storage buffer offset adjustment is unsupported\n"); } buffer_offset = static_cast(adjustment); - result.buffer = buffer->Handle(); - result.offset = aligned_offset; - result.range = static_cast(size + adjustment); + const vk::DescriptorBufferInfo result {buffer->Handle(), aligned_offset, size + adjustment}; if (resource.formatted && resource.written) { context.GetTextureCache().InvalidateMemoryFromGPU(address, size); } @@ -820,13 +801,14 @@ static vk::Sampler NativeSampler(RenderContext& context, return context.GetSamplerCache().GetSampler(descriptor); } -static BufferView NativeUpload(RenderContext& context, std::span data) { +static vk::DescriptorBufferInfo NativeUpload(RenderContext& context, + std::span data) { EXIT_IF(data.empty()); auto& command_buffer = context.GetCommandScheduler().Current(); EXIT_IF(command_buffer.IsInvalid()); auto& buffer = context.GetBufferCache().GetUtilityBuffer(MemoryUsage::Stream); const auto offset = buffer.Copy(data.data(), data.size_bytes(), 256); - return {.buffer = buffer.Handle(), .offset = offset, .range = data.size_bytes()}; + return {buffer.Handle(), offset, data.size_bytes()}; } void RenderExecutor::TrackImageBinding(ImageId id) { @@ -872,17 +854,15 @@ PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runti PreparedBindings prepared; prepared.program = runtime.program; prepared.snapshot = &runtime.resources; - auto& descriptors = prepared.resources; - descriptors.buffers.reserve(program.info.buffers.size()); - descriptors.images.reserve(program.info.images.size()); + prepared.images.reserve(program.info.images.size()); for (uint32_t i = 0; i < program.info.images.size(); i++) { auto binding = ResolveTexture(program.info.images[i], snapshot.images[i]); BindImage(binding.image_id, binding.desc.type == TextureCache::BindingType::Storage); - descriptors.images.push_back(binding); + prepared.images.push_back(std::move(binding)); } - descriptors.samplers.reserve(program.info.samplers.size()); + prepared.samplers.reserve(program.info.samplers.size()); for (uint32_t i = 0; i < program.info.samplers.size(); i++) { - descriptors.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i])); + prepared.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i])); } prepared.shader_data.reserve(program.bindings.ShaderDataDwords()); for (const auto reg: program.bindings.user_data_registers) { @@ -891,7 +871,7 @@ PreparedBindings RenderExecutor::PrepareBindings(const ShaderStageRuntime& runti prepared.shader_data.resize(program.bindings.ShaderDataDwords()); if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) { - descriptors.gds.buffer = m_context.GetBufferCache().GetGdsBuffer()->Handle(); + prepared.gds.buffer = m_context.GetBufferCache().GetGdsBuffer()->Handle(); } return prepared; } @@ -910,16 +890,15 @@ void RenderExecutor::FindBuffers(PreparedBindings& prepared) { const auto address = descriptor.Base48(); const auto stride = descriptor.Stride(); const auto records = descriptor.NumRecords(); - EXIT_IF(stride != 0 && records > UINT64_MAX / stride); + // The descriptor has a 14-bit stride and 32-bit record count, so the product fits u64. const auto requested_size = stride != 0 ? static_cast(stride) * records : records; if (address == 0 || requested_size == 0) { - prepared.buffer_sources.emplace_back(descriptor, BufferId {}); + prepared.buffer_sources.push_back({}); continue; } const auto size = Libs::LibKernel::Memory::ClampRangeSize(address, requested_size); - prepared.buffer_sources.emplace_back(descriptor, cache.FindBuffer(address, size)); + prepared.buffer_sources.push_back({address, size, cache.FindBuffer(address, size)}); } - } void RenderExecutor::RebindBuffers(PreparedBindings& prepared) { @@ -927,12 +906,11 @@ void RenderExecutor::RebindBuffers(PreparedBindings& prepared) { EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); const auto& program = *prepared.program; const auto& snapshot = *prepared.snapshot; - auto& resources = prepared.resources; const auto& layout = program.bindings; EXIT_IF(prepared.buffer_sources.size() != program.info.buffers.size()); - resources.buffers.clear(); - resources.buffers.reserve(program.info.buffers.size()); + prepared.buffers.clear(); + prepared.buffers.reserve(program.info.buffers.size()); EXIT_IF(prepared.shader_data.size() != layout.ShaderDataDwords()); std::fill(prepared.shader_data.begin() + layout.memory_offset_dword, prepared.shader_data.end(), 0); @@ -942,20 +920,19 @@ void RenderExecutor::RebindBuffers(PreparedBindings& prepared) { prepared.shader_data[dword] |= offset << shift; }; for (uint32_t i = 0; i < program.info.buffers.size(); i++) { - const auto& [descriptor, buffer_id] = prepared.buffer_sources[i]; uint32_t buffer_offset = 0; - resources.buffers.push_back(NativeStorageBuffer(m_context, descriptor, - program.info.buffers[i], program.stage, i, - buffer_offset, buffer_id)); + prepared.buffers.push_back(NativeStorageBuffer(m_context, prepared.buffer_sources[i], + program.info.buffers[i], program.stage, i, + buffer_offset)); pack_memory_offset(i, buffer_offset); } if (ShaderRecompiler::IR::FindBinding( layout, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != nullptr) { - resources.flattened_srt = NativeUpload(m_context, snapshot.flattened_srt); + prepared.flattened_srt = NativeUpload(m_context, snapshot.flattened_srt); } if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::ShaderData) != nullptr) { - resources.shader_data = NativeUpload(m_context, prepared.shader_data); + prepared.shader_data_buffer = NativeUpload(m_context, prepared.shader_data); } } @@ -964,7 +941,7 @@ void RenderExecutor::RebindImages(PreparedBindings& prepared) { EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); const auto& program = *prepared.program; const auto& snapshot = *prepared.snapshot; - auto& images = prepared.resources.images; + auto& images = prepared.images; EXIT_IF(images.size() != program.info.images.size()); auto& texture_cache = m_context.GetTextureCache(); for (uint32_t i = 0; i < program.info.images.size(); i++) { @@ -1075,7 +1052,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, for (auto* prepared: prepared_bindings) { const auto& program = *prepared->program; - auto& descriptors = prepared->resources; + auto& descriptors = *prepared; const auto shader_stage = NativeShaderStage(program.stage); const auto shader_stages = ShaderPipelineStages(shader_stage); if (descriptors.gds.buffer != nullptr) { @@ -1165,7 +1142,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, for (const auto resource: binding.resources) { const auto& view = descriptors.buffers.at(resource); EXIT_IF(view.buffer == nullptr); - m_descriptor_buffers.emplace_back(view.buffer, view.offset, view.range); + m_descriptor_buffers.push_back(view); } break; case BindingKind::BdaPagetable: @@ -1181,14 +1158,14 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, case BindingKind::FlattenedSrt: case BindingKind::ShaderData: case BindingKind::Gds: { - const BufferView* view = &descriptors.gds; + const vk::DescriptorBufferInfo* view = &descriptors.gds; if (binding.kind == BindingKind::FlattenedSrt) { view = &descriptors.flattened_srt; } else if (binding.kind == BindingKind::ShaderData) { - view = &descriptors.shader_data; + view = &descriptors.shader_data_buffer; } EXIT_IF(view->buffer == nullptr); - m_descriptor_buffers.emplace_back(view->buffer, view->offset, view->range); + m_descriptor_buffers.push_back(*view); break; } case BindingKind::Samplers: diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.h b/src/graphics/host_gpu/renderer/pipeline/descriptors.h index e5b8af02d..4c5519856 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.h +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.h @@ -20,12 +20,6 @@ namespace ShaderRecompiler::IR { struct ResourceSnapshot; } -struct BufferView { - vk::Buffer buffer = nullptr; - vk::DeviceSize offset = 0; - vk::DeviceSize range = VK_WHOLE_SIZE; -}; - struct TextureBinding { ImageId image_id; vk::ImageView image_view = nullptr; @@ -34,21 +28,25 @@ struct TextureBinding { std::vector mip_views; }; -struct NativeDescriptors { - std::vector buffers; - std::vector images; - std::vector samplers; - BufferView gds; - BufferView flattened_srt; - BufferView shader_data; -}; - struct PreparedBindings { + struct BufferSource { + uint64_t address = 0; + uint64_t size = 0; + BufferId id; + }; + const ShaderRecompiler::IR::CompiledShaderInfo* program = nullptr; const ShaderRecompiler::IR::ResourceSnapshot* snapshot = nullptr; - NativeDescriptors resources; - std::vector> buffer_sources; - std::vector shader_data; + // Keep the resolved guest range through cache preparation; only the host buffer ID may + // become stale and need resolving again when bindings are rebound. + std::vector buffer_sources; + std::vector buffers; + std::vector images; + std::vector samplers; + vk::DescriptorBufferInfo gds {nullptr, 0, VK_WHOLE_SIZE}; + vk::DescriptorBufferInfo flattened_srt; + vk::DescriptorBufferInfo shader_data_buffer; + std::vector shader_data; }; [[nodiscard]] vk::DescriptorType diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp index 2608ce715..167848e83 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp @@ -343,7 +343,7 @@ struct PipelineCache::ProgramCache { input_info.stage = {.program = &permutation.program, .resources = std::move(resources)}; permutation.program.bindings.AdvancePushData(push_data_cursor); - std::printf("Num compiled %u shaders\n", ++num_compiled); + std::printf("Num compiled %" PRIu64 " shaders\n", next_shader_id); return permutation.handle; } @@ -362,7 +362,6 @@ struct PipelineCache::ProgramCache { std::unordered_map programs; ProgramKey lookup_key; vk::Device device; - uint32_t num_compiled = 0; uint64_t next_shader_id = 0; }; @@ -602,7 +601,7 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) return std::memcmp(this, &other, sizeof(*this)) == 0; } -PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( +PipelineCache::Pipeline& PipelineCache::CreateGraphicsPipeline( std::span colors, const RenderDepthInfo& depth, const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command, const ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, @@ -619,47 +618,42 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( Common::LockGuard lock(m_mutex); auto& ctx = command.GetRegisters(); - uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; - for (uint32_t i = 0; i < color_count; i++) { - color_mask[i] = - (colors[i].image_id ? colors[i].export_mapping.ApplyMask(render_target_mask_slot( - ctx.GetRenderTargetMask(), colors[i].target_slot)) - : 0); - } const HW::ModeControl& mc = ctx.GetModeControl(); const auto vs_id = vertex_program.id; const auto ps_id = ps_active ? pixel_program.id : 0; PipelineStaticParameters static_params {}; - - static_params.color_count = color_count; - PipelineRenderingState rendering {}; + PipelineRenderingState rendering {}; rendering.color_count = color_count; uint32_t attachment_samples = 0; for (uint32_t i = 0; i < color_count; i++) { - EXIT_IF(!colors[i].image_id || colors[i].format == vk::Format::eUndefined); - rendering.color_formats[i] = colors[i].format; + EXIT_IF(!colors[i].image_id || colors[i].desc.view_info.format == vk::Format::eUndefined); + static_params.color_mask[i] = colors[i].export_mapping.ApplyMask( + render_target_mask_slot(ctx.GetRenderTargetMask(), colors[i].target_slot)); + rendering.color_formats[i] = colors[i].desc.view_info.format; if (attachment_samples == 0) { - attachment_samples = colors[i].samples; - } else if (attachment_samples != colors[i].samples) { + attachment_samples = colors[i].desc.info.samples; + } else if (attachment_samples != colors[i].desc.info.samples) { EXIT("mixed color attachment sample counts are unsupported: %u and %u\n", - attachment_samples, colors[i].samples); + attachment_samples, colors[i].desc.info.samples); } } const bool with_depth = - depth.format != vk::Format::eUndefined && static_cast(depth.image_id); + depth.desc.view_info.format != vk::Format::eUndefined && static_cast(depth.image_id); if (with_depth) { - const auto aspects = ImageViewOps::DepthAspectMask(depth.format); - rendering.depth_format = - aspects & vk::ImageAspectFlagBits::eDepth ? depth.format : vk::Format::eUndefined; - rendering.stencil_format = - aspects & vk::ImageAspectFlagBits::eStencil ? depth.format : vk::Format::eUndefined; + const auto aspects = ImageViewOps::DepthAspectMask(depth.desc.view_info.format); + rendering.depth_format = aspects & vk::ImageAspectFlagBits::eDepth + ? depth.desc.view_info.format + : vk::Format::eUndefined; + rendering.stencil_format = aspects & vk::ImageAspectFlagBits::eStencil + ? depth.desc.view_info.format + : vk::Format::eUndefined; if (attachment_samples == 0) { - attachment_samples = depth.samples; - } else if (attachment_samples != depth.samples) { + attachment_samples = depth.desc.info.samples; + } else if (attachment_samples != depth.desc.info.samples) { EXIT("mixed color/depth sample counts are unsupported: %u and %u\n", attachment_samples, - depth.samples); + depth.desc.info.samples); } } if (color_count == 0 && !with_depth) { @@ -689,16 +683,12 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( if (static_params.sample_shading_enable && !m_graphics.sample_rate_shading_enabled) { EXIT("Pipeline: sample-rate shading is required but unsupported by the host\n"); } - static_params.with_depth = with_depth; static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable; static_params.depth_min_bounds = depth.depth_min_bounds; static_params.depth_max_bounds = depth.depth_max_bounds; static_params.stencil_test_enable = depth.stencil_test_enable; static_params.stencil_front = depth.stencil_static_front; static_params.stencil_back = depth.stencil_static_back; - for (uint32_t i = 0; i < RENDER_COLOR_ATTACHMENTS_MAX; i++) { - static_params.color_mask[i] = color_mask[i]; - } const bool rect_list = topology == vk::PrimitiveTopology::ePatchList; static_params.cull_back = !rect_list && mc.cull_back; static_params.cull_front = !rect_list && mc.cull_front; @@ -763,13 +753,11 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( static_cast(pixel_program.module)); } - auto cached = std::make_unique(); - cached->ps_shader_id = ps_id; - cached->vs_shader_id = vs_id; + auto cached = std::make_unique(); LogPipelineTrace("CreatePipelineInternal begin", vs_id, ps_id); CreatePipelineInternal(m_graphics, *cached, rendering, key.vertex_input, vs_input_info, - vertex_program.module, ps_input_info, pixel_program.module, - static_params, m_driver_cache); + vertex_program, ps_input_info, pixel_program, static_params, + m_driver_cache); LogPipelineTrace("CreatePipelineInternal done", vs_id, ps_id); EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr); @@ -781,19 +769,17 @@ PipelineCache::GraphicsPipeline& PipelineCache::CreateGraphicsPipeline( return *iter->second; } -PipelineCache::ComputePipeline& -PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info, - const ShaderProgram& compute_program) { +PipelineCache::Pipeline& +PipelineCache::CreateComputePipeline(const ShaderComputeInputInfo& input_info, + const ShaderProgram& compute_program) { KYTY_PROFILER_BLOCK("PipelineCache::CreatePipeline(Compute)", profiler::colors::RedA100); EXIT_IF(!compute_program); Common::LockGuard lock(m_mutex); - ComputePipelineKey key {}; - key.cs_shader_id = compute_program.id; - - if (auto iter = m_compute_pipelines.find(key); iter != m_compute_pipelines.end()) { + if (auto iter = m_compute_pipelines.find(compute_program.id); + iter != m_compute_pipelines.end()) { return *iter->second; } @@ -801,14 +787,13 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo& input_info, ShaderDbgDumpInputInfo(input_info); } - auto cached = std::make_unique(); - cached->cs_shader_id = compute_program.id; + auto cached = std::make_unique(); CreatePipelineInternal(m_graphics, *cached, input_info, compute_program.module, m_driver_cache); EXIT_NOT_IMPLEMENTED(cached->pipeline == nullptr); EXIT_NOT_IMPLEMENTED(cached->pipeline_layout == nullptr); - auto [iter, inserted] = m_compute_pipelines.emplace(std::move(key), std::move(cached)); + auto [iter, inserted] = m_compute_pipelines.emplace(compute_program.id, std::move(cached)); EXIT_IF(!inserted); return *iter->second; diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h index beec46b46..9d556d518 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h @@ -39,14 +39,12 @@ struct PipelineStaticParameters { bool primitive_restart_enable = false; uint32_t samples = 1; bool sample_shading_enable = false; - bool with_depth = false; bool depth_bounds_test_enable = false; float depth_min_bounds = 0.0f; float depth_max_bounds = 0.0f; bool stencil_test_enable = false; PipelineStencilStaticState stencil_front; PipelineStencilStaticState stencil_back; - uint32_t color_count = 1; uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; bool cull_front = false; bool cull_back = false; @@ -69,7 +67,7 @@ struct PipelineStaticParameters { static_assert(std::is_trivially_copyable_v); static_assert(std::is_standard_layout_v); static_assert(alignof(PipelineStaticParameters) == 1); -static_assert(sizeof(PipelineStaticParameters) == 166); +static_assert(sizeof(PipelineStaticParameters) == 161); struct PipelineRenderingState { std::array color_formats {}; @@ -121,15 +119,6 @@ public: bool uses_push_descriptors = false; }; - struct GraphicsPipeline: Pipeline { - uint64_t vs_shader_id = 0; - uint64_t ps_shader_id = 0; - }; - - struct ComputePipeline: Pipeline { - uint64_t cs_shader_id = 0; - }; - struct GraphicsPrograms { ShaderProgram vertex; ShaderProgram pixel; @@ -146,14 +135,14 @@ public: const HW::ShaderRegisters& sh, ShaderComputeInputInfo& input_info); - GraphicsPipeline& + Pipeline& CreateGraphicsPipeline(std::span colors, const RenderDepthInfo& depth, const ShaderVertexInputInfo& vs_input_info, CommandBuffer& command, const ShaderPixelInputInfo* ps_input_info, vk::PrimitiveTopology topology, bool primitive_restart_enable, const ShaderProgram& vertex_program, const ShaderProgram& pixel_program); - ComputePipeline& CreateComputePipeline(ShaderComputeInputInfo& input_info, - const ShaderProgram& compute_program); + Pipeline& CreateComputePipeline(const ShaderComputeInputInfo& input_info, + const ShaderProgram& compute_program); private: struct ProgramCache; @@ -172,14 +161,6 @@ private: } }; - struct ComputePipelineKey { - uint64_t cs_shader_id = 0; - - bool operator==(const ComputePipelineKey& other) const { - return cs_shader_id == other.cs_shader_id; - } - }; - struct PipelineKeyHash { static void Mix(std::size_t& hash, std::size_t value) { hash ^= value + static_cast(0x9e3779b97f4a7c15ull) + (hash << 6u) + @@ -224,23 +205,13 @@ private: } }; - struct ComputePipelineKeyHash { - std::size_t operator()(const ComputePipelineKey& key) const { - std::size_t hash = 0; - PipelineKeyHash::Mix(hash, key.cs_shader_id); - return hash; - } - }; - GraphicContext& m_graphics; std::unique_ptr m_program_cache; vk::PipelineCache m_driver_cache = nullptr; std::filesystem::path m_driver_cache_path; - std::unordered_map, - GraphicsPipelineKeyHash> - m_graphics_pipelines; - std::unordered_map, ComputePipelineKeyHash> - m_compute_pipelines; + std::unordered_map, GraphicsPipelineKeyHash> + m_graphics_pipelines; + std::unordered_map> m_compute_pipelines; Common::Mutex m_mutex; void InitializeDriverCache(); @@ -248,12 +219,12 @@ private: void LogPipelineTrace(const char* phase, uint64_t vertex_program_id, uint64_t pixel_program_id); void CreatePipelineInternal( - GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline, + GraphicContext& graphics, PipelineCache::Pipeline& pipeline, const PipelineRenderingState& rendering, const PipelineVertexInputState& vertex_input, - const ShaderVertexInputInfo& vs_input_info, vk::ShaderModule vertex_module, - const ShaderPixelInputInfo* ps_input_info, vk::ShaderModule pixel_module, + const ShaderVertexInputInfo& vs_input_info, const ShaderProgram& vertex_program, + const ShaderPixelInputInfo* ps_input_info, const ShaderProgram& pixel_program, const PipelineStaticParameters& static_params, vk::PipelineCache driver_cache); -void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline, +void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline, const ShaderComputeInputInfo& input_info, vk::ShaderModule compute_module, vk::PipelineCache driver_cache); diff --git a/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.cpp b/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.cpp index 00e907afa..adffbd020 100644 --- a/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.cpp @@ -67,11 +67,12 @@ vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer) { return barrier; } -std::vector -CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& program, - const ShaderRecompiler::IR::ResourceSnapshot& resources) { +bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) { + EXIT_IF(!runtime); + const auto& program = *runtime.program; + const auto& resources = runtime.resources; EXIT_IF(resources.buffers.size() != program.info.buffers.size()); - std::vector writes; + bool has_writes = false; for (uint32_t i = 0; i < program.info.buffers.size(); i++) { if (!program.info.buffers[i].written) { continue; @@ -80,23 +81,11 @@ CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& progra EXIT_IF(value.dword_count < 4); ShaderBufferResource descriptor; std::memcpy(descriptor.fields, value.dwords.data(), sizeof(descriptor.fields)); - const auto address = descriptor.Base48(); - const auto records = static_cast(descriptor.NumRecords()); - const auto stride = static_cast(descriptor.Stride()); - if (stride != 0 && records > UINT64_MAX / stride) { - EXIT("shader resource barrier buffer footprint overflow\n"); - } - const auto size = stride == 0 ? records : stride * records; - if (address != 0 && size != 0) { - writes.push_back({address, size}); - } + // A zero stride means byte addressing. For either addressing mode a nonzero record + // count is exactly the condition for a nonempty descriptor range. + has_writes |= descriptor.Base48() != 0 && descriptor.NumRecords() != 0; } - return writes; -} - -bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) { - EXIT_IF(!runtime); - return !CollectShaderBufferWrites(*runtime.program, runtime.resources).empty(); + return has_writes; } void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages) { diff --git a/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h b/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h index 70a1c7286..98ab3018a 100644 --- a/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h +++ b/src/graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h @@ -4,27 +4,15 @@ #include "graphics/host_gpu/graphicContext.h" #include "graphics/shader/recompiler/ir/passes/ResourceMaterialization.h" -#include - namespace Libs::Graphics { struct ShaderStageRuntime; -struct ShaderBufferWriteRange { - uint64_t address = 0; - uint64_t size = 0; - - bool operator==(const ShaderBufferWriteRange& other) const = default; -}; - vk::PipelineStageFlags ShaderPipelineStages(vk::ShaderStageFlags stages); VulkanMemoryBarrier MakeShaderAccessDependency(); VulkanMemoryBarrier MakeShaderWriteHazardDependency(); VulkanMemoryBarrier MakeShaderWriteDependency(); vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer); -std::vector -CollectShaderBufferWrites(const ShaderRecompiler::IR::CompiledShaderInfo& program, - const ShaderRecompiler::IR::ResourceSnapshot& resources); bool HasShaderBufferWrites(const ShaderStageRuntime& runtime); void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages); void ShaderWriteHazardBarrier(vk::CommandBuffer vk_buffer, diff --git a/src/graphics/host_gpu/renderer/pipeline/shaders.cpp b/src/graphics/host_gpu/renderer/pipeline/shaders.cpp index 66c694431..1be8d558d 100644 --- a/src/graphics/host_gpu/renderer/pipeline/shaders.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/shaders.cpp @@ -419,13 +419,15 @@ static void CreateDescriptorLayout(GraphicContext& graphics, PipelineCache::Pipe // NOLINTNEXTLINE(readability-function-cognitive-complexity) void CreatePipelineInternal( - GraphicContext& graphics, PipelineCache::GraphicsPipeline& pipeline, + GraphicContext& graphics, PipelineCache::Pipeline& pipeline, const PipelineRenderingState& rendering, const PipelineVertexInputState& vertex_input, - const ShaderVertexInputInfo& vs_input_info, vk::ShaderModule vertex_module, - const ShaderPixelInputInfo* ps_input_info, vk::ShaderModule pixel_module, + const ShaderVertexInputInfo& vs_input_info, const ShaderProgram& vertex_program, + const ShaderPixelInputInfo* ps_input_info, const ShaderProgram& pixel_program, const PipelineStaticParameters& static_params, vk::PipelineCache driver_cache) { const bool ps_active = ps_input_info != nullptr; - EXIT_IF(vertex_module == nullptr || (ps_active && pixel_module == nullptr)); + EXIT_IF(!vertex_program || (ps_active && !pixel_program)); + const bool with_depth = rendering.depth_format != vk::Format::eUndefined || + rendering.stencil_format != vk::Format::eUndefined; EXIT_IF(!vs_input_info.stage); const bool mesh = vs_input_info.stage.program->stage == ShaderType::Mesh; EXIT_NOT_IMPLEMENTED(mesh && !graphics.mesh_shader_enabled); @@ -468,12 +470,12 @@ void CreatePipelineInternal( vk::PipelineShaderStageCreateInfo vert_shader_stage_info {}; vert_shader_stage_info.stage = vertex_stage; - vert_shader_stage_info.module = vertex_module; + vert_shader_stage_info.module = vertex_program.module; vert_shader_stage_info.pName = "main"; vk::PipelineShaderStageCreateInfo frag_shader_stage_info {}; frag_shader_stage_info.stage = vk::ShaderStageFlagBits::eFragment; - frag_shader_stage_info.module = pixel_module; + frag_shader_stage_info.module = pixel_program.module; frag_shader_stage_info.pName = "main"; vk::PipelineShaderStageCreateInfo tess_control_shader_stage_info {}; @@ -605,7 +607,7 @@ void CreatePipelineInternal( multisampling.minSampleShading = 1.0f; vk::PipelineColorBlendAttachmentState color_blend_attachment[RENDER_COLOR_ATTACHMENTS_MAX] = {}; - for (uint32_t i = 0; i < static_params.color_count; i++) { + for (uint32_t i = 0; i < rendering.color_count; i++) { EXIT_NOT_IMPLEMENTED((static_params.color_mask[i] & ~0x0fu) != 0); color_blend_attachment[i].colorWriteMask = vk::ColorComponentFlags {static_params.color_mask[i]}; @@ -629,12 +631,12 @@ void CreatePipelineInternal( } vk::Bool32 color_write_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {}; - for (uint32_t i = 0; i < static_params.color_count; i++) { + for (uint32_t i = 0; i < rendering.color_count; i++) { color_write_enable[i] = VK_TRUE; } vk::PipelineColorWriteCreateInfoEXT color_write {}; - color_write.attachmentCount = static_params.color_count; + color_write.attachmentCount = rendering.color_count; color_write.pColorWriteEnables = color_write_enable; vk::PipelineColorBlendStateCreateInfo color_blending {}; @@ -644,7 +646,7 @@ void CreatePipelineInternal( color_blending.pNext = &color_write; #endif color_blending.logicOp = vk::LogicOp::eCopy; - color_blending.attachmentCount = static_params.color_count; + color_blending.attachmentCount = rendering.color_count; color_blending.pAttachments = color_blend_attachment; std::vector descriptor_bindings; @@ -670,7 +672,7 @@ void CreatePipelineInternal( if (graphics_debug_dump_enabled()) { LOGF("PipelineTrace: vkCreatePipelineLayout begin VS=%" PRIu64 " PS=%" PRIu64 " set_layouts=1 push_constants=%" PRIu32 "\n", - pipeline.vs_shader_id, pipeline.ps_shader_id, 1u); + vertex_program.id, ps_active ? pixel_program.id : 0, 1u); } result = graphics.device.createPipelineLayout(&pipeline_layout_info, nullptr, &pipeline.pipeline_layout); @@ -722,7 +724,7 @@ void CreatePipelineInternal( auto dynamic_states_count = static_cast(sizeof(dynamic_states) / sizeof(dynamic_states[0])); #if !defined(__APPLE__) - if (static_params.color_count == 0) { + if (rendering.color_count == 0) { dynamic_states_count--; } #endif @@ -748,8 +750,7 @@ void CreatePipelineInternal( pipeline_info.pViewportState = &viewport_state; pipeline_info.pRasterizationState = &rasterizer; pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = - (static_params.with_depth ? &depth_stencil_info : nullptr); + pipeline_info.pDepthStencilState = (with_depth ? &depth_stencil_info : nullptr); pipeline_info.pColorBlendState = &color_blending; pipeline_info.pDynamicState = &dynamic_state; pipeline_info.layout = pipeline.pipeline_layout; @@ -761,10 +762,10 @@ void CreatePipelineInternal( LOGF("PipelineTrace: vkCreateGraphicsPipelines begin VS=%" PRIu64 " PS=%" PRIu64 " topology=%" PRIu32 " color_mask=0x%08" PRIx32 " depth=%s blend=%s dyn_states=%" PRIu32 "\n", - pipeline.vs_shader_id, pipeline.ps_shader_id, + vertex_program.id, ps_active ? pixel_program.id : 0, static_cast(static_params.topology), static_params.color_mask[0], - (static_params.with_depth ? "true" : "false"), - (static_params.blend_enable[0] ? "true" : "false"), dynamic_states_count); + (with_depth ? "true" : "false"), (static_params.blend_enable[0] ? "true" : "false"), + dynamic_states_count); } result = graphics.device.createGraphicsPipelines(driver_cache, 1, &pipeline_info, nullptr, &pipeline.pipeline); @@ -785,9 +786,9 @@ void CreatePipelineInternal( } // NOLINTNEXTLINE(readability-function-cognitive-complexity) -void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::ComputePipeline& pipeline, +void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& pipeline, const ShaderComputeInputInfo& input_info, - vk::ShaderModule compute_module, vk::PipelineCache driver_cache) { + vk::ShaderModule compute_module, vk::PipelineCache driver_cache) { EXIT_IF(compute_module == nullptr); vk::PipelineShaderStageCreateInfo comp_shader_stage_info {}; diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index 0314585ad..34ce276b9 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -109,12 +109,8 @@ static float ConvertPolygonOffsetConstantFactor(float guest_factor, const HW::Po return std::ldexp(guest_factor, host_depth_bits + offset.neg_num_db_bits); } -static const char* RenderColorTypeName(RenderColorType type) { - switch (type) { - case RenderColorType::NoColorOutput: return "NoColorOutput"; - case RenderColorType::RenderTexture: return "RenderTexture"; - default: return "Unknown"; - } +static const char* RenderColorTypeName(const RenderColorInfo& color) { + return color.image_id ? "RenderTexture" : "NoColorOutput"; } static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& color, @@ -135,10 +131,12 @@ static void LogFramebufferSkip(const char* draw_name, const RenderColorInfo& col "DrawFramebufferSkip[%u]: %s color=%s color_addr=0x%010" PRIx64 " color_size=0x%016" PRIx64 " color_image=%s depth_format=%s depth_image=%s depth_vaddr_num=%d target_mask=0x%08" PRIx32 " prim=%u index_count=%u flags=0x%08" PRIx32 "\n", - log_id, draw_name, RenderColorTypeName(color.type), color.base_addr, color.buffer_size, - color.image_id ? "yes" : "no", VulkanToString(depth.format).c_str(), - depth.image_id ? "yes" : "no", depth.vaddr_num, ctx.GetRenderTargetMask(), - static_cast(ucfg.GetPrimType()), index_count, flags); + log_id, draw_name, RenderColorTypeName(color), color.desc.info.data.address, + color.desc.info.data.size, color.image_id ? "yes" : "no", + VulkanToString(depth.desc.view_info.format).c_str(), depth.image_id ? "yes" : "no", + static_cast(!depth.desc.info.data.Empty()) + + static_cast(depth.desc.info.HasStencil()), + ctx.GetRenderTargetMask(), static_cast(ucfg.GetPrimType()), index_count, flags); } static void LogMrtState(const char* draw_name, const CommandBuffer& buffer, @@ -191,7 +189,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col uint32_t flags) { const auto& ctx = buffer.GetRegisters(); const auto& ucfg = buffer.GetUserConfig(); - if (color.type == RenderColorType::NoColorOutput) { + if (!color.image_id) { return; } @@ -211,8 +209,8 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col return image.resource_class == ShaderRecompiler::IR::ImageResourceClass::Sampled; }); - vk::Extent2D extent = color.image_id ? color.extent : vk::Extent2D {}; - auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent); + const auto extent = color.Extent(); + const auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent); LOGF( "DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64 @@ -221,13 +219,12 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col " blend=%s src=%u dst=%u comb=%u ps_tex=%d sampled=%d storage=%d ps_kill=%s target_mode0=%u" " depth_test=%s depth_write=%s depth_func=%u depth_clear=%s viewport=(%.1f,%.1f %.1fx%.1f) " "scissor=(%d,%d)-(%d,%d)\n", - log_id, buffer.GetContext().GetGpu().GetFrameNum(), draw_name, - RenderColorTypeName(color.type), color.base_addr, extent.width, extent.height, + log_id, buffer.GetContext().GetGpu().GetFrameNum(), draw_name, RenderColorTypeName(color), + color.desc.info.data.address, extent.width, extent.height, static_cast(ucfg.GetPrimType()), index_count, flags, ctx.GetRenderTargetMask(), - color.color_clear_enable ? "true" : "false", color.color_clear_value.float32[0], - color.color_clear_value.float32[1], color.color_clear_value.float32[2], - color.color_clear_value.float32[3], cc.mode, cc.op, bc.enable ? "true" : "false", - bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn, + "false", color.color_clear_value.float32[0], color.color_clear_value.float32[1], + color.color_clear_value.float32[2], color.color_clear_value.float32[3], cc.mode, cc.op, + bc.enable ? "true" : "false", bc.color_srcblend, bc.color_destblend, bc.color_comb_fcn, static_cast(ps_resources.images.size()), static_cast(sampled_images), static_cast(ps_resources.images.size() - sampled_images), ps_input_info.ps_pixel_kill_enable ? "true" : "false", ps_input_info.target_output_mode[0], @@ -251,9 +248,10 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo LOGF("DrawInputState[%u]: frame=%d target=%s addr=0x%010" PRIx64 " index_type=%u index_count=%u index_addr=0x%016" PRIx64 " vs_resources=%d vs_buffers=%d\n", - log_id, buffer.GetContext().GetGpu().GetFrameNum(), RenderColorTypeName(color.type), - color.base_addr, index_type_and_size, index_count, reinterpret_cast(index_addr), - vs_input_info.resources_num, vs_input_info.buffers_num); + log_id, buffer.GetContext().GetGpu().GetFrameNum(), RenderColorTypeName(color), + color.desc.info.data.address, index_type_and_size, index_count, + reinterpret_cast(index_addr), vs_input_info.resources_num, + vs_input_info.buffers_num); for (int bi = 0; bi < vs_input_info.buffers_num; bi++) { const auto& b = vs_input_info.buffers[bi]; @@ -328,9 +326,9 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf const auto& vp = ctx.GetScreenViewport(); vk::Extent2D framebuffer_extent {}; if (color_count > 0 && colors[0].image_id) { - framebuffer_extent = colors[0].extent; + framebuffer_extent = colors[0].Extent(); } else if (depth.image_id) { - framebuffer_extent = {depth.width, depth.height}; + framebuffer_extent = {depth.desc.info.extent.width, depth.desc.info.extent.height}; } else { const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits; framebuffer_extent = {limits.maxFramebufferWidth, limits.maxFramebufferHeight}; @@ -392,8 +390,8 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf // Vulkan has one bias for both faces. Prefer a visible front face when both are enabled. const float guest_constant_factor = use_front ? poly_offset.front_offset : poly_offset.back_offset; - const float constant_factor = - ConvertPolygonOffsetConstantFactor(guest_constant_factor, poly_offset, depth.format); + const float constant_factor = ConvertPolygonOffsetConstantFactor( + guest_constant_factor, poly_offset, depth.desc.view_info.format); const float slope_factor = (use_front ? poly_offset.front_scale : poly_offset.back_scale) / 16.0f; vk_buffer.setDepthBias(constant_factor, poly_offset.clamp, slope_factor); @@ -449,7 +447,6 @@ struct DrawRenderState { RenderColorInfo color_info[RENDER_COLOR_ATTACHMENTS_MAX] = {}; uint32_t color_count = 0; bool ps_active = true; - RenderState rendering; ShaderVertexInputInfo vs_input_info; ShaderPixelInputInfo ps_input_info; PipelineCache::GraphicsPrograms programs; @@ -549,23 +546,23 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo target.image_id = cache.FindImage(target.desc); BindRenderTarget(target.image_id); } - target.image_view = cache.FindRenderTarget(target.image_id, target.desc); - auto& image = cache.GetImage(target.image_id); + const auto image_view = cache.FindRenderTarget(target.image_id, target.desc); + auto& image = cache.GetImage(target.image_id); SetVulkanObjectNameF(m_context.GetGraphics().device, image.backing.image, "Kyty.MRT{}.Image[guest=0x{:016x} size=0x{:x} format={}]", target.target_slot, image.info.data.address, image.info.data.size, static_cast(image.info.pixel_format)); - SetVulkanObjectNameF(m_context.GetGraphics().device, target.image_view, + SetVulkanObjectNameF(m_context.GetGraphics().device, image_view, "Kyty.MRT{}.View[guest=0x{:016x} mip={} layer={}+{}]", target.target_slot, image.info.data.address, target.desc.view_info.base_level, target.desc.view_info.base_layer, target.desc.view_info.layer_count); - EXIT_IF(image.backing.samples != target.samples || target.image_view == nullptr); + EXIT_IF(image.backing.samples != target.desc.info.samples || image_view == nullptr); if (attachment_samples == 0) { - attachment_samples = target.samples; - } else if (attachment_samples != target.samples) { + attachment_samples = target.desc.info.samples; + } else if (attachment_samples != target.desc.info.samples) { EXIT("mixed color attachment sample counts are unsupported: %u and %u\n", - attachment_samples, target.samples); + attachment_samples, target.desc.info.samples); } const auto& view = target.desc.view_info; const auto layout = image.binding.is_bound ? vk::ImageLayout::eGeneral @@ -577,11 +574,12 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo ImageSubresourceRange {view.base_level, view.level_count, view.base_layer, view.layer_count}, buffer.Handle()); - state.width = std::min(state.width, target.extent.width); - state.height = std::min(state.height, target.extent.height); + const auto extent = target.Extent(); + state.width = std::min(state.width, extent.width); + state.height = std::min(state.height, extent.height); state.num_layers = std::min(state.num_layers, view.layer_count); auto& attachment = state.color_attachments[i]; - attachment.image_view = target.image_view; + attachment.image_view = image_view; attachment.image_layout = layout; attachment.clear_value = target.color_clear_value.uint32; vk::ClearColorValue metadata_clear_value {}; @@ -590,23 +588,25 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo if (metadata_clear) { attachment.clear_value = metadata_clear_value.uint32; } - attachment.is_clear = target.color_clear_enable || metadata_clear; + attachment.is_clear = metadata_clear; } if (depth.image_id) { const auto owner = cache.m_slot_images.try_get(depth.image_id); if (owner == nullptr || !owner->registered || owner->binding.needs_rebind) { EXIT("depth target changed after render-state discovery\n"); } - depth.image_view = cache.FindDepthTarget(depth.image_id, depth.desc); - if (depth.htile && depth.depth_clear_enable && !cache.ClearMeta(depth.htile_buffer_vaddr)) { + const auto image_view = cache.FindDepthTarget(depth.image_id, depth.desc); + const auto& metadata = depth.desc.info.metadata; + if (metadata.kind == ImageMetadataKind::Htile && depth.depth_clear_enable && + !cache.ClearMeta(metadata.range.address)) { EXIT("failed to acquire HTile metadata for a depth clear\n"); } depth.depth_meta_clear_enable = - depth.htile && - cache.IsMetaCleared(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer); + metadata.kind == ImageMetadataKind::Htile && + cache.IsMetaCleared(metadata.range.address, depth.desc.view_info.base_layer); depth.depth_load_clear_enable = depth.depth_clear_enable || depth.depth_meta_clear_enable; if (depth.depth_meta_clear_enable && - !cache.TouchMeta(depth.htile_buffer_vaddr, depth.desc.view_info.base_layer, false)) { + !cache.TouchMeta(metadata.range.address, depth.desc.view_info.base_layer, false)) { EXIT("failed to consume HTile clear state\n"); } auto& image = cache.GetImage(depth.image_id); @@ -614,16 +614,16 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo "Kyty.DepthTarget.Image[guest=0x{:016x} size=0x{:x} format={}]", image.info.data.address, image.info.data.size, static_cast(image.info.pixel_format)); - SetVulkanObjectNameF(m_context.GetGraphics().device, depth.image_view, + SetVulkanObjectNameF(m_context.GetGraphics().device, image_view, "Kyty.DepthTarget.View[guest=0x{:016x} layer={}+{}]", image.info.data.address, depth.desc.view_info.base_layer, depth.desc.view_info.layer_count); - EXIT_IF(depth.image_view == nullptr || image.backing.samples != depth.samples); + EXIT_IF(image_view == nullptr || image.backing.samples != depth.desc.info.samples); if (attachment_samples == 0) { - attachment_samples = depth.samples; - } else if (attachment_samples != depth.samples) { + attachment_samples = depth.desc.info.samples; + } else if (attachment_samples != depth.desc.info.samples) { EXIT("mixed color/depth sample counts are unsupported: %u and %u\n", attachment_samples, - depth.samples); + depth.desc.info.samples); } const auto layout = depth_attachment_layout(depth); // The attachment store writes even when guest depth/stencil tests do not. @@ -636,12 +636,12 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo ImageSubresourceRange {view.base_level, view.level_count, view.base_layer, view.layer_count}, buffer.Handle()); - state.width = std::min(state.width, depth.width); - state.height = std::min(state.height, depth.height); + state.width = std::min(state.width, depth.desc.info.extent.width); + state.height = std::min(state.height, depth.desc.info.extent.height); state.num_layers = std::min(state.num_layers, view.layer_count); - const auto aspects = ImageViewOps::DepthAspectMask(depth.format); + const auto aspects = ImageViewOps::DepthAspectMask(depth.desc.view_info.format); auto& attachment = state.depth_stencil_attachment; - attachment.image_view = depth.image_view; + attachment.image_view = image_view; attachment.image_layout = layout; attachment.clear_value[0] = std::bit_cast(depth.depth_clear_value); attachment.clear_value[1] = depth.stencil_clear_value; @@ -705,7 +705,6 @@ struct DrawEmitInfo { }; struct DrawIndexBufferSource { - bool enabled = false; uint64_t address = 0; const void* host_data = nullptr; uint64_t size = 0; @@ -715,7 +714,6 @@ struct DrawIndexBufferSource { struct PreparedIndexBuffer { vk::Buffer buffer = nullptr; - uint64_t size = 0; vk::DeviceSize offset = 0; vk::IndexType type = vk::IndexType::eUint16; }; @@ -849,8 +847,6 @@ static PreparedVertexBuffers AcquireVertexBuffers(CommandBuffer& b static void SetDrawDebugPhase(CommandBuffer& buffer, uint64_t submit_id, const DrawCallInfo& draw, uint32_t phase) { - EXIT_IF(draw.name == nullptr); - buffer.SetDebugInfo(static_cast(draw.debug_op), submit_id, phase, draw.index_count, 0, draw.instance_count, draw.first_instance); } @@ -935,7 +931,6 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b const DrawCallInfo& draw, uint32_t render_target_slice_offset, bool log_setup_phases, DrawRenderState& state) { - EXIT_IF(draw.name == nullptr); auto& ctx = buffer.GetRegisters(); if (ResolveColorTargets(submit_id, buffer, render_target_slice_offset)) { @@ -960,9 +955,7 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b ResolveRenderDepthTarget(submit_id, buffer, state.depth_info); state.ps_active = DrawHasActivePixelShader(buffer); - const bool with_depth = (state.depth_info.format != vk::Format::eUndefined && - static_cast(state.depth_info.image_id)); - if (state.color_count == 0 && !with_depth && !state.ps_active) { + if (state.color_count == 0 && !state.depth_info.image_id && !state.ps_active) { LogFramebufferSkip(draw.name, state.color_info[0], state.depth_info, buffer, draw.index_count, 0); return false; @@ -973,7 +966,6 @@ bool RenderExecutor::PrepareDrawRenderState(uint64_t submit_id, CommandBuffer& b static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool log_phases, DrawRenderState& state) { - EXIT_IF(draw.name == nullptr); auto& ctx = buffer.GetRegisters(); auto& sh_ctx = buffer.GetShaders(); @@ -1000,11 +992,9 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool static PreparedIndexBuffer PrepareIndexBuffer(CommandBuffer& buffer, const DrawIndexBufferSource& source) { PreparedIndexBuffer prepared; - if (!source.enabled) { + if (source.size == 0) { return prepared; } - EXIT_IF(source.size == 0); - prepared.size = source.size; prepared.type = source.type; if (source.host_data != nullptr) { auto& stream = buffer.GetContext().GetBufferCache().GetUtilityBuffer(MemoryUsage::Stream); @@ -1040,10 +1030,9 @@ static void CommitVertexBuffers(vk::CommandBuffer vk_buffer, } static void CommitIndexBuffer(vk::CommandBuffer vk_buffer, const PreparedIndexBuffer& prepared) { - if (prepared.size == 0) { + if (prepared.buffer == nullptr) { return; } - EXIT_IF(prepared.buffer == nullptr); vk_buffer.bindIndexBuffer(prepared.buffer, prepared.offset, prepared.type); } @@ -1051,8 +1040,6 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo const DrawRenderState& state, bool always_log, bool force_legacy_rect_log, uint32_t index_type_and_size, const void* index_addr) { - EXIT_IF(draw.name == nullptr); - if (!graphics_debug_dump_enabled()) { return; } @@ -1067,14 +1054,11 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo } LogDrawInputState(buffer, state.color_info[0], state.vs_input_info, index_type_and_size, draw.index_count, index_addr); - // LogDrawTextureState(draw.name, state.color_info[0], state.ps_input_info); } static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer, const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw, const DrawEmitInfo& emit) { - EXIT_IF(draw.name == nullptr); - switch (ucfg.GetPrimType()) { case Prospero::PrimitiveType::kPointList: case Prospero::PrimitiveType::kLineList: @@ -1121,7 +1105,6 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff const DrawIndexBufferSource& index_source, bool primitive_restart_enable, bool log_pipeline_phase, bool set_bind_debug, bool set_auto_debug) { - EXIT_IF(draw.name == nullptr); auto& ucfg = buffer.GetUserConfig(); const bool mesh_active = state.vs_input_info.stage.program->stage == ShaderType::Mesh; uint32_t mesh_groups = 0; @@ -1163,7 +1146,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff vertex_bindings = AcquireVertexBuffers(buffer, state.vs_input_info); index_binding = PrepareIndexBuffer(buffer, index_source); } - state.rendering = + const auto rendering = AcquireRenderTargets(buffer, state.color_info, state.color_count, state.depth_info); if (log_pipeline_phase) { @@ -1222,7 +1205,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x400u); } - m_context.GetCommandScheduler().BeginRendering(state.rendering); + m_context.GetCommandScheduler().BeginRendering(rendering); vk_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.pipeline); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x500u); @@ -1345,7 +1328,6 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer, } DrawIndexBufferSource index_source {}; - index_source.enabled = true; index_source.address = reinterpret_cast(args.index_addr); index_source.host_data = expanded_indices.empty() ? nullptr : static_cast(expanded_indices.data()); @@ -1496,12 +1478,12 @@ bool RenderExecutor::ResolveColorTargets(uint64_t submit_id, CommandBuffer& buff RenderColorInfo dst {}; ResolveRenderColorTarget(submit_id, buffer, src, render_target_slice_offset, 0, true, true); ResolveRenderColorTarget(submit_id, buffer, dst, render_target_slice_offset, 1, true, true); - if (!src.image_id || !dst.image_id || src.type == RenderColorType::NoColorOutput || - dst.type == RenderColorType::NoColorOutput) { + if (!src.image_id || !dst.image_id) { return false; } - if (src.base_addr == dst.base_addr && src.base_mip_level == dst.base_mip_level && - src.base_array_layer == dst.base_array_layer) { + if (src.desc.info.data.address == dst.desc.info.data.address && + src.guest_mip_level == dst.guest_mip_level && + src.guest_array_layer == dst.guest_array_layer) { return true; } @@ -1509,8 +1491,8 @@ bool RenderExecutor::ResolveColorTargets(uint64_t submit_id, CommandBuffer& buff cache.MarkGpuWritten(dst.image_id); auto& source = cache.GetImage(src.image_id); auto& destination = cache.GetImage(dst.image_id); - destination.Resolve(source, {src.base_mip_level, 1, src.base_array_layer, 1}, - {dst.base_mip_level, 1, dst.base_array_layer, 1}); + destination.Resolve(source, {src.guest_mip_level, 1, src.guest_array_layer, 1}, + {dst.guest_mip_level, 1, dst.guest_array_layer, 1}); return true; } diff --git a/src/graphics/host_gpu/vma.cpp b/src/graphics/host_gpu/vma.cpp index f9e2a02f8..baba436e0 100644 --- a/src/graphics/host_gpu/vma.cpp +++ b/src/graphics/host_gpu/vma.cpp @@ -165,7 +165,7 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm VmaAllocationInfo allocation_result {}; vk::Image::CType native_image = VK_NULL_HANDLE; - const auto result = static_cast( + const auto result = static_cast( vmaCreateImage(allocator, static_cast(image_info), &alloc_info, &native_image, &memory.allocation, &allocation_result)); image.image = native_image; @@ -175,7 +175,7 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm } device.getImageMemoryRequirements(image.image, &memory.requirements); - memory.type = allocation_result.memoryType; + memory.type = allocation_result.memoryType; VulkanTrackAllocation(memory); return true; } diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 5a7a95b73..a9d335d93 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -1725,6 +1725,28 @@ public: HW::Shader shaders{}; scheduler.Begin(registers, user_config, shaders); + auto *command = &scheduler.Current(); + const auto original_handle = command->Handle(); + HW::Context next_registers{}; + HW::UserConfig next_user_config{}; + HW::Shader next_shaders{}; + scheduler.Begin(next_registers, next_user_config, next_shaders); + Require("SchedulerTimeline", "guest context rebind", + &scheduler.Current() == command && + command->Handle() == original_handle && + &command->GetRegisters() == &next_registers && + &command->GetUserConfig() == &next_user_config && + &command->GetShaders() == &next_shaders, + "rebinding guest state replaced the active command recording"); + scheduler.FlushAndWait(); + Require("SchedulerTimeline", "guest context after recording restart", + scheduler.Active() && &scheduler.Current() == command && + &command->GetRegisters() == &next_registers && + &command->GetUserConfig() == &next_user_config && + &command->GetShaders() == &next_shaders, + "restarting command recording lost the current guest context"); + scheduler.Begin(registers, user_config, shaders); + const auto first_tick = scheduler.CurrentTick(); uint32_t completed = 0; scheduler.DeferOperation([owned = std::make_unique(1), @@ -7585,7 +7607,7 @@ public: scheduler.Current().EndRendering(); Require(name, "captured 1D target", color.image_id && attachment != nullptr && - color.image_view != nullptr && + rendering.color_attachments[0].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} && @@ -7716,7 +7738,7 @@ public: Require( name, "3D slice transition", sliced_color.image_id == color.image_id && - sliced_color.image_view != nullptr && + sliced_rendering.color_attachments[0].image_view != nullptr && sliced_color.desc.view_info.base_layer == 7 && sliced_rendering.num_color_attachments == 1 && sliced_rendering.num_layers == 1 && @@ -8170,7 +8192,8 @@ public: const auto &image = texture_cache.GetImage(color.image_id); Require(name, "captured target", color.image_id && attachment != nullptr && - color.base_array_layer == 5 && + color.guest_array_layer == 5 && + color.desc.view_info.base_layer == 5 && color.desc.info.data.address == target_address && color.desc.info.data.size == target_size && color.desc.info.tile_mode == tile_case.tile && @@ -8374,6 +8397,46 @@ public: ShaderRecompiler::IR::AllocateBindings(program); }; + { + ShaderRecompiler::IR::Program buffer_ir{}; + buffer_ir.stage = ShaderType::Compute; + buffer_ir.resource_tracking_complete = true; + buffer_ir.info.buffers.resize(1); + buffer_ir.info.buffers[0].read = true; + allocate_bindings(buffer_ir); + ShaderRecompiler::IR::CompiledShaderInfo buffer_program{}; + buffer_program.stage = buffer_ir.stage; + buffer_program.info = std::move(buffer_ir.info); + buffer_program.bindings = std::move(buffer_ir.bindings); + + constexpr uint64_t buffer_address = base + allocation_size - 0x5000; + ShaderBufferResource buffer_descriptor{}; + buffer_descriptor.UpdateAddress48(buffer_address); + buffer_descriptor.fields[2] = 0x8000; + ShaderStageRuntime buffer_runtime{.program = &buffer_program}; + auto &value = buffer_runtime.resources.buffers.emplace_back(); + std::memcpy(value.dwords.data(), buffer_descriptor.fields, + sizeof(buffer_descriptor.fields)); + value.dword_count = 4; + auto buffer_bindings = executor.PrepareBindings(buffer_runtime); + executor.FindBuffers(buffer_bindings); + const auto original_id = buffer_bindings.buffer_sources[0].id; + + auto &buffer_cache = resources.GetBufferCache(); + const auto merged_id = + buffer_cache.FindBuffer(base + allocation_size - 0x10000, 0x10000); + Require(name, "buffer discovery invalidation", merged_id != original_id, + "overlapping buffer discovery did not replace its smaller owner"); + executor.RebindBuffers(buffer_bindings); + const auto &binding = buffer_bindings.buffers[0]; + const auto &owner = buffer_cache.GetBuffer(merged_id); + Require(name, "clamped buffer rebind", + binding.buffer == owner.Handle() && + binding.offset == owner.Offset(buffer_address) && + binding.range == 0x5000, + "descriptor rebind lost its clamped guest range or retained a stale host owner"); + } + constexpr auto stencil_format = Prospero::BufferFormat::k8UInt; constexpr auto linear = Prospero::TileMode::kLinear; TileSizeAlign stencil_layout{}; @@ -8425,13 +8488,13 @@ public: auto null_bindings = executor.PrepareBindings(null_runtime); executor.RebindImages(null_bindings); Require(name, "null descriptor count", - null_bindings.resources.images.size() == 3, + null_bindings.images.size() == 3, "null descriptor preparation lost an image binding"); - const auto null_image_id = null_bindings.resources.images[0].image_id; + const auto null_image_id = null_bindings.images[0].image_id; const auto &null_image = texture_cache.GetImage(null_image_id); Require(name, "one null image per format", - null_bindings.resources.images[1].image_id == null_image_id && - null_bindings.resources.images[2].image_id == null_image_id && + null_bindings.images[1].image_id == null_image_id && + null_bindings.images[2].image_id == null_image_id && TextureCacheTestAccess::NullImageCount(texture_cache) == 1, "null view dimension or usage created another image allocation"); Require(name, "null descriptors share final cache acquisition", @@ -8447,7 +8510,7 @@ public: descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings( executor, scheduler.Current(), null_bindings)); Require(name, "null descriptor general layouts", - std::ranges::all_of(null_bindings.resources.images, + std::ranges::all_of(null_bindings.images, [](const auto &binding) { const auto info = MakeImageInfo(binding); return binding.layout == @@ -8578,19 +8641,19 @@ public: overwide_mipped_storage_descriptor}; mipped_prepared.program = &mipped_program; mipped_prepared.snapshot = &mipped_snapshot; - mipped_prepared.resources.images.push_back( + mipped_prepared.images.push_back( std::move(plain_mipped_storage_binding)); - mipped_prepared.resources.images.push_back( + mipped_prepared.images.push_back( std::move(mipped_storage_binding)); - mipped_prepared.resources.images.push_back( + mipped_prepared.images.push_back( std::move(overwide_mipped_storage_binding)); - mipped_prepared.resources.images.push_back( + mipped_prepared.images.push_back( std::move(sampled_overwide_resolved)); executor.RebindImages(mipped_prepared); - auto &plain_mipped_binding = mipped_prepared.resources.images[0]; - auto &mipped_binding = mipped_prepared.resources.images[1]; - auto &overwide_mipped_binding = mipped_prepared.resources.images[2]; - auto &sampled_overwide_binding = mipped_prepared.resources.images[3]; + auto &plain_mipped_binding = mipped_prepared.images[0]; + auto &mipped_binding = mipped_prepared.images[1]; + auto &overwide_mipped_binding = mipped_prepared.images[2]; + auto &sampled_overwide_binding = mipped_prepared.images[3]; plain_mipped_binding.layout = vk::ImageLayout::eGeneral; mipped_binding.layout = vk::ImageLayout::eGeneral; overwide_mipped_binding.layout = vk::ImageLayout::eGeneral; @@ -8774,9 +8837,9 @@ public: ShaderStageRuntime storage_runtime{&storage_info, std::move(storage_snapshot)}; auto storage_discovery = executor.PrepareBindings(storage_runtime); - const auto storage_id = storage_discovery.resources.images[0].image_id; + const auto storage_id = storage_discovery.images[0].image_id; Require(name, "storage prefetch purity", - storage_discovery.resources.images[0].image_view == nullptr && + storage_discovery.images[0].image_view == nullptr && texture_cache.GetImage(storage_id).binding.is_bound && !texture_cache.GetImage(storage_id).usage.storage && !TextureCacheTestAccess::PendingDownload(texture_cache, @@ -8828,10 +8891,10 @@ public: auto ordered_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings( executor, storage_runtime, ordered_sampled_runtime, true); const auto ordered_sampled_id = - ordered_bindings.pixel->resources.images[0].image_id; + ordered_bindings.pixel->images[0].image_id; Require( name, "VS-before-PS retained-owner order", - ordered_bindings.vertex.resources.images[0].image_id == storage_id && + ordered_bindings.vertex.images[0].image_id == storage_id && ordered_sampled_id != storage_id && RenderExecutorTestAccess::BoundImagesInOrder(executor, storage_id, ordered_sampled_id), @@ -8843,9 +8906,9 @@ public: RenderExecutorTestAccess::PrepareGraphicsBindings( executor, storage_runtime, sampled_runtime, true); const auto &storage_binding = - graphics_bindings.vertex.resources.images[0]; + graphics_bindings.vertex.images[0]; const auto &sampled_binding = - graphics_bindings.pixel->resources.images[0]; + graphics_bindings.pixel->images[0]; Require(name, "storage final acquisition", storage_binding.image_view != nullptr && texture_cache.GetImage(storage_id).usage.storage && @@ -8909,13 +8972,13 @@ public: *writable_alias_bindings.pixel)); Require( name, "forced-general descriptor capture", - writable_alias_bindings.vertex.resources.images[0].layout == + writable_alias_bindings.vertex.images[0].layout == vk::ImageLayout::eGeneral && - writable_alias_bindings.pixel->resources.images[0].layout == + writable_alias_bindings.pixel->images[0].layout == vk::ImageLayout::eGeneral && - MakeImageInfo(writable_alias_bindings.vertex.resources.images[0]) + MakeImageInfo(writable_alias_bindings.vertex.images[0]) .imageLayout == vk::ImageLayout::eGeneral && - MakeImageInfo(writable_alias_bindings.pixel->resources.images[0]) + MakeImageInfo(writable_alias_bindings.pixel->images[0]) .imageLayout == vk::ImageLayout::eGeneral && texture_cache.GetImage(storage_id).backing.state.layout == vk::ImageLayout::eGeneral && @@ -8975,10 +9038,10 @@ public: ShaderRecompiler::IR::ResourceSnapshot split_snapshot{}; split_bindings.program = &split_program; split_bindings.snapshot = &split_snapshot; - split_bindings.resources.images.push_back( + split_bindings.images.push_back( {split_id, texture_cache.FindTexture(split_id, split_storage_desc), split_storage_desc}); - split_bindings.resources.images.push_back( + split_bindings.images.push_back( {split_id, texture_cache.FindTexture(split_id, split_sampled_desc), split_sampled_desc}); descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings( @@ -8986,13 +9049,13 @@ public: const auto &split_image = texture_cache.GetImage(split_id); Require( name, "per-binding subresource layouts", - split_bindings.resources.images[0].layout == + split_bindings.images[0].layout == vk::ImageLayout::eGeneral && - split_bindings.resources.images[1].layout == + split_bindings.images[1].layout == vk::ImageLayout::eShaderReadOnlyOptimal && - MakeImageInfo(split_bindings.resources.images[0]).imageLayout == + MakeImageInfo(split_bindings.images[0]).imageLayout == vk::ImageLayout::eGeneral && - MakeImageInfo(split_bindings.resources.images[1]).imageLayout == + MakeImageInfo(split_bindings.images[1]).imageLayout == vk::ImageLayout::eShaderReadOnlyOptimal && split_image.backing.subresource_states.size() == 2 && split_image.backing.subresource_states[0].layout == @@ -9066,7 +9129,7 @@ public: executor, 1, scheduler.Current(), non_texture_compatible_depth); Require( name, "depth texture compatibility identity", - phased_depth.image_id && phased_depth.htile && + phased_depth.image_id && (phased_depth.desc.info.metadata.kind == ImageMetadataKind::Htile) && non_texture_compatible_depth.image_id == phased_depth.image_id && non_texture_compatible_depth.desc.info.data == phased_depth.desc.info.data && @@ -9077,7 +9140,7 @@ public: phased_depth.desc.info.metadata.stencil_compressed && !phased_depth.depth_clear_enable && !phased_depth.depth_meta_clear_enable && - !texture_cache.IsMeta(phased_depth.htile_buffer_vaddr) && + !texture_cache.IsMeta(phased_depth.desc.info.metadata.range.address) && !texture_cache.GetImage(phased_depth.image_id).IsGpuModified() && !texture_cache.GetImage(phased_depth.image_id).usage.depth_target, "valid PS5 texture-compatibility policy changed logical depth image " @@ -9113,8 +9176,8 @@ public: Require( name, "read-only depth/stencil target without write addresses", read_only_depth.image_id == phased_depth.image_id && - read_only_depth.depth_buffer_vaddr == phased_depth_address && - read_only_depth.stencil_buffer_vaddr == phased_stencil_address && + read_only_depth.desc.info.data.address == phased_depth_address && + read_only_depth.desc.info.stencil.address == phased_stencil_address && !read_only_depth.depth_write_enable && !read_only_depth.stencil_clear_enable && read_only_depth.stencil_test_enable && @@ -9152,16 +9215,14 @@ public: executor, scheduler.Current(), &no_color, 0, phased_depth); Require( name, "HTile final acquisition", - phased_depth.image_view != nullptr && + phased_rendering.depth_stencil_attachment.image_view != nullptr && phased_rendering.num_color_attachments == 0 && - phased_rendering.depth_stencil_attachment.image_view == - phased_depth.image_view && phased_rendering.depth_stencil_attachment.has_depth && phased_depth.depth_meta_clear_enable && phased_depth.depth_load_clear_enable && - texture_cache.IsMeta(phased_depth.htile_buffer_vaddr) && + texture_cache.IsMeta(phased_depth.desc.info.metadata.range.address) && !texture_cache.IsMetaCleared( - phased_depth.htile_buffer_vaddr, + phased_depth.desc.info.metadata.range.address, phased_depth.desc.view_info.base_layer) && texture_cache.GetImage(phased_depth.image_id).IsGpuModified() && texture_cache.GetImage(phased_depth.image_id).usage.depth_target, @@ -9198,22 +9259,18 @@ public: executor, 1, scheduler.Current(), depth_only); Require( name, "depth-only target with stale stencil state", - depth_only.image_id && depth_only.format == vk::Format::eD32Sfloat && - depth_only.htile && + depth_only.image_id && depth_only.desc.view_info.format == vk::Format::eD32Sfloat && + (depth_only.desc.info.metadata.kind == ImageMetadataKind::Htile) && depth_only.depth_test_enable && depth_only.depth_write_enable && depth_only.depth_clear_enable && !depth_only.stencil_test_enable && !depth_only.stencil_clear_enable && - depth_only.stencil_buffer_vaddr == 0 && - depth_only.stencil_buffer_size == 0 && depth_only.desc.info.stencil.Empty() && - depth_only.htile_buffer_vaddr == depth_only_htile_address && depth_only.desc.info.metadata.range.address == depth_only_htile_address && - depth_only.depth_buffer_size != 0 && - depth_only_address + depth_only.depth_buffer_size <= + depth_only.desc.info.data.size != 0 && + depth_only_address + depth_only.desc.info.data.size <= base + allocation_size && - depth_only.vaddr_num == 1 && depth_only.AttachmentWriteAspects() == vk::ImageAspectFlagBits::eDepth, "inactive stencil state changed a depth-only HTile attachment"); @@ -9308,7 +9365,7 @@ public: for (uint32_t pass = 0; pass < 2; ++pass) { Require(name, "bounds prior depth contents", texture_cache.ClearImageFromBuffer(scheduler.Current(), - depth_only.depth_buffer_vaddr, depth_only.depth_buffer_size, + depth_only.desc.info.data.address, depth_only.desc.info.data.size, std::bit_cast(0.625f)), "failed to seed depth before the deferred HTile clear"); if (pass == 0) { @@ -9325,8 +9382,8 @@ public: executor, scheduler.Current(), &no_color, 0, bounds_depth); descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings( executor, scheduler.Current(), bounds_bindings.vertex, *bounds_bindings.pixel)); - const auto &vertex_depth = bounds_bindings.vertex.resources.images[0]; - const auto &pixel_depth = bounds_bindings.pixel->resources.images[0]; + const auto &vertex_depth = bounds_bindings.vertex.images[0]; + const auto &pixel_depth = bounds_bindings.pixel->images[0]; constexpr auto readonly_layout = vk::ImageLayout::eDepthReadOnlyOptimal; Require(name, "deferred clear with sampled read-only depth bounds", bounds_depth.image_id == depth_only.image_id && @@ -9422,8 +9479,8 @@ public: vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite; const auto &shared_image = texture_cache.GetImage(shared_depth.image_id); - const auto &vertex_image = shared_bindings.vertex.resources.images[0]; - const auto &pixel_image = shared_bindings.pixel->resources.images[0]; + const auto &vertex_image = shared_bindings.vertex.images[0]; + const auto &pixel_image = shared_bindings.pixel->images[0]; Require(name, "sampled depth and stencil attachment layout", shared_depth.image_id == phased_depth.image_id && vertex_image.image_id == shared_depth.image_id && @@ -9534,7 +9591,7 @@ public: auto array_binding = executor.PrepareBindings(array_runtime); executor.RebindImages(array_binding); - const auto expanded_array_id = array_binding.resources.images[0].image_id; + const auto expanded_array_id = array_binding.images[0].image_id; const auto &expanded_array = texture_cache.GetImage(expanded_array_id); Require( name, "2D target to array backing expansion", @@ -9543,36 +9600,30 @@ public: expanded_array_id != array_target_id && !TextureCacheTestAccess::Contains(texture_cache, array_target_id) && - array_binding.resources.images[0].image_view != nullptr && - array_binding.resources.images[0].desc.info.type == + array_binding.images[0].image_view != nullptr && + array_binding.images[0].desc.info.type == Prospero::ImageType::kColor2D && - array_binding.resources.images[0].desc.info.resources == + array_binding.images[0].desc.info.resources == ImageSubresources{1, 2} && - array_binding.resources.images[0].desc.view_info.type == + array_binding.images[0].desc.view_info.type == vk::ImageViewType::e2DArray && - array_binding.resources.images[0].desc.view_info.layer_count == + array_binding.images[0].desc.view_info.layer_count == 2 && expanded_array.backing.layers == 2 && expanded_array.IsGpuModified() && expanded_array.usage.texture, "raw array view did not expand and reuse the Color2D backing"); RenderColorInfo rebound_array_target{}; - rebound_array_target.type = RenderColorType::RenderTexture; rebound_array_target.desc = array_target; rebound_array_target.image_id = array_target_id; - rebound_array_target.format = array_target.view_info.format; - rebound_array_target.extent = {128, 128}; - rebound_array_target.samples = 1; RenderDepthInfo no_array_depth{}; auto array_rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &rebound_array_target, 1, no_array_depth); Require(name, "expanded array target rebind", rebound_array_target.image_id == expanded_array_id && - rebound_array_target.image_view != nullptr && + array_rendering.color_attachments[0].image_view != nullptr && array_rendering.num_color_attachments == 1 && - array_rendering.color_attachments[0].image_view == - rebound_array_target.image_view && array_rendering.width == 128 && array_rendering.height == 128 && array_rendering.num_layers == 1 && @@ -9608,7 +9659,7 @@ public: executor.PrepareBindings(colliding_msaa_runtime); executor.RebindImages(colliding_msaa_binding); const auto &resolved_colliding_msaa = - colliding_msaa_binding.resources.images[0]; + colliding_msaa_binding.images[0]; Require( name, "equal-footprint sample-count identity", resolved_colliding_msaa.image_id != expanded_array_id && @@ -9665,7 +9716,7 @@ public: ShaderStageRuntime msaa_runtime{&msaa_program, std::move(msaa_snapshot)}; auto msaa_binding = executor.PrepareBindings(msaa_runtime); executor.RebindImages(msaa_binding); - const auto &resolved_msaa = msaa_binding.resources.images[0]; + const auto &resolved_msaa = msaa_binding.images[0]; Require( name, "MSAA descriptor backing reuse", msaa_target_view != nullptr && @@ -9705,7 +9756,7 @@ public: std::move(msaa_array_snapshot)}; auto msaa_array_binding = executor.PrepareBindings(msaa_array_runtime); executor.RebindImages(msaa_array_binding); - const auto &resolved_msaa_array = msaa_array_binding.resources.images[0]; + const auto &resolved_msaa_array = msaa_array_binding.images[0]; Require(name, "MSAA array backing expansion", resolved_msaa_array.image_id != msaa_target_id && resolved_msaa_array.image_view != nullptr && @@ -9760,19 +9811,19 @@ public: "depth prefetch performed final target acquisition"); auto target_parent = - make_target_desc(base, target_mip_size * 2, {2, 2, 1}); + make_target_desc(base, target_mip_size * 2, {4, 4, 1}); target_parent.type = BindingType::RenderTarget; target_parent.info.resources.levels = 2; - target_parent.info.mip_layout[0] = {0, target_mip_size, 2, 2}; - target_parent.info.mip_layout[1] = {target_mip_size, target_mip_size, 1, - 1}; + target_parent.info.mip_layout[0] = {0, target_mip_size, 4, 4}; + target_parent.info.mip_layout[1] = {target_mip_size, target_mip_size, 2, + 2}; target_parent.view_info.usage = vk::ImageUsageFlagBits::eColorAttachment; auto target_base_subresource = - make_target_desc(base, target_mip_size, {2, 2, 1}); + make_target_desc(base, target_mip_size, {4, 4, 1}); const auto target_base_subresource_id = texture_cache.FindImage(target_base_subresource); auto target_subresource = - make_target_desc(base + target_mip_size, target_mip_size, {1, 1, 1}); + make_target_desc(base + target_mip_size, target_mip_size, {2, 2, 1}); const auto target_subresource_id = texture_cache.FindImage(target_subresource); const auto *target_subresource_owner = @@ -9809,18 +9860,10 @@ public: "target overlap did not transfer target state to the merged " "owner"); RenderColorInfo rebound_color{}; - rebound_color.type = RenderColorType::RenderTexture; rebound_color.desc = target_subresource; rebound_color.image_id = target_subresource_id; - rebound_color.format = target_subresource.view_info.format; - rebound_color.extent = {1, 1}; - rebound_color.samples = 1; RenderDepthInfo rebound_depth{}; rebound_depth.desc = depth; - rebound_depth.format = depth.info.pixel_format; - rebound_depth.width = 1; - rebound_depth.height = 1; - rebound_depth.samples = 1; rebound_depth.image_id = depth_id; scheduler.Finish(); Require(name, "deferred target slot erasure", @@ -9829,18 +9872,20 @@ public: "the displaced target slot was not erased after GPU completion"); auto rebound_rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &rebound_color, 1, rebound_depth); + Require(name, "guest target extent after host mip remap", + rebound_color.desc.view_info.base_level == 1 && + rebound_color.guest_mip_level == 0 && + rebound_color.Extent() == vk::Extent2D{2, 2}, + "remapping a guest target into its parent mip shrank the guest " + "render area twice"); const auto stencil_proxy_id = texture_cache.FindImageFromRange( stencil_address, stencil_layout.size, false); Require( name, "production target rebind", rebound_color.image_id == target_parent_id && - rebound_color.image_view != nullptr && - rebound_depth.image_view != nullptr && + rebound_rendering.color_attachments[0].image_view != nullptr && + rebound_rendering.depth_stencil_attachment.image_view != nullptr && rebound_rendering.num_color_attachments == 1 && - rebound_rendering.color_attachments[0].image_view == - rebound_color.image_view && - rebound_rendering.depth_stencil_attachment.image_view == - rebound_depth.image_view && rebound_rendering.width == 1 && rebound_rendering.height == 1 && texture_cache.GetImage(target_parent_id).binding.is_target && texture_cache.GetImage(target_parent_id).usage.render_target && @@ -9878,29 +9923,17 @@ public: const auto ordered_depth_id = texture_cache.FindImage(ordered_depth_desc); RenderExecutorTestAccess::BindRenderTarget(executor, ordered_depth_id); RenderColorInfo ordered_color{}; - ordered_color.type = RenderColorType::RenderTexture; ordered_color.desc = ordered_color_desc; ordered_color.image_id = stale_ordered_color; - ordered_color.format = ordered_color_desc.view_info.format; - ordered_color.extent = {1, 1}; - ordered_color.samples = 1; RenderDepthInfo ordered_depth{}; ordered_depth.desc = ordered_depth_desc; - ordered_depth.format = ordered_depth_desc.info.pixel_format; - ordered_depth.width = 1; - ordered_depth.height = 1; - ordered_depth.samples = 1; ordered_depth.image_id = ordered_depth_id; auto ordered_rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &ordered_color, 1, ordered_depth); Require(name, "color-before-depth acquisition order", ordered_color.image_id != stale_ordered_color && - ordered_color.image_view != nullptr && - ordered_depth.image_view != nullptr && - ordered_rendering.color_attachments[0].image_view == - ordered_color.image_view && - ordered_rendering.depth_stencil_attachment.image_view == - ordered_depth.image_view && + ordered_rendering.color_attachments[0].image_view != nullptr && + ordered_rendering.depth_stencil_attachment.image_view != nullptr && texture_cache.GetImage(ordered_color.image_id).depth_id == ordered_depth.image_id, "depth acquisition ran before the stale color target was " @@ -9937,11 +9970,11 @@ public: ShaderStageRuntime runtime{&program, std::move(snapshot)}; auto prepared = context.GetRenderExecutor().PrepareBindings(runtime); - const auto sampled_stencil_id = prepared.resources.images[0].image_id; + const auto sampled_stencil_id = prepared.images[0].image_id; Require(name, "first stencil discovery", - prepared.resources.images.size() == 1 && + prepared.images.size() == 1 && sampled_stencil_id != depth_id && - prepared.resources.images[0].image_view == nullptr && + prepared.images[0].image_view == nullptr && texture_cache.GetImage(sampled_stencil_id).binding.is_bound && !texture_cache.GetImage(stencil_proxy_id).binding.is_bound && !texture_cache.GetImage(stencil_proxy_id).binding.is_target, @@ -9950,14 +9983,13 @@ public: context.GetRenderExecutor().RebindImages(prepared); Require(name, "first stencil acquisition", - prepared.resources.images[0].image_id == sampled_stencil_id && - prepared.resources.images[0].image_view != nullptr && + prepared.images[0].image_id == sampled_stencil_id && + prepared.images[0].image_view != nullptr && texture_cache.GetImage(sampled_stencil_id).usage.texture, "the first sampled-stencil image was not finally acquired"); RenderExecutorTestAccess::ResetBindings(executor); RenderDepthInfo reassociated_depth = rebound_depth; - reassociated_depth.image_view = nullptr; RenderColorInfo no_reassociated_color{}; (void)RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &no_reassociated_color, 0, @@ -9971,17 +10003,17 @@ public: auto redirected = context.GetRenderExecutor().PrepareBindings(runtime); Require(name, "redirected owner discovery", - redirected.resources.images.size() == 1 && - redirected.resources.images[0].image_id == depth_id && - redirected.resources.images[0].image_view == nullptr && + redirected.images.size() == 1 && + redirected.images[0].image_id == depth_id && + redirected.images[0].image_view == nullptr && texture_cache.GetImage(depth_id).binding.is_bound && !texture_cache.GetImage(sampled_stencil_id).binding.is_bound, "the established stencil association did not redirect the next " "discovery to the depth owner"); context.GetRenderExecutor().RebindImages(redirected); Require(name, "second-pass stencil acquisition", - redirected.resources.images[0].image_id == depth_id && - redirected.resources.images[0].image_view != nullptr && + redirected.images[0].image_id == depth_id && + redirected.images[0].image_view != nullptr && texture_cache.GetImage(depth_id).usage.texture, "RebindImages did not acquire the associated depth owner"); RenderExecutorTestAccess::ResetBindings(executor); @@ -25704,7 +25736,7 @@ void CheckStencilAttachmentAccess() { void CheckDepthAttachmentWrites() { RenderDepthInfo target{}; - target.format = vk::Format::eD32SfloatS8Uint; + target.desc.view_info.format = vk::Format::eD32SfloatS8Uint; target.depth_write_enable = true; Require("DepthAttachmentWrites", "disabled depth test", !target.AttachmentWriteAspects(), @@ -25756,7 +25788,7 @@ void CheckDepthAttachmentWrites() { target.AttachmentWriteAspects() == vk::ImageAspectFlagBits::eStencil, "stencil attachment clear did not claim stencil"); - target.format = vk::Format::eD32Sfloat; + target.desc.view_info.format = vk::Format::eD32Sfloat; Require("DepthAttachmentWrites", "missing stencil aspect", !target.AttachmentWriteAspects(), "depth-only format claimed a stencil write"); @@ -25804,7 +25836,7 @@ void CheckDynamicRenderingState() { "depth/stencil formats did not participate in pipeline identity"); RenderDepthInfo attachment{}; - attachment.format = vk::Format::eD32SfloatS8Uint; + attachment.desc.view_info.format = vk::Format::eD32SfloatS8Uint; Require("DynamicRenderingState", "read-only depth/stencil layout", depth_attachment_layout(attachment) == vk::ImageLayout::eDepthStencilReadOnlyOptimal, diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 74aeafeed..1d5491588 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -1136,11 +1136,22 @@ void TestNativeShaderResourceDependencies() { .info = program.info, .bindings = program.bindings, }; - const auto writes = CollectShaderBufferWrites(compiled, resources); - Check(writes == - std::vector({{0x1000, 48}, {0x2000, 64}}), - "graphics/compute write collector lost or invented a storage-buffer " - "range"); + ShaderStageRuntime runtime{.program = &compiled, .resources = resources}; + Check(HasShaderBufferWrites(runtime), + "graphics/compute write predicate lost nonempty written buffers"); + set_buffer(0, 0, 16, 3); + set_buffer(2, 0x2000, 0, 0); + runtime.resources = resources; + Check(!HasShaderBufferWrites(runtime), + "graphics/compute write predicate included null, empty, or read-only buffers"); + set_buffer(2, 0x2000, 0, 64); + runtime.resources = resources; + Check(HasShaderBufferWrites(runtime), + "graphics/compute write predicate lost a byte-addressed buffer"); + set_buffer(2, 0x2000, 0x3FFF, UINT32_MAX); + runtime.resources = resources; + Check(HasShaderBufferWrites(runtime), + "graphics/compute write predicate lost a maximum-size strided buffer"); VulkanBuffer buffer; buffer.buffer = reinterpret_cast(uintptr_t{1});