mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
Address some regressions with TFB + SSBO's due to WFI removal
This commit is contained in:
@@ -137,6 +137,22 @@ public:
|
||||
content_serial = ++next_content_serial;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool HasDrawHazard(u64 pass, u64 wfi, DAddr addr, u64 size) const noexcept {
|
||||
return draw_write_pass == pass && draw_write_wfi < wfi && addr < draw_write_end &&
|
||||
addr + size > draw_write_begin;
|
||||
}
|
||||
|
||||
void MarkDrawWrite(u64 pass, u64 wfi, DAddr addr, u64 size) noexcept {
|
||||
if (draw_write_pass != pass) {
|
||||
draw_write_pass = pass;
|
||||
draw_write_begin = addr;
|
||||
draw_write_end = addr + size;
|
||||
}
|
||||
draw_write_wfi = wfi;
|
||||
draw_write_begin = (std::min)(draw_write_begin, addr);
|
||||
draw_write_end = (std::max)(draw_write_end, addr + size);
|
||||
}
|
||||
|
||||
private:
|
||||
static inline u64 next_content_serial = 0;
|
||||
|
||||
@@ -147,6 +163,10 @@ private:
|
||||
size_t size_bytes = 0;
|
||||
u64 write_tick = 0;
|
||||
u64 content_serial = ++next_content_serial;
|
||||
u64 draw_write_pass = 0;
|
||||
u64 draw_write_wfi = 0;
|
||||
DAddr draw_write_begin = 0;
|
||||
DAddr draw_write_end = 0;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
||||
@@ -366,6 +366,13 @@ void BufferCache<P>::DisableGraphicsUniformBuffer(size_t stage, u32 index) {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateGraphicsBuffers(bool is_indexed) {
|
||||
if constexpr (!IS_OPENGL) {
|
||||
draw_writes.clear();
|
||||
draw_pass = runtime.RenderPassSerial();
|
||||
draw_wfi = runtime.WaitForIdleSerial();
|
||||
draw_hazard = false;
|
||||
recording_draw = true;
|
||||
}
|
||||
ReclaimInline();
|
||||
do {
|
||||
channel_state->has_deleted_buffers = false;
|
||||
@@ -373,6 +380,24 @@ void BufferCache<P>::UpdateGraphicsBuffers(bool is_indexed) {
|
||||
} while (channel_state->has_deleted_buffers);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::TakeDrawHazard() noexcept {
|
||||
return std::exchange(draw_hazard, false);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::CommitDrawWrites() {
|
||||
recording_draw = false;
|
||||
if (draw_writes.empty()) {
|
||||
return;
|
||||
}
|
||||
const u64 pass = runtime.RenderPassSerial();
|
||||
for (const DrawWrite& write : draw_writes) {
|
||||
slot_buffers[write.buffer_id].MarkDrawWrite(pass, draw_wfi, write.device_addr, write.size);
|
||||
}
|
||||
runtime.MarkRenderPassWrites();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::UpdateComputeBuffers() {
|
||||
ReclaimInline();
|
||||
@@ -1550,6 +1575,9 @@ void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u3
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
buffer.setWriteTick(runtime.CurrentTick());
|
||||
buffer.MarkContentModified();
|
||||
if (recording_draw) {
|
||||
draw_writes.push_back({buffer_id, device_addr, size});
|
||||
}
|
||||
}
|
||||
memory_tracker.MarkRegionAsGpuModified(device_addr, size);
|
||||
gpu_modified_ranges.Add(device_addr, size);
|
||||
@@ -1770,6 +1798,9 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
|
||||
if constexpr (!IS_OPENGL) {
|
||||
draw_hazard |= buffer.HasDrawHazard(draw_pass, draw_wfi, device_addr, size);
|
||||
}
|
||||
upload_copies.clear();
|
||||
u64 total_size_bytes = 0;
|
||||
u64 largest_copy = 0;
|
||||
|
||||
@@ -260,6 +260,10 @@ public:
|
||||
|
||||
void UpdateComputeBuffers();
|
||||
|
||||
[[nodiscard]] bool TakeDrawHazard() noexcept;
|
||||
|
||||
void CommitDrawWrites();
|
||||
|
||||
void BindHostGeometryBuffers(bool is_indexed);
|
||||
|
||||
void BindHostStageBuffers(size_t stage);
|
||||
@@ -520,6 +524,17 @@ private:
|
||||
|
||||
boost::container::small_vector<BufferCopy, 4> upload_copies;
|
||||
|
||||
struct DrawWrite {
|
||||
BufferId buffer_id;
|
||||
DAddr device_addr;
|
||||
u32 size;
|
||||
};
|
||||
boost::container::small_vector<DrawWrite, 8> draw_writes;
|
||||
u64 draw_pass = 0;
|
||||
u64 draw_wfi = 0;
|
||||
bool draw_hazard = false;
|
||||
bool recording_draw = false;
|
||||
|
||||
MemoryTracker memory_tracker;
|
||||
Common::RangeSet<DAddr> uncommitted_gpu_modified_ranges;
|
||||
Common::RangeSet<DAddr> gpu_modified_ranges;
|
||||
|
||||
@@ -440,6 +440,18 @@ u64 BufferCacheRuntime::CurrentTick() {
|
||||
return scheduler.GetMasterSemaphore().CurrentTick();
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::RenderPassSerial() const noexcept {
|
||||
return scheduler.ActiveRenderPassSerial();
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::WaitForIdleSerial() const noexcept {
|
||||
return scheduler.WaitForIdleSerial();
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::MarkRenderPassWrites() noexcept {
|
||||
scheduler.MarkRenderPassWrites();
|
||||
}
|
||||
|
||||
u64 BufferCacheRuntime::KnownGpuTick() {
|
||||
return scheduler.GetMasterSemaphore().KnownGpuTick();
|
||||
}
|
||||
|
||||
@@ -112,6 +112,12 @@ public:
|
||||
|
||||
u64 CurrentTick();
|
||||
|
||||
u64 RenderPassSerial() const noexcept;
|
||||
|
||||
u64 WaitForIdleSerial() const noexcept;
|
||||
|
||||
void MarkRenderPassWrites() noexcept;
|
||||
|
||||
u64 KnownGpuTick();
|
||||
|
||||
void Wait(u64 buffer_tick);
|
||||
|
||||
@@ -595,7 +595,11 @@ bool GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_cache.TakeDrawHazard()) {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
scheduler.RequestRenderpass(texture_cache.GetFramebuffer());
|
||||
buffer_cache.CommitDrawWrites();
|
||||
if (!is_built.load(std::memory_order::relaxed)) {
|
||||
// Wait for the pipeline to be built
|
||||
scheduler.Record([this](vk::CommandBuffer) {
|
||||
|
||||
@@ -894,6 +894,7 @@ void RasterizerVulkan::FlushAndInvalidateRegion(DAddr addr, u64 size,
|
||||
|
||||
void RasterizerVulkan::WaitForIdle() {
|
||||
query_cache.NotifyWFI();
|
||||
scheduler.NotifyWaitForIdle();
|
||||
fence_manager.SignalOrdering();
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass
|
||||
state.renderpass = renderpass;
|
||||
state.framebuffer = framebuffer_handle;
|
||||
state.render_area = render_area;
|
||||
++renderpass_serial;
|
||||
|
||||
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||
const std::string render_pass_info =
|
||||
@@ -417,8 +418,17 @@ void Scheduler::EndRenderPass()
|
||||
Record([num_images = num_renderpass_images,
|
||||
images = renderpass_images,
|
||||
ranges = renderpass_image_ranges,
|
||||
has_transform_feedback = device.IsExtTransformFeedbackSupported()](
|
||||
num_memory_barriers =
|
||||
static_cast<size_t>(std::exchange(renderpass_writes, false))](
|
||||
vk::CommandBuffer cmdbuf) {
|
||||
static constexpr VkMemoryBarrier2 WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER,
|
||||
.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT,
|
||||
};
|
||||
std::array<VkImageMemoryBarrier2, 9> barriers;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
const VkImageSubresourceRange& range = ranges[i];
|
||||
@@ -459,20 +469,8 @@ void Scheduler::EndRenderPass()
|
||||
};
|
||||
}
|
||||
cmdbuf.EndRenderPass();
|
||||
cmdbuf.PipelineBarrier(0, {}, {}, vk::Span(barriers.data(), num_images));
|
||||
if (has_transform_feedback) {
|
||||
static constexpr VkMemoryBarrier2 XFB_OUTPUT_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||
.srcAccessMask = VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT
|
||||
| VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT
|
||||
| VK_ACCESS_2_TRANSFER_READ_BIT,
|
||||
};
|
||||
cmdbuf.PipelineBarrier(XFB_OUTPUT_BARRIER);
|
||||
}
|
||||
cmdbuf.PipelineBarrier(0, vk::Span(&WRITE_BARRIER, num_memory_barriers), {},
|
||||
vk::Span(barriers.data(), num_images));
|
||||
});
|
||||
|
||||
state.renderpass = VkRenderPass{};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
@@ -77,6 +78,25 @@ public:
|
||||
return state.renderpass != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
u64 ActiveRenderPassSerial() const noexcept {
|
||||
if (state.renderpass) {
|
||||
return renderpass_serial;
|
||||
}
|
||||
return (std::numeric_limits<u64>::max)();
|
||||
}
|
||||
|
||||
u64 WaitForIdleSerial() const noexcept {
|
||||
return wfi_serial;
|
||||
}
|
||||
|
||||
void NotifyWaitForIdle() noexcept {
|
||||
++wfi_serial;
|
||||
}
|
||||
|
||||
void MarkRenderPassWrites() noexcept {
|
||||
renderpass_writes = true;
|
||||
}
|
||||
|
||||
/// Update the pipeline to the current execution context.
|
||||
bool UpdateGraphicsPipeline(GraphicsPipeline* pipeline);
|
||||
|
||||
@@ -311,6 +331,9 @@ private:
|
||||
|
||||
State state;
|
||||
|
||||
u64 renderpass_serial = 0;
|
||||
u64 wfi_serial = 0;
|
||||
bool renderpass_writes = false;
|
||||
u32 num_renderpass_images = 0;
|
||||
std::array<VkImage, 9> renderpass_images{};
|
||||
std::array<VkImageSubresourceRange, 9> renderpass_image_ranges{};
|
||||
|
||||
Reference in New Issue
Block a user