diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 73417c55..0de0f425 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -82,7 +82,7 @@ ComputePipeline::ComputePipeline(const Instance& instance_, Scheduler& scheduler ComputePipeline::~ComputePipeline() = default; -void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& staging, +bool ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& staging, VideoCore::TextureCache& texture_cache) const { // Bind resource buffers and textures. boost::container::static_vector buffer_infos; @@ -93,12 +93,11 @@ void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& s for (const auto& buffer : info.buffers) { const auto vsharp = info.ReadUd(buffer.sgpr_base, buffer.dword_offset); const u32 size = vsharp.GetSize(); - const VAddr addr = vsharp.base_address.Value(); - texture_cache.OnCpuWrite(addr); - const u32 offset = staging.Copy(addr, size, + const VAddr address = vsharp.base_address.Value(); + texture_cache.OnCpuWrite(address); + const u32 offset = staging.Copy(address, size, buffer.is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment()); - // const auto [vk_buffer, offset] = memory->GetVulkanBuffer(addr); buffer_infos.emplace_back(staging.Handle(), offset, size); set_writes.push_back({ .dstSet = VK_NULL_HANDLE, @@ -110,12 +109,18 @@ void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& s .pBufferInfo = &buffer_infos.back(), }); + // Most of the time when a metadata is updated with a shader it gets cleared. It means we + // can skip the whole dispatch and update the tracked state instead. Also, it is not + // intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we will + // need its full emulation anyways. For cases of metadata read a warning will be logged. if (buffer.is_storage) { - // In most of the cases we can skip the whole dispatch when meta is written - texture_cache.TouchMeta(addr, true); + if (texture_cache.TouchMeta(address, true)) { + LOG_TRACE(Render_Vulkan, "Metadata update skipped"); + return false; + } } else { - if (texture_cache.IsMeta(addr)) { - LOG_WARNING(Render_Vulkan, "Unexpected meta data read by a CS shader"); + if (texture_cache.IsMeta(address)) { + LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (buffer)"); } } } @@ -133,6 +138,10 @@ void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& s : vk::DescriptorType::eSampledImage, .pImageInfo = &image_infos.back(), }); + + if (texture_cache.IsMeta(tsharp.Address())) { + LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a CS shader (texture)"); + } } for (const auto& sampler : info.samplers) { const auto ssharp = info.ReadUd(sampler.sgpr_base, sampler.dword_offset); @@ -148,11 +157,13 @@ void ComputePipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& s }); } - if (!set_writes.empty()) { - const auto cmdbuf = scheduler.CommandBuffer(); - cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, - set_writes); + if (set_writes.empty()) { + return false; } + + const auto cmdbuf = scheduler.CommandBuffer(); + cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eCompute, *pipeline_layout, 0, set_writes); + return true; } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 781bd81b..1d074814 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -31,7 +31,7 @@ public: return *pipeline; } - void BindResources(Core::MemoryManager* memory, StreamBuffer& staging, + bool BindResources(Core::MemoryManager* memory, StreamBuffer& staging, VideoCore::TextureCache& texture_cache) const; private: diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index bd7a8029..0fd7e5e5 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -327,8 +327,9 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& for (const auto& stage : stages) { for (const auto& buffer : stage.buffers) { const auto vsharp = stage.ReadUd(buffer.sgpr_base, buffer.dword_offset); + const VAddr address = vsharp.base_address.Value(); const u32 size = vsharp.GetSize(); - const u32 offset = staging.Copy(vsharp.base_address.Value(), size, + const u32 offset = staging.Copy(address, size, buffer.is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment()); buffer_infos.emplace_back(staging.Handle(), offset, size); @@ -341,6 +342,10 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& : vk::DescriptorType::eUniformBuffer, .pBufferInfo = &buffer_infos.back(), }); + + if (texture_cache.IsMeta(address)) { + LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (buffer)"); + } } for (const auto& image : stage.images) { @@ -357,6 +362,10 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& : vk::DescriptorType::eSampledImage, .pImageInfo = &image_infos.back(), }); + + if (texture_cache.IsMeta(tsharp.Address())) { + LOG_WARNING(Render_Vulkan, "Unexpected metadata read by a PS shader (texture)"); + } } for (const auto& sampler : stage.samplers) { const auto ssharp = diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 06a03758..d378bd15 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -128,7 +128,10 @@ void Rasterizer::DispatchDirect() { return; } - pipeline->BindResources(memory, vertex_index_buffer, texture_cache); + const auto has_resources = pipeline->BindResources(memory, vertex_index_buffer, texture_cache); + if (!has_resources) { + return; + } cmdbuf.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->Handle()); cmdbuf.dispatch(cs_program.dim_x, cs_program.dim_y, cs_program.dim_z); diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 22006eb8..750cc437 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -268,7 +268,7 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, } Transit(vk::ImageLayout::eGeneral, vk::AccessFlagBits::eNone); -} // namespace VideoCore +} void Image::Transit(vk::ImageLayout dst_layout, vk::Flags dst_mask) { if (dst_layout == layout && dst_mask == access_mask) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 5e6412dc..8778f3e8 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -84,11 +84,13 @@ public: return false; } - void TouchMeta(VAddr address, bool is_clear) { + bool TouchMeta(VAddr address, bool is_clear) { auto it = surface_metas.find(address); if (it != surface_metas.end()) { it.value().is_cleared = is_clear; + return true; } + return false; } private: @@ -154,7 +156,7 @@ private: /// Register image in the page table void RegisterImage(ImageId image); - /// Register meta data surfaces attached to the image + /// Register metadata surfaces attached to the image void RegisterMeta(const ImageInfo& info, ImageId image); /// Unregister image from the page table