diff --git a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp index 9f09eafa..4d344c32 100644 --- a/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp +++ b/MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp @@ -3096,18 +3096,9 @@ 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 + // The split emitter waits for an owned pixel reply, then uploads its + // packed rows into the client PBO. Its shadow is already authoritative; + // marking another GPU write here would invent a readback that never ran. } /* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */ diff --git a/MobileGL/MG_Remote/Client/EmitTables.cpp b/MobileGL/MG_Remote/Client/EmitTables.cpp index 476d9689..4cd7ca40 100644 --- a/MobileGL/MG_Remote/Client/EmitTables.cpp +++ b/MobileGL/MG_Remote/Client/EmitTables.cpp @@ -1009,6 +1009,7 @@ namespace MobileGL::MG_Remote::Client { if (pbo) { // pixels is an offset, never a host pointer. Upload only the // requested rows so PACK padding and untouched bytes survive. + pbo->SyncGpuWrites(); const Uint64 alignment = std::max(pack.Alignment, 1); const Uint64 rowPixels = pack.RowLength > 0 ? pack.RowLength : width; const Uint64 stride = (rowPixels * bytesPerPixel + alignment - 1) / alignment * alignment; diff --git a/MobileGL/MG_Remote/Client/TextureReadbackEmit.inc b/MobileGL/MG_Remote/Client/TextureReadbackEmit.inc index 61d1f518..df954d52 100644 --- a/MobileGL/MG_Remote/Client/TextureReadbackEmit.inc +++ b/MobileGL/MG_Remote/Client/TextureReadbackEmit.inc @@ -94,6 +94,7 @@ offset += info.DstSize; } ApplyReadbackByteSwap(bytes.data(), tight, type, pack); + if (pbo) pbo->SyncGpuWrites(); for (Uint64 z = 0; z < depth; ++z) { for (Int y = 0; y < size.y(); ++y) { Uint8* source = bytes.data() + (z * size.y() + y) * layout.RowBytes;