mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[Feat] (GLImpl): mark the pack PBO after a glReadPixels and the capture targets at glEndTransformFeedback, in place of a stall and an unbounded fence wait
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
#include <MG_State/EGLState/Core.h>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#include <MG_Impl/Pipe/PipeFill.h>
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#include <MG_Remote/Client/GpuWritePending.h>
|
||||
#endif
|
||||
#include "../Getter/GL_Getter.h"
|
||||
|
||||
namespace MobileGL::MG_Impl::GLImpl {
|
||||
@@ -1315,6 +1318,14 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
static_cast<Uint>(bufferIndex));
|
||||
const auto& buffer = bindingPoint.GetBoundObject();
|
||||
if (buffer == nullptr) continue;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// This fixup READS the captured bytes back through the shadow, so it is the one
|
||||
// consumer that cannot simply inherit the deferral EndTransformFeedback's dropped
|
||||
// fence introduces. Under split it pays the reconciliation itself, which is the
|
||||
// same cost the fence used to charge every caller - here charged only to the
|
||||
// capture shapes that actually need reordering.
|
||||
buffer->SyncGpuWrites();
|
||||
#endif
|
||||
const Range1D range = bindingPoint.GetRange();
|
||||
const Uint8* mapped = buffer->MappedData();
|
||||
if (mapped == nullptr) continue;
|
||||
@@ -1355,12 +1366,28 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
MGP_FILL(EndTransformFeedback);
|
||||
endXfb();
|
||||
}
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5 (b1), the second producer the client-side GPU-write set ADDS, and it has to be
|
||||
// taken HERE - before GLContext::EndTransformFeedback clears the live bindings, since
|
||||
// a mark taken after it marks nothing.
|
||||
MG_Remote::Client::MarkEndTransformFeedbackCaptureTargets();
|
||||
#endif
|
||||
MG_State::pGLContext->EndTransformFeedback();
|
||||
// Captured results must be visible to MapBuffer/GetBufferSubData after
|
||||
// End; the capture targets are host-coherent GPU memory, so completing
|
||||
// the GPU work is all that is required.
|
||||
//
|
||||
// P5 (b1): UNDER SPLIT THE UNBOUNDED WAIT GOES AND THE MARK ABOVE REPLACES IT. The
|
||||
// wait exists for one reason - so that a later MapBuffer sees real captured results -
|
||||
// and that is precisely what m_gpuWritePending says; SyncGpuWrites then pays for it
|
||||
// once, on the first read that actually wants the bytes, instead of on every
|
||||
// glEndTransformFeedback. A ~0ull ClientWaitSync on the GL thread is also the one
|
||||
// shape a verb barrier cannot make cheap, because it is the driver's wait and not the
|
||||
// barrier's.
|
||||
auto& backendGL = MG_Backend::gBackendFunctionsTable.GL;
|
||||
if (backendGL.FenceSync && backendGL.ClientWaitSync) {
|
||||
const Bool waitForTheCapture =
|
||||
MG_Config::Transport == MG_Config::TransportMode::Monolith;
|
||||
if (waitForTheCapture && backendGL.FenceSync && backendGL.ClientWaitSync) {
|
||||
MGP_FILL(FenceSync);
|
||||
if (auto sync = backendGL.FenceSync()) {
|
||||
MGP_FILL(ClientWaitSync);
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Impl/Pipe/PipeFill.h>
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#include <MG_Remote/Client/GpuWritePending.h>
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a, ID-19(c). This file is the ONLY place every DSA framebuffer entry point lives, and the
|
||||
// emitter it reaches is this package's own header rather than a declaration in one of the
|
||||
@@ -3093,6 +3096,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void ReadPixels_Backend(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
|
||||
MGP_FILL(ReadPixels);
|
||||
MG_Backend::gBackendFunctionsTable.GL.ReadPixels(x, y, width, height, format, type, pixels);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5 (b1), one of the two producers the client-side GPU-write set ADDS. A read into a
|
||||
// bound GL_PIXEL_PACK_BUFFER is a GPU write to that buffer exactly as a shader's store
|
||||
// is, and marking it is what makes the next glMapBuffer / glGetBufferSubData of the
|
||||
// PBO reconcile. It is a no-op on the monolith path, where the backend still maps the
|
||||
// PBO and copies it into the shadow inside the call
|
||||
// (DirectGLES.cpp:10983-10993) - an unconditional stall on every glReadPixels whether
|
||||
// or not anything ever reads the shadow. Deferring that to the first read that wants
|
||||
// it is STRICTLY BETTER, which is the only reason a split build is allowed to differ
|
||||
// here at all.
|
||||
MG_Remote::Client::MarkReadPixelsPackBuffer();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
|
||||
Reference in New Issue
Block a user