mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-18 00:58:30 +09:00
[Merge] (MGPipe, P5): integrate package b1
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,20 @@ 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.
|
||||
//
|
||||
// TRANSPORT-GATED LIKE EVERY OTHER NEW SITE (D-J). Without the test this fires in
|
||||
// a build-split lane running MOBILEGL_TRANSPORT=monolith on Magma - whose
|
||||
// BeginXfbCaptureForDraw does mark the capture targets - where the fence at the
|
||||
// caller still runs, so the readback it emits is pure new work on the monolith
|
||||
// path and integration-gpu cannot see it.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) buffer->SyncGpuWrites();
|
||||
#endif
|
||||
const Range1D range = bindingPoint.GetRange();
|
||||
const Uint8* mapped = buffer->MappedData();
|
||||
if (mapped == nullptr) continue;
|
||||
@@ -1355,12 +1372,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@ */
|
||||
|
||||
@@ -702,6 +702,15 @@ namespace MobileGL::MG_Pipe {
|
||||
// one was emitted, so this cannot be false - but a zeroed record (null
|
||||
// handle, size 0) is not the answer if that pre-pass is ever relaxed.
|
||||
if (!MGPipeBuildSubDataRecord(handle, at, length, record, /*verbatimShadow=*/true)) return;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5 (b1): the live-host-writes bit rides the content record, because
|
||||
// "someone may be writing these bytes without telling you" is a fact about the
|
||||
// CONTENT and not about the storage. It is set from the object's PUBLISHED
|
||||
// value rather than from a live IsMapped() read so that the record and the
|
||||
// edge that announced it can never disagree. MGPipeBuildSubDataRecord does not
|
||||
// take the object, which is why it is set here and not in the builder.
|
||||
record.HasLiveHostWrites = buffer.HasLiveHostWritesForWire() ? 1 : 0;
|
||||
#endif
|
||||
MGPipeApplyResourceSubData(record, base + at);
|
||||
});
|
||||
if (!encodable) {
|
||||
@@ -723,6 +732,15 @@ namespace MobileGL::MG_Pipe {
|
||||
// store, or the pattern FillSubData expanded locally, and neither is this
|
||||
// client's untransformed shadow of the level.
|
||||
if (!MGPipeBuildSubDataRecord(handle, at, length, record, /*verbatimShadow=*/false)) return;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5 (b1): THE SECOND CONTENT EMITTER, and it has to speak for the same reason
|
||||
// the first does. ApplyBufferWrite ASSIGNS the bit - a content record emitted
|
||||
// while nothing maps the buffer is how the state goes back to false - so a
|
||||
// resident sub-data that stayed silent would write false over a live write
|
||||
// map. `glBufferSubData` against a persistently mapped arena is legal and is
|
||||
// the ordinary Flywheel/Create shape, so that is not a corner.
|
||||
record.HasLiveHostWrites = buffer.HasLiveHostWritesForWire() ? 1 : 0;
|
||||
#endif
|
||||
// The application's STAGING store, valid for the duration of the call only.
|
||||
MGPipeApplyBufferSubDataResident(record, base + (at - offset));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user