Revert "Write pixels goes through GrRenderTask system."

This reverts commit 27efe6cb1e.

Reason for revert: wasm compile

Original change's description:
> Write pixels goes through GrRenderTask system.
>
> The specific motivation is to remove some uses of GrResourceProvider
> making textures with data in lazy callbacks. But it's a general
> improvement that could allow use cases like writePixels in DDL
> recordings.
>
> Bug: skia:11204
>
> Change-Id: Ic55c3f75976a1d3a7d93981e21be75a3053ef069
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/356845
> Reviewed-by: Adlai Holler <adlai@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=bsalomon@google.com,adlai@google.com

Change-Id: I116caf1e4dd9015270b9d4f810bd26e0e30a6497
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:11204
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/359559
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2021-01-26 18:12:25 +00:00 committed by Skia Commit-Bot
parent 489e5b9cb2
commit 1eea1ea8c1
16 changed files with 67 additions and 295 deletions

View File

@ -276,8 +276,6 @@ skia_gpu_sources = [
"$_src/gpu/GrWaitRenderTask.h",
"$_src/gpu/GrWindowRectangles.h",
"$_src/gpu/GrWindowRectsState.h",
"$_src/gpu/GrWritePixelsRenderTask.cpp",
"$_src/gpu/GrWritePixelsRenderTask.h",
"$_src/gpu/GrXferProcessor.cpp",
"$_src/gpu/GrXferProcessor.h",
"$_src/gpu/GrYUVABackendTextures.cpp",

View File

@ -185,7 +185,8 @@ bool GrDirectContext::init() {
SkASSERT(this->threadSafeCache());
fStrikeCache = std::make_unique<GrStrikeCache>();
fResourceCache = std::make_unique<GrResourceCache>(this->singleOwner(), this->contextID());
fResourceCache = std::make_unique<GrResourceCache>(this->caps(), this->singleOwner(),
this->contextID());
fResourceCache->setProxyProvider(this->proxyProvider());
fResourceCache->setThreadSafeCache(this->threadSafeCache());
fResourceProvider = std::make_unique<GrResourceProvider>(fGpu.get(), fResourceCache.get(),

View File

@ -42,7 +42,6 @@
#include "src/gpu/GrTracing.h"
#include "src/gpu/GrTransferFromRenderTask.h"
#include "src/gpu/GrWaitRenderTask.h"
#include "src/gpu/GrWritePixelsRenderTask.h"
#include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h"
#include "src/gpu/text/GrSDFTOptions.h"
#include "src/image/SkSurface_Gpu.h"
@ -860,49 +859,6 @@ bool GrDrawingManager::newCopyRenderTask(sk_sp<GrSurfaceProxy> src,
return true;
}
bool GrDrawingManager::newWritePixelsTask(sk_sp<GrSurfaceProxy> dst,
SkIRect rect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel levels[],
int levelCount,
sk_sp<SkData> owner) {
SkDEBUGCODE(this->validate());
SkASSERT(fContext);
this->closeActiveOpsTask();
const GrCaps& caps = *fContext->priv().caps();
// On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
// complete flush here.
if (!caps.preferVRAMUseOverFlushes()) {
this->flushSurfaces(SkSpan<GrSurfaceProxy*>{},
SkSurface::BackendSurfaceAccess::kNoAccess,
GrFlushInfo{},
nullptr);
}
GrRenderTask* task = this->appendTask(GrWritePixelsTask::Make(this,
std::move(dst),
rect,
srcColorType,
dstColorType,
levels,
levelCount,
std::move(owner)));
if (!task) {
return false;
}
task->makeClosed(caps);
// We have closed the previous active oplist but since a new oplist isn't being added there
// shouldn't be an active one.
SkASSERT(!fActiveOpsTask);
SkDEBUGCODE(this->validate());
return true;
}
/*
* This method finds a path renderer that can draw the specified path on
* the provided target.

View File

@ -83,18 +83,6 @@ public:
SkIPoint dstPoint,
GrSurfaceOrigin);
// Adds a task that writes the data from the passed GrMipLevels to dst. The lifetime of the
// pixel data in the levels should be tied to the passed SkData. srcColorType is the color
// type of the GrMipLevels. dstColorType is the color type being used with dst and must
// be compatible with dst's format according to GrCaps::areColorTypeAndFormatCompatible().
bool newWritePixelsTask(sk_sp<GrSurfaceProxy> dst,
SkIRect rect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel[],
int levelCount,
sk_sp<SkData> storage);
GrRecordingContext* getContext() { return fContext; }
GrPathRenderer* getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,

View File

@ -8,7 +8,6 @@
#ifndef GrPixmap_DEFINED
#define GrPixmap_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkPixmap.h"
#include "src/gpu/GrImageInfo.h"
@ -29,18 +28,6 @@ public:
/* implicit */ GrPixmap(const SkPixmap& pixmap)
: GrPixmap(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes()) {}
/**
* Returns a GrPixmap that owns its backing store. Copies of the pixmap will share ownership.
*/
static GrPixmap Allocate(const GrImageInfo& info) {
size_t rb = info.minRowBytes();
size_t size = info.height()*rb;
if (!size) {
return {};
}
return GrPixmap(info, SkData::MakeUninitialized(size), rb);
}
const GrImageInfo& info() const { return fInfo; }
const GrColorInfo& colorInfo() const { return fInfo.colorInfo(); }
@ -48,8 +35,6 @@ public:
size_t rowBytes() const { return fRowBytes; }
bool hasPixels() const { return SkToBool(fAddr); }
bool ownsPixels() const { return SkToBool(fPixelStorage); }
sk_sp<SkData> pixelStorage() const { return fPixelStorage; }
int width() const { return fInfo.width(); }
int height() const { return fInfo.height(); }
@ -77,16 +62,21 @@ public:
return {this->info().makeDimensions(rect.size()), addr, fRowBytes};
}
private:
GrPixmap(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
: GrPixmap(std::move(info), storage->writable_data(), rowBytes) {
fPixelStorage = std::move(storage);
/** Returns a GrPixmap and a unique_ptr that owns the storage backing the pixmap. */
static std::tuple<GrPixmap, std::unique_ptr<char[]>> Allocate(const GrImageInfo& info) {
size_t rb = info.minRowBytes();
size_t size = info.height()*rb;
if (!size) {
return {};
}
std::unique_ptr<char[]> storage(new char[size]);
return {GrPixmap(info, storage.get(), rb), std::move(storage)};
}
private:
void* fAddr = nullptr;
size_t fRowBytes = 0;
GrImageInfo fInfo;
sk_sp<SkData> fPixelStorage;
};
#endif

View File

@ -108,11 +108,13 @@ inline bool GrResourceCache::TextureAwaitingUnref::finished() { return !fNumUnre
//////////////////////////////////////////////////////////////////////////////
GrResourceCache::GrResourceCache(GrSingleOwner* singleOwner, uint32_t contextUniqueID)
GrResourceCache::GrResourceCache(const GrCaps* caps, GrSingleOwner* singleOwner,
uint32_t contextUniqueID)
: fInvalidUniqueKeyInbox(contextUniqueID)
, fFreedTextureInbox(contextUniqueID)
, fContextUniqueID(contextUniqueID)
, fSingleOwner(singleOwner) {
, fSingleOwner(singleOwner)
, fPreferVRAMUseOverFlushes(caps->preferVRAMUseOverFlushes()) {
SkASSERT(contextUniqueID != SK_InvalidUniqueID);
}

View File

@ -58,7 +58,7 @@ static inline bool SkShouldPostMessageToBus(
*/
class GrResourceCache {
public:
GrResourceCache(GrSingleOwner* owner, uint32_t contextUniqueID);
GrResourceCache(const GrCaps*, GrSingleOwner* owner, uint32_t contextUniqueID);
~GrResourceCache();
// Default maximum number of bytes of gpu memory of budgeted resources in the cache.
@ -371,6 +371,8 @@ private:
// This resource is allowed to be in the nonpurgeable array for the sake of validate() because
// we're in the midst of converting it to purgeable status.
SkDEBUGCODE(GrGpuResource* fNewlyPurgeableResourceForValidation = nullptr;)
bool fPreferVRAMUseOverFlushes = false;
};
class GrResourceCache::ResourceAccess {

View File

@ -494,12 +494,15 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIP
bool convert = premul || unpremul || needColorConversion || makeTight ||
(src.colorType() != allowedColorType) || flip;
if (convert || !src.ownsPixels()) {
std::unique_ptr<char[]> tmpPixels;
if (convert) {
GrImageInfo tmpInfo(allowedColorType,
this->colorInfo().alphaType(),
this->colorInfo().refColorSpace(),
src.dimensions());
GrPixmap tmp = GrPixmap::Allocate(tmpInfo);
auto tmpRB = tmpInfo.minRowBytes();
tmpPixels.reset(new char[tmpRB * tmpInfo.height()]);
GrPixmap tmp(tmpInfo, tmpPixels.get(), tmpRB);
SkAssertResult(GrConvertPixels(tmp, src, flip));
@ -507,17 +510,16 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIP
pt.fY = flip ? dstSurface->height() - pt.fY - tmpInfo.height() : pt.fY;
}
GrMipLevel level;
level.fPixels = src.addr();
level.fRowBytes = src.rowBytes();
return dContext->priv().drawingManager()->newWritePixelsTask(
this->asSurfaceProxyRef(),
SkIRect::MakePtSize(pt, src.dimensions()),
src.colorType(),
dstColorType,
&level,
1,
src.pixelStorage());
// On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
// complete flush here. On platforms that prefer VRAM use over flushes we're better off
// giving the drawing manager the chance of skipping the flush (i.e., by passing in the
// destination proxy)
// TODO: should this policy decision just be moved into the drawing manager?
dContext->priv().flushSurface(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
return dContext->priv().getGpu()->writePixels(dstSurface, pt.fX, pt.fY, src.width(),
src.height(), this->colorInfo().colorType(),
src.colorType(), src.addr(), src.rowBytes());
}
void GrSurfaceContext::asyncRescaleAndReadPixels(GrDirectContext* dContext,
@ -632,13 +634,18 @@ public:
AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
~AsyncReadResult() override {
for (int i = 0; i < fPlanes.count(); ++i) {
fPlanes[i].releaseMappedBuffer(fInboxID);
if (!fPlanes[i].fMappedBuffer) {
delete[] static_cast<const char*>(fPlanes[i].fData);
} else {
GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
{std::move(fPlanes[i].fMappedBuffer), fInboxID});
}
}
}
int count() const override { return fPlanes.count(); }
const void* data(int i) const override { return fPlanes[i].data(); }
size_t rowBytes(int i) const override { return fPlanes[i].rowBytes(); }
const void* data(int i) const override { return fPlanes[i].fData; }
size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
bool addTransferResult(const PixelTransferResult& result,
SkISize dimensions,
@ -650,10 +657,9 @@ public:
return false;
}
if (result.fPixelConverter) {
size_t size = rowBytes*dimensions.height();
sk_sp<SkData> data = SkData::MakeUninitialized(size);
result.fPixelConverter(data->writable_data(), mappedData);
this->addCpuPlane(std::move(data), rowBytes);
std::unique_ptr<char[]> convertedData(new char[rowBytes * dimensions.height()]);
result.fPixelConverter(convertedData.get(), mappedData);
this->addCpuPlane(std::move(convertedData), rowBytes);
result.fTransferBuffer->unmap();
} else {
manager->insert(result.fTransferBuffer);
@ -662,10 +668,10 @@ public:
return true;
}
void addCpuPlane(sk_sp<SkData> data, size_t rowBytes) {
void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
SkASSERT(data);
SkASSERT(rowBytes > 0);
fPlanes.emplace_back(std::move(data), rowBytes);
fPlanes.emplace_back(data.release(), rowBytes, nullptr);
}
private:
@ -674,41 +680,16 @@ private:
SkASSERT(rowBytes > 0);
SkASSERT(mappedBuffer);
SkASSERT(mappedBuffer->isMapped());
fPlanes.emplace_back(std::move(mappedBuffer), rowBytes);
fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
}
class Plane {
public:
Plane(sk_sp<GrGpuBuffer> buffer, size_t rowBytes)
: fMappedBuffer(std::move(buffer)), fRowBytes(rowBytes) {}
Plane(sk_sp<SkData> data, size_t rowBytes) : fData(std::move(data)), fRowBytes(rowBytes) {}
~Plane() { SkASSERT(!fMappedBuffer); }
void releaseMappedBuffer(uint32_t inboxID) {
if (fMappedBuffer) {
GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
{std::move(fMappedBuffer), inboxID});
}
}
const void* data() const {
if (fMappedBuffer) {
SkASSERT(!fData);
SkASSERT(fMappedBuffer->isMapped());
return fMappedBuffer->map();
}
SkASSERT(fData);
return fData->data();
}
size_t rowBytes() const { return fRowBytes; }
private:
sk_sp<SkData> fData;
sk_sp<GrGpuBuffer> fMappedBuffer;
struct Plane {
Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
: fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
const void* fData;
size_t fRowBytes;
// If this is null then fData is heap alloc and must be delete[]ed as const char[].
sk_sp<GrGpuBuffer> fMappedBuffer;
};
SkSTArray<3, Plane> fPlanes;
uint32_t fInboxID;
@ -735,8 +716,9 @@ void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
auto ii = SkImageInfo::Make(rect.size(), colorType, this->colorInfo().alphaType(),
this->colorInfo().refColorSpace());
auto result = std::make_unique<AsyncReadResult>(0);
GrPixmap pm = GrPixmap::Allocate(ii);
result->addCpuPlane(pm.pixelStorage(), pm.rowBytes());
std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
SkPixmap pm(ii, data.get(), ii.minRowBytes());
result->addCpuPlane(std::move(data), pm.rowBytes());
SkIPoint pt{rect.fLeft, rect.fTop};
if (!this->readPixels(dContext, pm, pt)) {
@ -975,9 +957,9 @@ void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext
}
if (doSynchronousRead) {
GrPixmap yPmp = GrPixmap::Allocate(yInfo);
GrPixmap uPmp = GrPixmap::Allocate(uvInfo);
GrPixmap vPmp = GrPixmap::Allocate(uvInfo);
auto [yPmp, yStorage] = GrPixmap::Allocate(yInfo);
auto [uPmp, uStorage] = GrPixmap::Allocate(uvInfo);
auto [vPmp, vStorage] = GrPixmap::Allocate(uvInfo);
if (!yFC->readPixels(dContext, yPmp, {0, 0}) ||
!uFC->readPixels(dContext, uPmp, {0, 0}) ||
!vFC->readPixels(dContext, vPmp, {0, 0})) {
@ -985,9 +967,9 @@ void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext
return;
}
auto result = std::make_unique<AsyncReadResult>(dContext->priv().contextID());
result->addCpuPlane(yPmp.pixelStorage(), yPmp.rowBytes());
result->addCpuPlane(uPmp.pixelStorage(), uPmp.rowBytes());
result->addCpuPlane(vPmp.pixelStorage(), vPmp.rowBytes());
result->addCpuPlane(std::move(yStorage), yPmp.rowBytes());
result->addCpuPlane(std::move(uStorage), uPmp.rowBytes());
result->addCpuPlane(std::move(vStorage), vPmp.rowBytes());
callback(callbackContext, std::move(result));
return;
}

View File

@ -50,9 +50,6 @@ GrTexture::GrTexture(GrGpu* gpu,
} else {
fMaxMipmapLevel = SkMipmap::ComputeLevelCount(this->width(), this->height());
}
if (textureType == GrTextureType::kExternal) {
this->setReadOnly();
}
}
bool GrTexture::StealBackendTexture(sk_sp<GrTexture> texture,

View File

@ -34,9 +34,6 @@ GrTextureProxy::GrTextureProxy(const GrBackendFormat& format,
, fProxyProvider(nullptr)
, fDeferredUploader(nullptr) {
SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
if (this->textureType() == GrTextureType::kExternal) {
fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
}
}
// Lazy-callback version
@ -60,9 +57,6 @@ GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback,
, fProxyProvider(nullptr)
, fDeferredUploader(nullptr) {
SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
if (this->textureType() == GrTextureType::kExternal) {
fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
}
}
// Wrapped version
@ -80,9 +74,6 @@ GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf,
fProxyProvider = fTarget->asTexture()->getContext()->priv().proxyProvider();
fProxyProvider->adoptUniqueKeyFromSurface(this, fTarget.get());
}
if (this->textureType() == GrTextureType::kExternal) {
fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
}
}
GrTextureProxy::~GrTextureProxy() {

View File

@ -1,78 +0,0 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/GrWritePixelsRenderTask.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrResourceAllocator.h"
//
sk_sp<GrRenderTask> GrWritePixelsTask::Make(GrDrawingManager* dm,
sk_sp<GrSurfaceProxy> dst,
SkIRect rect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel texels[],
int levelCount,
sk_sp<SkData> pixelStorage) {
return sk_sp<GrRenderTask>(new GrWritePixelsTask(dm,
std::move(dst),
rect,
srcColorType,
dstColorType,
texels,
levelCount,
std::move(pixelStorage)));
}
GrWritePixelsTask::GrWritePixelsTask(GrDrawingManager* dm,
sk_sp<GrSurfaceProxy> dst,
SkIRect rect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel texels[],
int levelCount,
sk_sp<SkData> pixelStorage)
: fRect(rect)
, fSrcColorType(srcColorType)
, fDstColorType(dstColorType)
, fStorage(std::move(pixelStorage)) {
SkASSERT(fStorage);
this->addTarget(dm, std::move(dst));
fLevels.reset(levelCount);
std::copy_n(texels, levelCount, fLevels.get());
}
void GrWritePixelsTask::gatherProxyIntervals(GrResourceAllocator* alloc) const {
alloc->addInterval(this->target(0), alloc->curOp(), alloc->curOp(),
GrResourceAllocator::ActualUse::kYes);
alloc->incOps();
}
GrRenderTask::ExpectedOutcome GrWritePixelsTask::onMakeClosed(const GrCaps&,
SkIRect* targetUpdateBounds) {
*targetUpdateBounds = fRect;
return ExpectedOutcome::kTargetDirty;
}
bool GrWritePixelsTask::onExecute(GrOpFlushState* flushState) {
GrSurfaceProxy* dstProxy = this->target(0);
if (!dstProxy->isInstantiated()) {
return false;
}
GrSurface* dstSurface = dstProxy->peekSurface();
return flushState->gpu()->writePixels(dstSurface,
fRect.fLeft,
fRect.fTop,
fRect.width(),
fRect.height(),
fDstColorType,
fSrcColorType,
fLevels.get(),
fLevels.count());
}

View File

@ -1,56 +0,0 @@
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrWritePixelsTask_DEFINED
#define GrWritePixelsTask_DEFINED
#include "src/gpu/GrRenderTask.h"
class GrWritePixelsTask final : public GrRenderTask {
public:
static sk_sp<GrRenderTask> Make(GrDrawingManager*,
sk_sp<GrSurfaceProxy>,
SkIRect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel[],
int levelCount,
sk_sp<SkData> pixelStorage);
private:
GrWritePixelsTask(GrDrawingManager*,
sk_sp<GrSurfaceProxy> dst,
SkIRect,
GrColorType srcColorType,
GrColorType dstColorType,
const GrMipLevel[],
int levelCount,
sk_sp<SkData> pixelStorage);
bool onIsUsed(GrSurfaceProxy* proxy) const override { return false; }
// If instantiation failed, at flush time we simply will skip doing the write.
void handleInternalAllocationFailure() override {}
void gatherProxyIntervals(GrResourceAllocator*) const override;
ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) override;
bool onExecute(GrOpFlushState*) override;
#if GR_TEST_UTILS
const char* name() const final { return "WritePixels"; }
#endif
#ifdef SK_DEBUG
void visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const override {}
#endif
SkIRect fRect;
GrColorType fSrcColorType;
GrColorType fDstColorType;
SkAutoSTArray<16, GrMipLevel> fLevels;
sk_sp<SkData> fStorage;
};
#endif

View File

@ -195,9 +195,8 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(EGLImageTest, reporter, ctxInfo) {
}
}
//TestReadPixels(reporter, context0, surfaceContext.get(), pixels.get(), "EGLImageTest-read");
TestReadPixels(reporter, context0, surfaceContext.get(), pixels.get(), "EGLImageTest-read");
SkDebugf("type: %d\n", surfaceContext->asTextureProxy()->textureType());
// We should not be able to write to an EXTERNAL texture
TestWritePixels(reporter, context0, surfaceContext.get(), false, "EGLImageTest-write");

View File

@ -598,7 +598,7 @@ static void run_test(GrDirectContext* dContext, const char* testName,
return;
}
GrPixmap resultPM = GrPixmap::Allocate(gold.info());
auto [resultPM, resultStorage] = GrPixmap::Allocate(gold.info());
rtc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
rtc->addDrawOp(GrMeshTestOp::Make(dContext, prepareFn, executeFn));

View File

@ -58,7 +58,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RenderTargetContextTest, reporter, ctxInfo) {
check_instantiation_status(reporter, rtCtx.get(), false);
SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(kSize, kSize);
GrPixmap dstPM = GrPixmap::Allocate(dstInfo);
auto [dstPM, dstStorage] = GrPixmap::Allocate(dstInfo);
bool result = rtCtx->readPixels(dContext, dstPM, {0, 0});
REPORTER_ASSERT(reporter, result);

View File

@ -127,7 +127,7 @@ void read_and_check_pixels(skiatest::Reporter* reporter,
const SkImageInfo& dstInfo, CheckFn checker, float error,
const char* subtestName) {
auto [w, h] = dstInfo.dimensions();
GrPixmap readPM = GrPixmap::Allocate(dstInfo);
auto [readPM, readStorage] = GrPixmap::Allocate(dstInfo);
memset(readPM.addr(), 0, sizeof(uint32_t)*w*h);
if (!sContext->readPixels(dContext, readPM, {0, 0})) {