mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-09 14:53:19 +00:00
Another intent on load store op none impl
This commit is contained in:
@@ -136,6 +136,37 @@ RenderingFormats PipelineFormats(const FixedPipelineState& state, const Device&
|
|||||||
return MakeRenderingFormats(device, color_formats, depth_format);
|
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 NumAttachments(const FixedPipelineState& state) {
|
||||||
size_t num{};
|
size_t num{};
|
||||||
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
|
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
|
||||||
@@ -586,7 +617,8 @@ bool GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
|||||||
if (buffer_cache.TakeDrawHazard()) {
|
if (buffer_cache.TakeDrawHazard()) {
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
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();
|
buffer_cache.CommitDrawWrites();
|
||||||
if (!is_built.load(std::memory_order::relaxed)) {
|
if (!is_built.load(std::memory_order::relaxed)) {
|
||||||
// Wait for the pipeline to be built
|
// 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);
|
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||||
if (!pipeline->Configure(is_indexed))
|
if (!pipeline->Configure(is_indexed))
|
||||||
return;
|
return;
|
||||||
scheduler.MarkDepthWrites(maxwell3d->regs.depth_test_enable != 0 &&
|
|
||||||
maxwell3d->regs.depth_write_enabled != 0);
|
|
||||||
|
|
||||||
UpdateDynamicStates(pipeline->HasDynamicVertexInput());
|
UpdateDynamicStates(pipeline->HasDynamicVertexInput());
|
||||||
|
|
||||||
@@ -584,7 +582,6 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
|||||||
if (aspect_flags == 0) {
|
if (aspect_flags == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduler.MarkDepthWrites(!can_defer_clear && (aspect_flags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0);
|
|
||||||
|
|
||||||
if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF &&
|
if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF &&
|
||||||
regs.stencil_front_mask != 0) {
|
regs.stencil_front_mask != 0) {
|
||||||
|
|||||||
@@ -27,6 +27,15 @@
|
|||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
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,
|
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
|
||||||
vk::CommandBuffer upload_cmdbuf) {
|
vk::CommandBuffer upload_cmdbuf) {
|
||||||
@@ -104,6 +113,7 @@ void Scheduler::DispatchWork() {
|
|||||||
work_queue.push(std::move(chunk));
|
work_queue.push(std::move(chunk));
|
||||||
}
|
}
|
||||||
event_cv.notify_all();
|
event_cv.notify_all();
|
||||||
|
recorded_attachments = nullptr;
|
||||||
AcquireNewChunk();
|
AcquireNewChunk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,7 +123,8 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer,
|
|||||||
PublishComputeWrites();
|
PublishComputeWrites();
|
||||||
state.framebuffer_id = framebuffer->Id();
|
state.framebuffer_id = framebuffer->Id();
|
||||||
++renderpass_serial;
|
++renderpass_serial;
|
||||||
renderpass_depth_writes = false;
|
attachments_touched = 0;
|
||||||
|
attachments_written = 0;
|
||||||
|
|
||||||
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||||
const VkExtent2D render_area = attachments.render_area.extent;
|
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);
|
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();
|
num_renderpass_images = framebuffer->NumImages();
|
||||||
renderpass_images = framebuffer->Images();
|
renderpass_images = framebuffer->Images();
|
||||||
renderpass_image_ranges = framebuffer->ImageRanges();
|
renderpass_image_ranges = framebuffer->ImageRanges();
|
||||||
@@ -161,7 +178,9 @@ void Scheduler::RealizeDeferredClear() {
|
|||||||
}
|
}
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
BeginRenderPassImpl(dc.framebuffer, attachments);
|
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,
|
bool Scheduler::DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot,
|
||||||
@@ -201,17 +220,16 @@ void Scheduler::FlushDeferredClear() {
|
|||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) {
|
||||||
if (deferred_clear.framebuffer == framebuffer) {
|
if (deferred_clear.framebuffer == framebuffer) {
|
||||||
RealizeDeferredClear();
|
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) {
|
attachments_touched |= touched;
|
||||||
return;
|
attachments_written |= written;
|
||||||
}
|
|
||||||
// Ends any active pass and realizes a deferred clear
|
|
||||||
EndRenderPass();
|
|
||||||
BeginRenderPassImpl(framebuffer, framebuffer->Attachments());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::RequestOutsideRenderPassOperationContext() {
|
void Scheduler::RequestOutsideRenderPassOperationContext() {
|
||||||
@@ -224,6 +242,28 @@ void Scheduler::RequestComputeDispatchContext() {
|
|||||||
compute_writes = true;
|
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() {
|
void Scheduler::PublishComputeWrites() {
|
||||||
if (!std::exchange(compute_writes, false)) {
|
if (!std::exchange(compute_writes, false)) {
|
||||||
return;
|
return;
|
||||||
@@ -406,6 +446,10 @@ void Scheduler::EndRenderPass()
|
|||||||
if (state.framebuffer_id == 0) {
|
if (state.framebuffer_id == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (recorded_attachments != nullptr) {
|
||||||
|
RelaxAttachmentOps(*recorded_attachments);
|
||||||
|
recorded_attachments = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
|
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ struct RenderingAttachments;
|
|||||||
/// OpenGL-like operations on Vulkan command buffers.
|
/// OpenGL-like operations on Vulkan command buffers.
|
||||||
class Scheduler {
|
class Scheduler {
|
||||||
public:
|
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);
|
explicit Scheduler(const Device& device, StateTracker& state_tracker);
|
||||||
~Scheduler();
|
~Scheduler();
|
||||||
|
|
||||||
@@ -59,7 +63,8 @@ public:
|
|||||||
void DispatchWork();
|
void DispatchWork();
|
||||||
|
|
||||||
/// Requests to begin a renderpass.
|
/// 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.
|
/// Defers a full-attachment color clear so it becomes the next render pass.
|
||||||
bool DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot, const VkClearValue& value);
|
bool DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot, const VkClearValue& value);
|
||||||
@@ -100,12 +105,8 @@ public:
|
|||||||
renderpass_writes = true;
|
renderpass_writes = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkDepthWrites(bool writes) noexcept {
|
|
||||||
renderpass_depth_writes |= writes;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasDepthWrites() const noexcept {
|
bool HasDepthWrites() const noexcept {
|
||||||
return renderpass_depth_writes;
|
return (attachments_written & DEPTH_ATTACHMENT_BIT) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the pipeline to the current execution context.
|
/// Update the pipeline to the current execution context.
|
||||||
@@ -235,6 +236,10 @@ private:
|
|||||||
command(cmdbuf, upload_cmdbuf);
|
command(cmdbuf, upload_cmdbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T& Get() noexcept {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T command;
|
T command;
|
||||||
};
|
};
|
||||||
@@ -244,16 +249,18 @@ private:
|
|||||||
void ExecuteAll(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf);
|
void ExecuteAll(vk::CommandBuffer cmdbuf, vk::CommandBuffer upload_cmdbuf);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool Record(T& command) {
|
T* Record(T& command) {
|
||||||
using FuncType = TypedCommand<T>;
|
using FuncType = TypedCommand<T>;
|
||||||
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
|
static_assert(sizeof(FuncType) < sizeof(data), "Lambda is too large");
|
||||||
|
|
||||||
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
|
command_offset = Common::AlignUp(command_offset, alignof(FuncType));
|
||||||
if (command_offset > sizeof(data) - sizeof(FuncType)) {
|
if (command_offset > sizeof(data) - sizeof(FuncType)) {
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Command* const current_last = last;
|
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) {
|
if (current_last) {
|
||||||
current_last->SetNext(last);
|
current_last->SetNext(last);
|
||||||
@@ -261,7 +268,7 @@ private:
|
|||||||
first = last;
|
first = last;
|
||||||
}
|
}
|
||||||
command_offset += sizeof(FuncType);
|
command_offset += sizeof(FuncType);
|
||||||
return true;
|
return &recorded->Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkSubmit() {
|
void MarkSubmit() {
|
||||||
@@ -322,6 +329,8 @@ private:
|
|||||||
|
|
||||||
void PublishComputeWrites();
|
void PublishComputeWrites();
|
||||||
|
|
||||||
|
void RelaxAttachmentOps(RenderingAttachments& attachments) const;
|
||||||
|
|
||||||
void AcquireNewChunk();
|
void AcquireNewChunk();
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
@@ -345,8 +354,10 @@ private:
|
|||||||
u64 renderpass_serial = 0;
|
u64 renderpass_serial = 0;
|
||||||
u64 wfi_serial = 0;
|
u64 wfi_serial = 0;
|
||||||
bool renderpass_writes = false;
|
bool renderpass_writes = false;
|
||||||
bool renderpass_depth_writes = false;
|
|
||||||
bool compute_writes = false;
|
bool compute_writes = false;
|
||||||
|
u32 attachments_touched = 0;
|
||||||
|
u32 attachments_written = 0;
|
||||||
|
RenderingAttachments* recorded_attachments = nullptr;
|
||||||
VkMemoryBarrier2 renderpass_write_barrier{};
|
VkMemoryBarrier2 renderpass_write_barrier{};
|
||||||
VkMemoryBarrier2 compute_write_barrier{};
|
VkMemoryBarrier2 compute_write_barrier{};
|
||||||
VkMemoryBarrier2 upload_write_barrier{};
|
VkMemoryBarrier2 upload_write_barrier{};
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
EXTENSION(KHR, SWAPCHAIN, swapchain) \
|
EXTENSION(KHR, SWAPCHAIN, swapchain) \
|
||||||
EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
|
EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
|
||||||
EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \
|
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, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \
|
||||||
EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
|
EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
|
||||||
EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
|
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.
|
/// 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 {
|
bool IsExtDepthBiasControlSupported() const {
|
||||||
return extensions.depth_bias_control;
|
return extensions.depth_bias_control;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user