SkSurface copy-on-write can yield stale GPU render targets.

Prepare_rt_for_external_access() grabs the render target and then fires
access notifications.

But the notification handlers may trigger copy-on-write, causing the
returned render target to be stale (pointing at the detached snapshot).

We should grab the render target after firing notifications.

R=reed@google.com,bsalomon@google.com

Review URL: https://codereview.chromium.org/1276713002
This commit is contained in:
fmalita 2015-08-06 07:04:51 -07:00 committed by Commit bot
parent ebe06c0560
commit e2639089bd
2 changed files with 38 additions and 1 deletions

View File

@ -28,7 +28,6 @@ SkSurface_Gpu::~SkSurface_Gpu() {
static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
SkSurface::BackendHandleAccess access) {
GrRenderTarget* rt = surface->getDevice()->accessRenderTarget();
switch (access) {
case SkSurface::kFlushRead_BackendHandleAccess:
break;
@ -40,6 +39,9 @@ static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
surface->getDevice()->accessBitmap(false).notifyPixelsChanged();
break;
}
// Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
GrRenderTarget* rt = surface->getDevice()->accessRenderTarget();
rt->prepareForExternalIO();
return rt;
}

View File

@ -622,6 +622,19 @@ static void test_snap_alphatype(skiatest::Reporter* reporter, GrContextFactory*
}
}
static void test_backend_cow(skiatest::Reporter* reporter, SkSurface* surface,
SkSurface::BackendHandleAccess mode,
GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
GrBackendObject obj1 = func(surface, mode);
SkAutoTUnref<SkImage> snap1(surface->newImageSnapshot());
GrBackendObject obj2 = func(surface, mode);
SkAutoTUnref<SkImage> snap2(surface->newImageSnapshot());
// If the access mode triggers CoW, then the backend objects should reflect it.
REPORTER_ASSERT(reporter, (obj1 == obj2) == (snap1 == snap2));
}
static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
GrContext* context) {
// Verify that the right canvas commands trigger a copy on write
@ -700,6 +713,28 @@ static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType sur
testPaint))
EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
testPaint))
const SkSurface::BackendHandleAccess accessModes[] = {
SkSurface::kFlushRead_BackendHandleAccess,
SkSurface::kFlushWrite_BackendHandleAccess,
SkSurface::kDiscardWrite_BackendHandleAccess,
};
for (auto access : accessModes) {
test_backend_cow(reporter, surface, access,
[](SkSurface* s, SkSurface::BackendHandleAccess a) -> GrBackendObject {
return s->getTextureHandle(a);
});
test_backend_cow(reporter, surface, access,
[](SkSurface* s, SkSurface::BackendHandleAccess a) -> GrBackendObject {
GrBackendObject result;
if (!s->getRenderTargetHandle(&result, a)) {
return 0;
}
return result;
});
}
}
static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,