Skip to content

Commit 731888c

Browse files
Thomas Smithskcq-be@skia-corp.google.com.iam.gserviceaccount.com
authored andcommitted
[ganesh] prevent stale readbacks
* Ganesh's SurfaceContext::readPixels did not consider whether the content it was attempting to readback was successfully rendered or not, leading to a scenario where stale texture data could potentially be readback. * Add some state tracking so that a failed flush is propagated out of the drawing manager and to the surface context Bug: b/521491024 Change-Id: Idb2b5eaccda7f4ec388e3dc415ee41d329d28533 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1295737 Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: Thomas Smith <thomsmit@google.com>
1 parent a1db562 commit 731888c

3 files changed

Lines changed: 85 additions & 4 deletions

File tree

src/gpu/ganesh/GrDrawingManager.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ bool GrDrawingManager::flush(SkSpan<GrSurfaceProxy*> proxies,
175175
}
176176

177177
bool cachePurgeNeeded = false;
178+
bool flushSuccessful = false;
178179

179180
if (preFlushSuccessful) {
180181
bool usingReorderedDAG = false;
@@ -205,8 +206,10 @@ bool GrDrawingManager::flush(SkSpan<GrSurfaceProxy*> proxies,
205206
resourceAllocator.assign();
206207
}
207208

208-
cachePurgeNeeded = !resourceAllocator.failedInstantiation() &&
209-
this->executeRenderTasks(&flushState);
209+
if (!resourceAllocator.failedInstantiation()) {
210+
cachePurgeNeeded = this->executeRenderTasks(&flushState);
211+
flushSuccessful = true;
212+
}
210213
}
211214
this->removeRenderTasks();
212215

@@ -226,7 +229,7 @@ bool GrDrawingManager::flush(SkSpan<GrSurfaceProxy*> proxies,
226229
}
227230
fFlushing = false;
228231

229-
return true;
232+
return flushSuccessful;
230233
}
231234

232235
bool GrDrawingManager::submitToGpu() {

src/gpu/ganesh/SurfaceContext.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,12 @@ bool SurfaceContext::readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoin
292292
pt.fY = flip ? srcSurface->height() - pt.fY - dst.height() : pt.fY;
293293
}
294294

295-
dContext->priv().flushSurface(srcProxy.get());
295+
bool hasPendingTasks =
296+
dContext->priv().drawingManager()->getLastRenderTask(srcProxy.get()) != nullptr;
297+
GrSemaphoresSubmitted flushResult = dContext->priv().flushSurface(srcProxy.get());
298+
if (flushResult == GrSemaphoresSubmitted::kNo && hasPendingTasks) {
299+
return false;
300+
}
296301
dContext->submit();
297302
if (!dContext->priv().getGpu()->readPixels(srcSurface,
298303
SkIRect::MakePtSize(pt, dst.dimensions()),

tests/ReadWritePixelsGpuTest.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@
4343
#include "src/gpu/ganesh/GrCaps.h"
4444
#include "src/gpu/ganesh/GrDataUtils.h"
4545
#include "src/gpu/ganesh/GrDirectContextPriv.h"
46+
#include "src/gpu/ganesh/GrDrawingManager.h"
4647
#include "src/gpu/ganesh/GrImageInfo.h"
48+
#include "src/gpu/ganesh/GrOnFlushResourceProvider.h"
4749
#include "src/gpu/ganesh/GrPixmap.h"
4850
#include "src/gpu/ganesh/GrSamplerState.h"
4951
#include "src/gpu/ganesh/GrSurfaceProxy.h"
@@ -243,6 +245,19 @@ using GpuWriteDstFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
243245
template <typename T>
244246
using GpuReadDstFn = SkAutoPixmapStorage(const T&);
245247

248+
class FailingFlushCallback : public GrOnFlushCallbackObject {
249+
public:
250+
bool preFlush(GrOnFlushResourceProvider*) override {
251+
++fCount;
252+
return false;
253+
}
254+
255+
int count() const { return fCount; }
256+
257+
private:
258+
int fCount = 0;
259+
};
260+
246261
} // anonymous namespace
247262

248263
SkPixmap make_pixmap_have_valid_alpha_type(SkPixmap pm) {
@@ -1513,3 +1528,61 @@ DEF_GANESH_TEST_FOR_GL_CONTEXT(GLReadPixelsUnbindPBO,
15131528

15141529
ComparePixels(syncResult.pixmap(), asyncResult, tol, error);
15151530
}
1531+
1532+
// readPixels() that uses an intermediate scratch surface should not return stale recycled scratch
1533+
// contents if the implicit flush of the queued draw into that surface drops its render tasks.
1534+
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReadPixelsIntermediateFailedFlush,
1535+
reporter,
1536+
ctxInfo,
1537+
CtsEnforcement::kNextRelease) {
1538+
auto dContext = ctxInfo.directContext();
1539+
if (dContext->supportsProtectedContent()) {
1540+
return;
1541+
}
1542+
1543+
static constexpr int kSize = 100;
1544+
static constexpr SkColor kStaleColor = 0xFF112233;
1545+
static constexpr SkColor kSrcColor = 0xFF008800;
1546+
1547+
auto srcII = SkImageInfo::Make({kSize, kSize}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
1548+
auto dstII = srcII.makeAlphaType(kUnpremul_SkAlphaType);
1549+
auto surf = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kYes, srcII);
1550+
if (!surf) {
1551+
return;
1552+
}
1553+
1554+
SkAutoPixmapStorage pixels;
1555+
pixels.alloc(dstII);
1556+
1557+
// Reading the unpremul destination from the premul source draws through an intermediate
1558+
// approx-fit surface. Do this once so a matching scratch surface lands in the resource cache
1559+
// with known stale contents.
1560+
surf->getCanvas()->clear(kStaleColor);
1561+
if (!surf->readPixels(pixels, 0, 0)) {
1562+
return;
1563+
}
1564+
1565+
surf->getCanvas()->clear(kSrcColor);
1566+
dContext->flushAndSubmit(GrSyncCpu::kYes);
1567+
1568+
// From here on the flush-time callback fails so any queued render tasks are discarded.
1569+
FailingFlushCallback failingCallback;
1570+
dContext->priv().addOnFlushCallbackObject(&failingCallback);
1571+
1572+
pixels.erase(SkColors::kTransparent);
1573+
bool ok = surf->readPixels(pixels, 0, 0);
1574+
1575+
dContext->priv().drawingManager()->testingOnly_removeOnFlushCallbackObject(&failingCallback);
1576+
1577+
if (ok) {
1578+
SkColor result = pixels.getColor(0, 0);
1579+
REPORTER_ASSERT(reporter,
1580+
result == kSrcColor,
1581+
"readPixels reported success but returned 0x%08x, expected 0x%08x",
1582+
result,
1583+
kSrcColor);
1584+
} else {
1585+
REPORTER_ASSERT(reporter, failingCallback.count() > 0);
1586+
}
1587+
}
1588+

0 commit comments

Comments
 (0)