Another intent on load store op none impl

This commit is contained in:
CamilleLaVey
2026-09-26 17:21:32 -04:00
parent 656370e70a
commit f3ce6acf53
5 changed files with 116 additions and 26 deletions
@@ -136,6 +136,37 @@ RenderingFormats PipelineFormats(const FixedPipelineState& state, const Device&
return MakeRenderingFormats(device, color_formats, depth_format);
}
struct AttachmentAccess {
u32 touched;
u32 written;
};
AttachmentAccess MakeAttachmentAccess(const Maxwell& regs) {
AttachmentAccess access{};
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
size_t mask_index = index;
if (regs.color_mask_common) {
mask_index = 0;
}
const auto& mask = regs.color_mask[mask_index];
if (mask.R || mask.G || mask.B || mask.A) {
access.touched |= 1u << index;
access.written |= 1u << index;
}
}
if (regs.depth_test_enable || regs.depth_bounds_enable) {
access.touched |= Scheduler::DEPTH_ATTACHMENT_BIT;
}
if (regs.depth_test_enable && regs.depth_write_enabled) {
access.written |= Scheduler::DEPTH_ATTACHMENT_BIT;
}
if (regs.stencil_enable) {
access.touched |= Scheduler::STENCIL_ATTACHMENT_BIT;
access.written |= Scheduler::STENCIL_ATTACHMENT_BIT;
}
return access;
}
size_t NumAttachments(const FixedPipelineState& state) {
size_t num{};
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
@@ -586,7 +617,8 @@ bool GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
if (buffer_cache.TakeDrawHazard()) {
scheduler.RequestOutsideRenderPassOperationContext();
}
scheduler.RequestRenderpass(texture_cache.GetFramebuffer());
const AttachmentAccess access = MakeAttachmentAccess(maxwell3d->regs);
scheduler.RequestRenderpass(texture_cache.GetFramebuffer(), access.touched, access.written);
buffer_cache.CommitDrawWrites();
if (!is_built.load(std::memory_order::relaxed)) {
// Wait for the pipeline to be built
@@ -263,8 +263,6 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, bool skip_empty, Func&& draw
pipeline->SetEngine(maxwell3d, gpu_memory);
if (!pipeline->Configure(is_indexed))
return;
scheduler.MarkDepthWrites(maxwell3d->regs.depth_test_enable != 0 &&
maxwell3d->regs.depth_write_enabled != 0);
UpdateDynamicStates(pipeline->HasDynamicVertexInput());
@@ -584,7 +582,6 @@ void RasterizerVulkan::Clear(u32 layer_count) {
if (aspect_flags == 0) {
return;
}
scheduler.MarkDepthWrites(!can_defer_clear && (aspect_flags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0);
if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF &&
regs.stencil_front_mask != 0) {
+55 -11
View File
@@ -27,6 +27,15 @@
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
namespace {
struct BeginRenderingCommand {
void operator()(vk::CommandBuffer cmdbuf, vk::CommandBuffer) const {
BeginRendering(cmdbuf, attachments);
}
RenderingAttachments attachments;
};
} // Anonymous namespace
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
vk::CommandBuffer upload_cmdbuf) {
@@ -104,6 +113,7 @@ void Scheduler::DispatchWork() {
work_queue.push(std::move(chunk));
}
event_cv.notify_all();
recorded_attachments = nullptr;
AcquireNewChunk();
}
}
@@ -113,7 +123,8 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer,
PublishComputeWrites();
state.framebuffer_id = framebuffer->Id();
++renderpass_serial;
renderpass_depth_writes = false;
attachments_touched = 0;
attachments_written = 0;
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
const VkExtent2D render_area = attachments.render_area.extent;
@@ -123,7 +134,13 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer,
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
}
Record([attachments](vk::CommandBuffer cmdbuf) { BeginRendering(cmdbuf, attachments); });
BeginRenderingCommand command{attachments};
BeginRenderingCommand* recorded = chunk->Record(command);
if (recorded == nullptr) {
DispatchWork();
recorded = chunk->Record(command);
}
recorded_attachments = &recorded->attachments;
num_renderpass_images = framebuffer->NumImages();
renderpass_images = framebuffer->Images();
renderpass_image_ranges = framebuffer->ImageRanges();
@@ -161,7 +178,9 @@ void Scheduler::RealizeDeferredClear() {
}
EndRenderPass();
BeginRenderPassImpl(dc.framebuffer, attachments);
renderpass_depth_writes = dc.depth_stencil;
if (dc.depth_stencil) {
attachments_written |= DEPTH_ATTACHMENT_BIT | STENCIL_ATTACHMENT_BIT;
}
}
bool Scheduler::DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot,
@@ -201,17 +220,16 @@ void Scheduler::FlushDeferredClear() {
EndRenderPass();
}
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) {
if (deferred_clear.framebuffer == framebuffer) {
RealizeDeferredClear();
return;
} else if (framebuffer->Id() != state.framebuffer_id) {
// Ends any active pass and realizes a deferred clear
EndRenderPass();
BeginRenderPassImpl(framebuffer, framebuffer->Attachments());
}
if (framebuffer->Id() == state.framebuffer_id) {
return;
}
// Ends any active pass and realizes a deferred clear
EndRenderPass();
BeginRenderPassImpl(framebuffer, framebuffer->Attachments());
attachments_touched |= touched;
attachments_written |= written;
}
void Scheduler::RequestOutsideRenderPassOperationContext() {
@@ -224,6 +242,28 @@ void Scheduler::RequestComputeDispatchContext() {
compute_writes = true;
}
void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const {
const bool load_op_none = device.IsLoadOpNoneSupported();
const auto relax = [&](VkRenderingAttachmentInfo& attachment, u32 bit) {
if (attachment.imageView == VK_NULL_HANDLE ||
attachment.resolveMode != VK_RESOLVE_MODE_NONE ||
attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ||
attachment.storeOp != VK_ATTACHMENT_STORE_OP_STORE ||
(attachments_written & bit) != 0) {
return;
}
attachment.storeOp = VK_ATTACHMENT_STORE_OP_NONE;
if (load_op_none && (attachments_touched & bit) == 0) {
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_NONE;
}
};
for (u32 slot = 0; slot < attachments.num_colors; ++slot) {
relax(attachments.colors[slot], 1u << slot);
}
relax(attachments.depth, DEPTH_ATTACHMENT_BIT);
relax(attachments.stencil, STENCIL_ATTACHMENT_BIT);
}
void Scheduler::PublishComputeWrites() {
if (!std::exchange(compute_writes, false)) {
return;
@@ -406,6 +446,10 @@ void Scheduler::EndRenderPass()
if (state.framebuffer_id == 0) {
return;
}
if (recorded_attachments != nullptr) {
RelaxAttachmentOps(*recorded_attachments);
recorded_attachments = nullptr;
}
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
+22 -11
View File
@@ -42,6 +42,10 @@ struct RenderingAttachments;
/// OpenGL-like operations on Vulkan command buffers.
class Scheduler {
public:
static constexpr u32 DEPTH_ATTACHMENT_BIT = 1u << 8;
static constexpr u32 STENCIL_ATTACHMENT_BIT = 1u << 9;
static constexpr u32 ALL_ATTACHMENTS = 0x3FF;
explicit Scheduler(const Device& device, StateTracker& state_tracker);
~Scheduler();
@@ -59,7 +63,8 @@ public:
void DispatchWork();
/// Requests to begin a renderpass.
void RequestRenderpass(const Framebuffer* framebuffer);
void RequestRenderpass(const Framebuffer* framebuffer, u32 touched = ALL_ATTACHMENTS,
u32 written = ALL_ATTACHMENTS);
/// Defers a full-attachment color clear so it becomes the next render pass.
bool DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot, const VkClearValue& value);
@@ -100,12 +105,8 @@ public:
renderpass_writes = true;
}
void MarkDepthWrites(bool writes) noexcept {
renderpass_depth_writes |= writes;
}
bool HasDepthWrites() const noexcept {
return renderpass_depth_writes;
return (attachments_written & DEPTH_ATTACHMENT_BIT) != 0;
}
/// Update the pipeline to the current execution context.
@@ -235,6 +236,10 @@ private:
command(cmdbuf, upload_cmdbuf);
}
T& Get() noexcept {
return command;
}
private:
T command;
};
@@ -244,16 +249,18 @@ private:
void ExecuteAll(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf);
template <typename T>
bool Record(T& command) {
T* Record(T& command) {
using FuncType = TypedCommand<T>;
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
if (command_offset > sizeof(data) - sizeof(FuncType)) {
return false;
return nullptr;
}
Command* const current_last = last;
last = new (data.data() + command_offset) FuncType(std::move(command));
FuncType* const recorded =
new (data.data() + command_offset) FuncType(std::move(command));
last = recorded;
if (current_last) {
current_last->SetNext(last);
@@ -261,7 +268,7 @@ private:
first = last;
}
command_offset += sizeof(FuncType);
return true;
return &recorded->Get();
}
void MarkSubmit() {
@@ -322,6 +329,8 @@ private:
void PublishComputeWrites();
void RelaxAttachmentOps(RenderingAttachments& attachments) const;
void AcquireNewChunk();
const Device& device;
@@ -345,8 +354,10 @@ private:
u64 renderpass_serial = 0;
u64 wfi_serial = 0;
bool renderpass_writes = false;
bool renderpass_depth_writes = false;
bool compute_writes = false;
u32 attachments_touched = 0;
u32 attachments_written = 0;
RenderingAttachments* recorded_attachments = nullptr;
VkMemoryBarrier2 renderpass_write_barrier{};
VkMemoryBarrier2 compute_write_barrier{};
VkMemoryBarrier2 upload_write_barrier{};
@@ -106,6 +106,8 @@ VK_DEFINE_HANDLE(VmaAllocator)
EXTENSION(KHR, SWAPCHAIN, swapchain) \
EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \
EXTENSION(KHR, LOAD_STORE_OP_NONE, load_store_op_none) \
EXTENSION(EXT, LOAD_STORE_OP_NONE, load_store_op_none_ext) \
EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \
EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
@@ -669,6 +671,10 @@ FN_MAX_LIMIT_LIST
}
/// Returns true if the device supports VK_EXT_depth_bias_control.
bool IsLoadOpNoneSupported() const {
return extensions.load_store_op_none || extensions.load_store_op_none_ext;
}
bool IsExtDepthBiasControlSupported() const {
return extensions.depth_bias_control;
}