Fix check in GrGLGpu for whether PBO 0 is bound

Found in OOP-R canvas in Chrome. Most likely async read followed by
sync read with an intervening resetContext().

Bug: chromium:1208212

Change-Id: Ibf85f070d0a4cd389f67e9b249655b0ef667c66e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/435277
Commit-Queue: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Auto-Submit: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
Brian Salomon 2021-07-30 17:17:39 -04:00 committed by SkCQ
parent 31df6806c0
commit 62d42db282
2 changed files with 59 additions and 2 deletions

View File

@ -952,9 +952,10 @@ bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface,
void GrGLGpu::unbindXferBuffer(GrGpuBufferType type) { void GrGLGpu::unbindXferBuffer(GrGpuBufferType type) {
SkASSERT(type == GrGpuBufferType::kXferCpuToGpu || type == GrGpuBufferType::kXferGpuToCpu); SkASSERT(type == GrGpuBufferType::kXferCpuToGpu || type == GrGpuBufferType::kXferGpuToCpu);
auto* xferBufferState = this->hwBufferState(type); auto* xferBufferState = this->hwBufferState(type);
if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) { if (!xferBufferState->fBufferZeroKnownBound) {
GL_CALL(BindBuffer(xferBufferState->fGLTarget, 0)); GL_CALL(BindBuffer(xferBufferState->fGLTarget, 0));
xferBufferState->invalidate(); xferBufferState->fBoundBufferUniqueID.makeInvalid();
xferBufferState->fBufferZeroKnownBound = true;
} }
} }

View File

@ -1239,3 +1239,59 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixelsMipped, reporter, ct
} }
} }
} }
// Tests a bug found in OOP-R canvas2d in Chrome. The GPU backend would incorrectly not bind
// buffer 0 to GL_PIXEL_PACK_BUFFER before a glReadPixels() that was supposed to read into
// client memory if a GrDirectContext::resetContext() occurred.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(GLReadPixelsUnbindPBO, reporter, ctxInfo) {
// Start with a async read so that we bind to GL_PIXEL_PACK_BUFFER.
auto info = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
SkAutoPixmapStorage pmap = make_ref_data(info, /*forceOpaque=*/false);
auto image = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
image = image->makeTextureImage(ctxInfo.directContext());
if (!image) {
ERRORF(reporter, "Couldn't make texture image.");
return;
}
AsyncContext asyncContext;
image->asyncRescaleAndReadPixels(info,
SkIRect::MakeSize(info.dimensions()),
SkImage::RescaleGamma::kSrc,
SkImage::RescaleMode::kNearest,
async_callback,
&asyncContext);
// This will force the async readback to finish.
ctxInfo.directContext()->flushAndSubmit(true);
if (!asyncContext.fCalled) {
ERRORF(reporter, "async_callback not called.");
}
if (!asyncContext.fResult) {
ERRORF(reporter, "async read failed.");
}
SkPixmap asyncResult(info, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0));
// Bug was that this would cause GrGLGpu to think no buffer was left bound to
// GL_PIXEL_PACK_BUFFER even though async transfer did leave one bound. So the sync read
// wouldn't bind buffer 0.
ctxInfo.directContext()->resetContext();
SkBitmap syncResult;
syncResult.allocPixels(info);
syncResult.eraseARGB(0xFF, 0xFF, 0xFF, 0xFF);
image->readPixels(ctxInfo.directContext(), syncResult.pixmap(), 0, 0);
float tol[4] = {}; // expect exactly same pixels, no conversions.
auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
const float diffs[4]) {
SkASSERT(x >= 0 && y >= 0);
ERRORF(reporter, "Expect sync and async read to be the same. "
"Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
});
ComparePixels(syncResult.pixmap(), asyncResult, tol, error);
}