GrSurfaceContext::read/writePixels takes GrPixmap

Change readPixels contract to allow unknown->unknown AT reads, but
fail if one side is unknown and the other isn't (and update GPU read
pixels test accordingly).

Also, ProxyUtils::MakeTextureProxyViewFromData takes GrPixmap.

Bug: skia:8862
Change-Id: I771c154833408e666f860413c1a711714696326d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/347196
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Brian Salomon 2020-12-23 20:36:44 -05:00 committed by Skia Commit-Bot
parent 12739dffec
commit dd4087d1e8
31 changed files with 291 additions and 273 deletions

View File

@ -28,6 +28,7 @@
#include "include/gpu/GrTypes.h"
#include "include/private/SkTArray.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrPixmap.h"
#include "src/image/SkImage_Base.h"
#include "src/image/SkImage_Gpu.h"
#include "tools/ToolUtils.h"
@ -133,7 +134,7 @@ static sk_sp<SkImage> make_reference_image(GrDirectContext* context,
auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
auto view = sk_gpu_test::MakeTextureProxyViewFromData(context, GrRenderable::kNo, origin,
bm.info(), bm.getPixels(), bm.rowBytes());
bm.pixmap());
if (!view) {
return nullptr;
}

View File

@ -515,7 +515,11 @@ bool GrConvertPixels(const GrImageInfo& dstInfo, void* dst, size_t dstRB,
// We don't expect to have to convert from this format.
return false;
}
if (!srcInfo.isValid() || !dstInfo.isValid()) {
if (srcInfo.dimensions().isEmpty() || dstInfo.dimensions().isEmpty()) {
return false;
}
if (srcInfo.colorType() == GrColorType::kUnknown ||
dstInfo.colorType() == GrColorType::kUnknown) {
return false;
}
if (!src || !dst) {

View File

@ -44,6 +44,10 @@ public:
return {this->colorType(), at, this->refColorSpace(), this->width(), this->height()};
}
GrImageInfo makeDimensions(SkISize dimensions) const {
return {this->colorType(), this->alphaType(), this->refColorSpace(), dimensions};
}
GrImageInfo makeWH(int width, int height) const {
return {this->colorType(), this->alphaType(), this->refColorSpace(), width, height};
}
@ -68,28 +72,6 @@ public:
size_t minRowBytes() const { return this->bpp() * this->width(); }
/**
* Place this image rect in a surface of dimensions surfaceWidth x surfaceHeight size offset at
* surfacePt and then clip the pixel rectangle to the bounds of the surface. If the pixel rect
* does not intersect the rectangle or is empty then return false. If clipped, the input
* surfacePt, the width/height of this GrImageInfo, and the data pointer will be modified to
* reflect the clipped rectangle.
*/
template <typename T>
bool clip(int surfaceWidth, int surfaceHeight, SkIPoint* surfacePt, T** data, size_t rowBytes) {
auto bounds = SkIRect::MakeWH(surfaceWidth, surfaceHeight);
auto rect = SkIRect::MakeXYWH(surfacePt->fX, surfacePt->fY, this->width(), this->height());
if (!rect.intersect(bounds)) {
return false;
}
*data = SkTAddOffset<T>(*data, (rect.fTop - surfacePt->fY) * rowBytes +
(rect.fLeft - surfacePt->fX) * this->bpp());
surfacePt->fX = rect.fLeft;
surfacePt->fY = rect.fTop;
fDimensions = rect.size();
return true;
}
bool isValid() const { return fColorInfo.isValid() && this->width() > 0 && this->height() > 0; }
private:

View File

@ -29,13 +29,49 @@ public:
: GrPixmap(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes()) {}
const GrImageInfo& info() const { return fInfo; }
const GrColorInfo& colorInfo() const { return fInfo.colorInfo(); }
void* addr() const { return fAddr; }
size_t rowBytes() const { return fRowBytes; }
bool hasPixels() const { return SkToBool(fAddr); }
int width() const { return fInfo.width(); }
int height() const { return fInfo.height(); }
SkISize dimensions() const { return fInfo.dimensions(); }
GrColorType colorType() const { return fInfo.colorType(); }
SkAlphaType alphaType() const { return fInfo.alphaType(); }
/**
* Map this pixmap to a rect in a surface of indicated dimensions at offset surfacePt. Clip the
* logical rectangle to the bounds of the surface. If the rect does not intersect the surface
* bounds or is empty then return a default GrPixmap. Otherwise, surfacePt is updated to refer
* to the upper left of the clipped rectangle. The returned pixmap will refer to the portion
* of the original pixmap inside the surface bounds.
*/
GrPixmap clip(SkISize surfaceDims, SkIPoint* surfacePt) {
auto bounds = SkIRect::MakeSize(surfaceDims);
auto rect = SkIRect::MakePtSize(*surfacePt, this->dimensions());
if (!rect.intersect(bounds)) {
return {};
}
void* addr = static_cast<char*>(fAddr) + (rect.fTop - surfacePt->fY)*fRowBytes +
(rect.fLeft - surfacePt->fX)*fInfo.bpp();
surfacePt->fX = rect.fLeft;
surfacePt->fY = rect.fTop;
return {this->info().makeDimensions(rect.size()), addr, fRowBytes};
}
/** 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;

View File

@ -162,8 +162,12 @@ const GrDrawingManager* GrSurfaceContext::drawingManager() const {
GrSingleOwner* GrSurfaceContext::singleOwner() const { return fContext->priv().singleOwner(); }
#endif
bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo& origDstInfo,
void* dst, size_t rowBytes, SkIPoint pt) {
static bool alpha_types_compatible(SkAlphaType srcAlphaType, SkAlphaType dstAlphaType) {
// If both alpha types are kUnknown things make sense. If not, it's too underspecified.
return (srcAlphaType == kUnknown_SkAlphaType) == (dstAlphaType == kUnknown_SkAlphaType);
}
bool GrSurfaceContext::readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoint pt) {
ASSERT_SINGLE_OWNER
RETURN_FALSE_IF_ABANDONED
SkDEBUGCODE(this->validate();)
@ -171,21 +175,15 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
if (!fContext->priv().matches(dContext)) {
return false;
}
if (!dst) {
dst = dst.clip(this->dimensions(), &pt);
if (!dst.hasPixels()) {
return false;
}
size_t tightRowBytes = origDstInfo.minRowBytes();
if (!rowBytes) {
rowBytes = tightRowBytes;
} else if (rowBytes < tightRowBytes) {
return false;
}
if (!origDstInfo.isValid()) {
if (!alpha_types_compatible(this->colorInfo().alphaType(), dst.alphaType())) {
return false;
}
// We allow unknown alpha types but only if both src and dst are unknown. Otherwise, it's too
// weird to reason about what should be expected.
GrSurfaceProxy* srcProxy = this->asSurfaceProxy();
@ -200,14 +198,8 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
GrSurface* srcSurface = srcProxy->peekSurface();
auto dstInfo = origDstInfo;
if (!dstInfo.clip(this->width(), this->height(), &pt, &dst, rowBytes)) {
return false;
}
// Our tight row bytes may have been changed by clipping.
tightRowBytes = dstInfo.minRowBytes();
SkColorSpaceXformSteps::Flags flags = SkColorSpaceXformSteps{this->colorInfo(), dstInfo}.flags;
SkColorSpaceXformSteps::Flags flags =
SkColorSpaceXformSteps{this->colorInfo(), dst.info()}.flags;
bool unpremul = flags.unpremul,
needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
premul = flags.premul;
@ -223,8 +215,8 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
GrRenderable::kYes);
GrColorType srcColorType = this->colorInfo().colorType();
bool canvas2DFastPath = unpremul && !needColorConversion &&
(GrColorType::kRGBA_8888 == dstInfo.colorType() ||
GrColorType::kBGRA_8888 == dstInfo.colorType()) &&
(GrColorType::kRGBA_8888 == dst.colorType() ||
GrColorType::kBGRA_8888 == dst.colorType()) &&
SkToBool(srcProxy->asTextureProxy()) &&
(srcColorType == GrColorType::kRGBA_8888 ||
srcColorType == GrColorType::kBGRA_8888) &&
@ -242,12 +234,12 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
? GrColorType::kRGBA_8888
: this->colorInfo().colorType();
SkAlphaType alphaType = canvas2DFastPath ? dstInfo.alphaType()
SkAlphaType alphaType = canvas2DFastPath ? dst.alphaType()
: this->colorInfo().alphaType();
GrImageInfo tempInfo(colorType,
alphaType,
this->colorInfo().refColorSpace(),
dstInfo.dimensions());
dst.dimensions());
auto sfc = GrSurfaceFillContext::Make(dContext, tempInfo, SkBackingFit::kApprox);
if (!sfc) {
return false;
@ -257,9 +249,11 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
if (canvas2DFastPath) {
fp = dContext->priv().createPMToUPMEffect(GrTextureEffect::Make(
this->readSurfaceView(), this->colorInfo().alphaType()));
if (dstInfo.colorType() == GrColorType::kBGRA_8888) {
if (dst.colorType() == GrColorType::kBGRA_8888) {
fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
dstInfo = dstInfo.makeColorType(GrColorType::kRGBA_8888);
dst = GrPixmap(dst.info().makeColorType(GrColorType::kRGBA_8888),
dst.addr(),
dst.rowBytes());
}
} else {
fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
@ -267,8 +261,8 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
if (!fp) {
return false;
}
sfc->fillRectToRectWithFP(SkIRect::MakePtSize(pt, dstInfo.dimensions()),
SkIRect::MakeSize(dstInfo.dimensions()),
sfc->fillRectToRectWithFP(SkIRect::MakePtSize(pt, dst.dimensions()),
SkIRect::MakeSize(dst.dimensions()),
std::move(fp));
pt = {0, 0};
tempCtx = std::move(sfc);
@ -283,7 +277,7 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, kFit,
kBudgeted);
} else {
auto srcRect = SkIRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height());
auto srcRect = SkIRect::MakePtSize(pt, dst.dimensions());
copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, srcRect,
kFit, kBudgeted, restrictions.fRectsMustMatch);
pt = {0, 0};
@ -295,52 +289,55 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
tempCtx = GrSurfaceContext::Make(dContext, std::move(view), this->colorInfo());
SkASSERT(tempCtx);
}
return tempCtx->readPixels(dContext, dstInfo, dst, rowBytes, pt);
return tempCtx->readPixels(dContext, dst, pt);
}
bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
auto supportedRead = caps->supportedReadPixelsColorType(
this->colorInfo().colorType(), srcProxy->backendFormat(), dstInfo.colorType());
this->colorInfo().colorType(), srcProxy->backendFormat(), dst.colorType());
bool makeTight = !caps->readPixelsRowBytesSupport() && tightRowBytes != rowBytes;
bool makeTight =
!caps->readPixelsRowBytesSupport() && dst.rowBytes() != dst.info().minRowBytes();
bool convert = unpremul || premul || needColorConversion || flip || makeTight ||
(dstInfo.colorType() != supportedRead.fColorType);
(dst.colorType() != supportedRead.fColorType);
std::unique_ptr<char[]> tmpPixels;
GrImageInfo tmpInfo;
void* readDst = dst;
size_t readRB = rowBytes;
GrPixmap tmp;
void* readDst = dst.addr();
size_t readRB = dst.rowBytes();
if (convert) {
tmpInfo = {supportedRead.fColorType, this->colorInfo().alphaType(),
this->colorInfo().refColorSpace(), dstInfo.width(), dstInfo.height()};
GrImageInfo tmpInfo(supportedRead.fColorType,
this->colorInfo().alphaType(),
this->colorInfo().refColorSpace(),
dst.dimensions());
size_t tmpRB = tmpInfo.minRowBytes();
size_t size = tmpRB * tmpInfo.height();
// Chrome MSAN bots require the data to be initialized (hence the ()).
tmpPixels = std::make_unique<char[]>(size);
tmp = {tmpInfo, tmpPixels.get(), tmpRB};
readDst = tmpPixels.get();
readRB = tmpRB;
pt.fY = flip ? srcSurface->height() - pt.fY - dstInfo.height() : pt.fY;
pt.fY = flip ? srcSurface->height() - pt.fY - dst.height() : pt.fY;
}
dContext->priv().flushSurface(srcProxy);
dContext->submit();
if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dstInfo.width(),
dstInfo.height(), this->colorInfo().colorType(),
if (!dContext->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dst.width(), dst.height(),
this->colorInfo().colorType(),
supportedRead.fColorType, readDst, readRB)) {
return false;
}
if (convert) {
return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, readDst, readRB, flip);
if (tmp.hasPixels()) {
return GrConvertPixels(dst, tmp, flip);
}
return true;
}
bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo& origSrcInfo,
const void* src, size_t rowBytes, SkIPoint pt) {
bool GrSurfaceContext::writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint pt) {
ASSERT_SINGLE_OWNER
RETURN_FALSE_IF_ABANDONED
SkDEBUGCODE(this->validate();)
@ -354,18 +351,11 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
return false;
}
if (!src) {
src = src.clip(this->dimensions(), &pt);
if (!src.hasPixels()) {
return false;
}
size_t tightRowBytes = origSrcInfo.minRowBytes();
if (!rowBytes) {
rowBytes = tightRowBytes;
} else if (rowBytes < tightRowBytes) {
return false;
}
if (!origSrcInfo.isValid()) {
if (!alpha_types_compatible(src.alphaType(), this->colorInfo().alphaType())) {
return false;
}
@ -381,14 +371,8 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
GrSurface* dstSurface = dstProxy->peekSurface();
auto srcInfo = origSrcInfo;
if (!srcInfo.clip(this->width(), this->height(), &pt, &src, rowBytes)) {
return false;
}
// Our tight row bytes may have been changed by clipping.
tightRowBytes = srcInfo.minRowBytes();
SkColorSpaceXformSteps::Flags flags = SkColorSpaceXformSteps{srcInfo, this->colorInfo()}.flags;
SkColorSpaceXformSteps::Flags flags =
SkColorSpaceXformSteps{src.info(), this->colorInfo()}.flags;
bool unpremul = flags.unpremul,
needColorConversion = flags.linearize || flags.gamut_transform || flags.encode,
premul = flags.premul;
@ -402,8 +386,8 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
// For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
// that are premultiplied on the GPU. This is kept as narrow as possible for now.
bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
(srcInfo.colorType() == GrColorType::kRGBA_8888 ||
srcInfo.colorType() == GrColorType::kBGRA_8888) &&
(src.colorType() == GrColorType::kRGBA_8888 ||
src.colorType() == GrColorType::kBGRA_8888) &&
this->asFillContext() &&
(dstColorType == GrColorType::kRGBA_8888 ||
dstColorType == GrColorType::kBGRA_8888) &&
@ -436,7 +420,7 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
GrSurfaceOrigin tempOrigin =
this->asFillContext() ? kTopLeft_GrSurfaceOrigin : this->origin();
auto tempProxy = dContext->priv().proxyProvider()->createProxy(
format, srcInfo.dimensions(), GrRenderable::kNo, 1, GrMipmapped::kNo,
format, src.dimensions(), GrRenderable::kNo, 1, GrMipmapped::kNo,
SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
if (!tempProxy) {
return false;
@ -448,10 +432,11 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
// When the data is really BGRA the write will cause the R and B channels to be swapped in
// the intermediate surface which gets corrected by a swizzle effect when drawing to the
// dst.
GrColorType origSrcColorType = src.colorType();
if (canvas2DFastPath) {
srcInfo = srcInfo.makeColorType(GrColorType::kRGBA_8888);
src = {src.info().makeColorType(GrColorType::kRGBA_8888), src.addr(), src.rowBytes()};
}
if (!tempCtx.writePixels(dContext, srcInfo, src, rowBytes, {0, 0})) {
if (!tempCtx.writePixels(dContext, src, {0, 0})) {
return false;
}
@ -461,7 +446,7 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
fp = dContext->priv().createUPMToPMEffect(
GrTextureEffect::Make(std::move(tempView), tempColorInfo.alphaType()));
// Important: check the original src color type here!
if (origSrcInfo.colorType() == GrColorType::kBGRA_8888) {
if (origSrcColorType == GrColorType::kBGRA_8888) {
fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
}
} else {
@ -470,12 +455,11 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
if (!fp) {
return false;
}
this->asFillContext()->fillRectToRectWithFP(
SkIRect::MakeSize(srcInfo.dimensions()),
SkIRect::MakePtSize(pt, srcInfo.dimensions()),
std::move(fp));
this->asFillContext()->fillRectToRectWithFP(SkIRect::MakeSize(src.dimensions()),
SkIRect::MakePtSize(pt, src.dimensions()),
std::move(fp));
} else {
SkIRect srcRect = SkIRect::MakeWH(srcInfo.width(), srcInfo.height());
SkIRect srcRect = SkIRect::MakeSize(src.dimensions());
SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
if (!this->copy(tempProxy.get(), srcRect, dstPoint)) {
return false;
@ -487,25 +471,26 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
GrColorType allowedColorType =
caps->supportedWritePixelsColorType(this->colorInfo().colorType(),
dstProxy->backendFormat(),
srcInfo.colorType()).fColorType;
src.colorType()).fColorType;
bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
bool makeTight = !caps->writePixelsRowBytesSupport() && rowBytes != tightRowBytes;
bool makeTight = !caps->writePixelsRowBytesSupport() &&
src.rowBytes() != src.info().minRowBytes();
bool convert = premul || unpremul || needColorConversion || makeTight ||
(srcInfo.colorType() != allowedColorType) || flip;
(src.colorType() != allowedColorType) || flip;
std::unique_ptr<char[]> tmpPixels;
GrColorType srcColorType = srcInfo.colorType();
if (convert) {
GrImageInfo tmpInfo(allowedColorType, this->colorInfo().alphaType(),
this->colorInfo().refColorSpace(), srcInfo.width(), srcInfo.height());
GrImageInfo tmpInfo(allowedColorType,
this->colorInfo().alphaType(),
this->colorInfo().refColorSpace(),
src.dimensions());
auto tmpRB = tmpInfo.minRowBytes();
tmpPixels.reset(new char[tmpRB * tmpInfo.height()]);
GrPixmap tmp(tmpInfo, tmpPixels.get(), tmpRB);
GrConvertPixels(tmpInfo, tmpPixels.get(), tmpRB, srcInfo, src, rowBytes, flip);
SkAssertResult(GrConvertPixels(tmp, src, flip));
srcColorType = tmpInfo.colorType();
rowBytes = tmpRB;
src = tmpPixels.get();
src = tmp;
pt.fY = flip ? dstSurface->height() - pt.fY - tmpInfo.height() : pt.fY;
}
@ -516,9 +501,9 @@ bool GrSurfaceContext::writePixels(GrDirectContext* dContext, const GrImageInfo&
// 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, srcInfo.width(),
srcInfo.height(), this->colorInfo().colorType(),
srcColorType, src, rowBytes);
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,
@ -732,7 +717,7 @@ void GrSurfaceContext::asyncReadPixels(GrDirectContext* dContext,
result->addCpuPlane(std::move(data), pm.rowBytes());
SkIPoint pt{rect.fLeft, rect.fTop};
if (!this->readPixels(dContext, ii, pm.writable_addr(), pm.rowBytes(), pt)) {
if (!this->readPixels(dContext, pm, pt)) {
callback(callbackContext, nullptr);
return;
}
@ -976,21 +961,19 @@ void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(GrDirectContext* dContext
if (doSynchronousRead) {
GrImageInfo yInfo(GrColorType::kAlpha_8, kPremul_SkAlphaType, nullptr, dstSize);
GrImageInfo uvInfo = yInfo.makeWH(halfW, halfH);
size_t yRB = yInfo.minRowBytes();
size_t uvRB = uvInfo.minRowBytes();
std::unique_ptr<char[]> y(new char[yRB * yInfo.height()]);
std::unique_ptr<char[]> u(new char[uvRB*uvInfo.height()]);
std::unique_ptr<char[]> v(new char[uvRB*uvInfo.height()]);
if (!yRTC->readPixels(dContext, yInfo, y.get(), yRB, {0, 0}) ||
!uRTC->readPixels(dContext, uvInfo, u.get(), uvRB, {0, 0}) ||
!vRTC->readPixels(dContext, uvInfo, v.get(), uvRB, {0, 0})) {
auto [yPmp, yStorage] = GrPixmap::Allocate(yInfo);
auto [uPmp, uStorage] = GrPixmap::Allocate(uvInfo);
auto [vPmp, vStorage] = GrPixmap::Allocate(uvInfo);
if (!yRTC->readPixels(dContext, yPmp, {0, 0}) ||
!uRTC->readPixels(dContext, uPmp, {0, 0}) ||
!vRTC->readPixels(dContext, vPmp, {0, 0})) {
callback(callbackContext, nullptr);
return;
}
auto result = std::make_unique<AsyncReadResult>(dContext->priv().contextID());
result->addCpuPlane(std::move(y), yRB );
result->addCpuPlane(std::move(u), uvRB);
result->addCpuPlane(std::move(v), uvRB);
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

@ -17,6 +17,7 @@
#include "src/gpu/GrColorInfo.h"
#include "src/gpu/GrDataUtils.h"
#include "src/gpu/GrImageInfo.h"
#include "src/gpu/GrPixmap.h"
#include "src/gpu/GrSurfaceProxy.h"
#include "src/gpu/GrSurfaceProxyView.h"
@ -92,19 +93,13 @@ public:
const GrCaps* caps() const;
/**
* Reads a rectangle of pixels from the render target context.
* Reads a rectangle of pixels from the surface context.
* @param dContext The direct context to use
* @param dstInfo image info for the destination
* @param dst destination pixels for the read
* @param rowBytes bytes in a row of 'dst'
* @param srcPt offset w/in the surface context from which to read
* is a GrDirectContext and fail otherwise.
*/
bool readPixels(GrDirectContext* dContext,
const GrImageInfo& dstInfo,
void* dst,
size_t rowBytes,
SkIPoint srcPt);
bool readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoint srcPt);
using ReadPixelsCallback = SkImage::ReadPixelsCallback;
using ReadPixelsContext = SkImage::ReadPixelsContext;
@ -134,16 +129,10 @@ public:
* Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the
* surfaceDrawContext at the specified position.
* @param dContext The direct context to use
* @param srcInfo image info for the source pixels
* @param src source for the write
* @param rowBytes bytes in a row of 'src'
* @param dstPt offset w/in the surface context at which to write
*/
bool writePixels(GrDirectContext* dContext,
const GrImageInfo& srcInfo,
const void* src,
size_t rowBytes,
SkIPoint dstPt);
bool writePixels(GrDirectContext* dContext, GrPixmap src, SkIPoint dstPt);
GrSurfaceProxy* asSurfaceProxy() { return fReadView.proxy(); }
const GrSurfaceProxy* asSurfaceProxy() const { return fReadView.proxy(); }
@ -178,7 +167,7 @@ public:
SkFilterQuality);
/**
* Like the above but allows the caller ot specify a destination render target context and
* Like the above but allows the caller ot specify a destination draw context and
* rect within that context. The dst rect must be contained by the dst or this will fail.
*/
bool rescaleInto(GrSurfaceDrawContext* dst,

View File

@ -174,8 +174,7 @@ bool SkGpuDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
return false;
}
return fSurfaceDrawContext->readPixels(dContext, pm.info(), pm.writable_addr(), pm.rowBytes(),
{x, y});
return fSurfaceDrawContext->readPixels(dContext, pm, {x, y});
}
bool SkGpuDevice::onWritePixels(const SkPixmap& pm, int x, int y) {
@ -187,7 +186,7 @@ bool SkGpuDevice::onWritePixels(const SkPixmap& pm, int x, int y) {
return false;
}
return fSurfaceDrawContext->writePixels(dContext, pm.info(), pm.addr(), pm.rowBytes(), {x, y});
return fSurfaceDrawContext->writePixels(dContext, pm, {x, y});
}
bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) {

View File

@ -24,8 +24,6 @@ in fragmentProcessor inputFP;
static constexpr int kSize = 256;
SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
uint32_t* srcData = data.get();
uint32_t* firstRead = data.get() + kSize * kSize;
uint32_t* secondRead = data.get() + 2 * kSize * kSize;
// Fill with every possible premultiplied A, color channel value. There will be 256-y
// duplicate values in row y. We set r, g, and b to the same value since they are handled
@ -39,8 +37,6 @@ in fragmentProcessor inputFP;
color[0] = std::min(x, y);
}
}
std::fill_n( firstRead, kSize * kSize, 0);
std::fill_n(secondRead, kSize * kSize, 0);
const SkImageInfo pmII =
SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
@ -65,6 +61,14 @@ in fragmentProcessor inputFP;
return false;
}
uint32_t* firstRead = data.get() + kSize*kSize;
uint32_t* secondRead = data.get() + 2*kSize*kSize;
std::fill_n( firstRead, kSize*kSize, 0);
std::fill_n(secondRead, kSize*kSize, 0);
GrPixmap firstReadPM( upmII, firstRead, kSize*sizeof(uint32_t));
GrPixmap secondReadPM(upmII, secondRead, kSize*sizeof(uint32_t));
// We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
// from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
// We then verify that two reads produced the same values.
@ -73,7 +77,7 @@ in fragmentProcessor inputFP;
bitmap.alphaType()),
PMConversion::kToUnpremul);
readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp1));
if (!readSFC->readPixels(dContext, upmII, firstRead, 0, {0, 0})) {
if (!readSFC->readPixels(dContext, firstReadPM, {0, 0})) {
return false;
}
@ -89,7 +93,7 @@ in fragmentProcessor inputFP;
PMConversion::kToUnpremul);
readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp3));
if (!readSFC->readPixels(dContext, upmII, secondRead, 0, {0, 0})) {
if (!readSFC->readPixels(dContext, secondReadPM, {0, 0})) {
return false;
}

View File

@ -89,8 +89,6 @@ bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* d
static constexpr int kSize = 256;
SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
uint32_t* srcData = data.get();
uint32_t* firstRead = data.get() + kSize * kSize;
uint32_t* secondRead = data.get() + 2 * kSize * kSize;
// Fill with every possible premultiplied A, color channel value. There will be 256-y
// duplicate values in row y. We set r, g, and b to the same value since they are handled
@ -104,8 +102,6 @@ bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* d
color[0] = std::min(x, y);
}
}
std::fill_n(firstRead, kSize * kSize, 0);
std::fill_n(secondRead, kSize * kSize, 0);
const SkImageInfo pmII =
SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
@ -130,6 +126,14 @@ bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* d
return false;
}
uint32_t* firstRead = data.get() + kSize * kSize;
uint32_t* secondRead = data.get() + 2 * kSize * kSize;
std::fill_n(firstRead, kSize * kSize, 0);
std::fill_n(secondRead, kSize * kSize, 0);
GrPixmap firstReadPM(upmII, firstRead, kSize * sizeof(uint32_t));
GrPixmap secondReadPM(upmII, secondRead, kSize * sizeof(uint32_t));
// We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
// from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
// We then verify that two reads produced the same values.
@ -138,7 +142,7 @@ bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* d
GrTextureEffect::Make(std::move(dataView), bitmap.alphaType()),
PMConversion::kToUnpremul);
readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp1));
if (!readSFC->readPixels(dContext, upmII, firstRead, 0, {0, 0})) {
if (!readSFC->readPixels(dContext, firstReadPM, {0, 0})) {
return false;
}
@ -152,7 +156,7 @@ bool GrConfigConversionEffect::TestForPreservingPMConversions(GrDirectContext* d
PMConversion::kToUnpremul);
readSFC->fillRectWithFP(SkIRect::MakeWH(kSize, kSize), std::move(fp3));
if (!readSFC->readPixels(dContext, upmII, secondRead, 0, {0, 0})) {
if (!readSFC->readPixels(dContext, secondReadPM, {0, 0})) {
return false;
}

View File

@ -241,7 +241,7 @@ static bool save_pixels(GrDirectContext* dContext, GrSurfaceProxyView view, GrCo
return false;
}
bool result = sContext->readPixels(dContext, ii, bm.getPixels(), bm.rowBytes(), {0, 0});
bool result = sContext->readPixels(dContext, bm.pixmap(), {0, 0});
if (!result) {
SkDebugf("------ failed to read pixels for %s\n", filename);
return false;

View File

@ -554,7 +554,7 @@ sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrDirectContext* dContex
GrSurfaceContext surfaceContext(dContext, std::move(view), image->imageInfo().colorInfo());
surfaceContext.writePixels(dContext, pixmap.info(), pixmap.addr(), pixmap.rowBytes(), {0, 0});
surfaceContext.writePixels(dContext, pixmap, {0, 0});
GrSurfaceProxy* p[1] = {surfaceContext.asSurfaceProxy()};
drawingManager->flush(p, SkSurface::BackendSurfaceAccess::kNoAccess, {}, nullptr);

View File

@ -126,8 +126,7 @@ bool SkImage_GpuBase::getROPixels(GrDirectContext* dContext,
return false;
}
if (!sContext->readPixels(dContext, pmap.info(), pmap.writable_addr(), pmap.rowBytes(),
{0, 0})) {
if (!sContext->readPixels(dContext, pmap, {0, 0})) {
return false;
}
@ -166,8 +165,8 @@ bool SkImage_GpuBase::onReadPixels(GrDirectContext* dContext,
int srcX,
int srcY,
CachingHint) const {
if (!fContext->priv().matches(dContext)
|| !SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
if (!fContext->priv().matches(dContext) ||
!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
return false;
}
@ -182,7 +181,7 @@ bool SkImage_GpuBase::onReadPixels(GrDirectContext* dContext,
return false;
}
return sContext->readPixels(dContext, dstInfo, dstPixels, dstRB, {srcX, srcY});
return sContext->readPixels(dContext, {dstInfo, dstPixels, dstRB}, {srcX, srcY});
}
GrSurfaceProxyView SkImage_GpuBase::refView(GrRecordingContext* context,

View File

@ -275,8 +275,7 @@ static void check_base_readbacks(GrDirectContext* dContext,
ERRORF(reporter, "Could not create surface context for colorType: %d\n", colorType);
}
if (!surfaceContext->readPixels(dContext, actual.info(), actual.writable_addr(),
actual.rowBytes(), {0, 0})) {
if (!surfaceContext->readPixels(dContext, actual, {0, 0})) {
// TODO: we need a better way to tell a priori if readPixels will work for an
// arbitrary colorType
#if 0
@ -416,11 +415,7 @@ static void check_mipmaps(GrDirectContext* dContext,
SkAssertResult(actual.tryAlloc(readbackII));
actual.erase(SkColors::kTransparent);
bool result = dstFillContext->readPixels(dContext,
actual.info(),
actual.writable_addr(),
actual.rowBytes(),
{0, 0});
bool result = dstFillContext->readPixels(dContext, actual, {0, 0});
REPORTER_ASSERT(reporter, result);
SkString str;

View File

@ -42,8 +42,7 @@ static bool check_rect(GrDirectContext* dContext, GrSurfaceDrawContext* rtc, con
readback.alloc(dstInfo);
readback.erase(~expectedValue);
if (!rtc->readPixels(dContext, readback.info(), readback.writable_addr(), readback.rowBytes(),
{rect.fLeft, rect.fTop})) {
if (!rtc->readPixels(dContext, readback, {rect.fLeft, rect.fTop})) {
return false;
}

View File

@ -78,12 +78,12 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CopySurface, reporter, ctxInfo) {
for (const SkIRect& srcRect : kSrcRects) {
for (const SkIPoint& dstPoint : kDstPoints) {
for (const SkImageInfo& ii: kImageInfos) {
GrPixmap srcPM(ii, srcPixels.get(), kRowBytes);
GrPixmap dstPM(ii, dstPixels.get(), kRowBytes);
auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(
dContext, sRenderable, sOrigin, ii, srcPixels.get(),
kRowBytes);
dContext, sRenderable, sOrigin, srcPM);
auto dstView = sk_gpu_test::MakeTextureProxyViewFromData(
dContext, dRenderable, dOrigin, ii, dstPixels.get(),
kRowBytes);
dContext, dRenderable, dOrigin, dstPM);
// Should always work if the color type is RGBA, but may not work
// for BGRA
@ -162,8 +162,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CopySurface, reporter, ctxInfo) {
}
sk_memset32(read.get(), 0, kW * kH);
if (!dstContext->readPixels(
dContext, ii, read.get(), kRowBytes, {0, 0})) {
GrPixmap readPM(ii, read.get(), kRowBytes);
if (!dstContext->readPixels(dContext, readPM, {0, 0})) {
ERRORF(reporter, "Error calling readPixels");
continue;
}

View File

@ -47,7 +47,7 @@ static SkBitmap read_back(GrDirectContext* dContext, GrSurfaceDrawContext* rtc,
SkBitmap bm;
bm.allocPixels(dstII);
rtc->readPixels(dContext, dstII, bm.getAddr(0, 0), bm.rowBytes(), {0, 0});
rtc->readPixels(dContext, bm.pixmap(), {0, 0});
return bm;
}

View File

@ -50,8 +50,11 @@ void runFPTest(skiatest::Reporter* reporter, GrDirectContext* dContext,
for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
GrImageInfo info(colorType, kPremul_SkAlphaType, nullptr, {DEV_W, DEV_H});
auto fpView = sk_gpu_test::MakeTextureProxyViewFromData(
dContext, GrRenderable::kYes, origin, info, controlPixelData.begin(), 0);
GrPixmap controlPixmap(info, controlPixelData.begin(), info.minRowBytes());
auto fpView = sk_gpu_test::MakeTextureProxyViewFromData(dContext,
GrRenderable::kYes,
origin,
controlPixmap);
// Floating point textures are NOT supported everywhere
if (!fpView) {
continue;
@ -60,7 +63,8 @@ void runFPTest(skiatest::Reporter* reporter, GrDirectContext* dContext,
auto sContext = GrSurfaceContext::Make(dContext, std::move(fpView), info.colorInfo());
REPORTER_ASSERT(reporter, sContext);
bool result = sContext->readPixels(dContext, info, readBuffer.begin(), 0, {0, 0});
GrPixmap readPixmap(info, readBuffer.begin(), info.minRowBytes());
bool result = sContext->readPixels(dContext, readPixmap, {0, 0});
REPORTER_ASSERT(reporter, result);
REPORTER_ASSERT(reporter,
!memcmp(readBuffer.begin(), controlPixelData.begin(), readBuffer.bytes()));

View File

@ -587,7 +587,7 @@ static void run_test(GrDirectContext* dContext, const char* testName,
const std::unique_ptr<GrSurfaceDrawContext>& rtc, const SkBitmap& gold,
std::function<void(DrawMeshHelper*)> prepareFn,
std::function<void(DrawMeshHelper*)> executeFn) {
const int w = gold.width(), h = gold.height(), rowBytes = gold.rowBytes();
const int w = gold.width(), h = gold.height();
const uint32_t* goldPx = reinterpret_cast<const uint32_t*>(gold.getPixels());
if (h != rtc->height() || w != rtc->width()) {
ERRORF(reporter, "[%s] expectation and rtc not compatible (?).", testName);
@ -598,11 +598,11 @@ static void run_test(GrDirectContext* dContext, const char* testName,
return;
}
SkAutoSTMalloc<kImageHeight * kImageWidth, uint32_t> resultPx(h * rowBytes);
auto [resultPM, resultStorage] = GrPixmap::Allocate(gold.info());
rtc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
rtc->addDrawOp(GrMeshTestOp::Make(dContext, prepareFn, executeFn));
rtc->readPixels(dContext, gold.info(), resultPx, rowBytes, {0, 0});
rtc->readPixels(dContext, resultPM, {0, 0});
#ifdef WRITE_PNG_CONTEXT_TYPE
#define STRINGIFY(X) #X
@ -610,14 +610,13 @@ static void run_test(GrDirectContext* dContext, const char* testName,
SkString filename;
filename.printf("GrMeshTest_%s_%s.png", TOSTRING(WRITE_PNG_CONTEXT_TYPE), testName);
SkDebugf("writing %s...\n", filename.c_str());
ToolUtils::EncodeImageToFile(filename.c_str(), SkPixmap(gold.info(), resultPx, rowBytes),
SkEncodedImageFormat::kPNG, 100);
ToolUtils::EncodeImageToFile(filename.c_str(), resultPM, SkEncodedImageFormat::kPNG, 100);
#endif
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
uint32_t expected = goldPx[y * kImageWidth + x];
uint32_t actual = resultPx[y * kImageWidth + x];
uint32_t actual = static_cast<uint32_t*>(resultPM.addr())[y * kImageWidth + x];
if (expected != actual) {
ERRORF(reporter, "[%s] pixel (%i,%i): got 0x%x expected 0x%x",
testName, x, y, actual, expected);

View File

@ -231,7 +231,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrPipelineDynamicStateTest, reporter, ctxInfo
rtc->addDrawOp(GrPipelineDynamicStateTestOp::Make(dContext, scissorTest, vbuff));
auto ii = SkImageInfo::Make(kScreenSize, kScreenSize,
kRGBA_8888_SkColorType, kPremul_SkAlphaType);
rtc->readPixels(dContext, ii, resultPx, 4 * kScreenSize, {0, 0});
GrPixmap resultPM(ii, resultPx, kScreenSize*sizeof(uint32_t));
rtc->readPixels(dContext, resultPM, {0, 0});
for (int y = 0; y < kScreenSize; ++y) {
for (int x = 0; x < kScreenSize; ++x) {
int expectedColorIdx;

View File

@ -272,9 +272,7 @@ DEF_GPUTEST(InitialTextureClear, reporter, baseOptions) {
auto texCtx = GrSurfaceContext::Make(dContext, std::move(view), info);
readback.erase(kClearColor);
if (texCtx->readPixels(
dContext, readback.info(), readback.writable_addr(),
readback.rowBytes(), {0, 0})) {
if (texCtx->readPixels(dContext, readback, {0, 0})) {
for (int i = 0; i < kSize * kSize; ++i) {
if (!checkColor(combo, readback.addr32()[i])) {
break;
@ -306,8 +304,7 @@ DEF_GPUTEST(InitialTextureClear, reporter, baseOptions) {
}
readback.erase(kClearColor);
if (surfCtx->readPixels(dContext, readback.info(), readback.writable_addr(),
readback.rowBytes(), {0, 0})) {
if (surfCtx->readPixels(dContext, readback, {0, 0})) {
for (int i = 0; i < kSize * kSize; ++i) {
if (!checkColor(combo, readback.addr32()[i])) {
break;
@ -376,8 +373,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
{
SkAutoPixmapStorage read;
read.alloc(srcPixmap.info());
auto readResult = surfContext->readPixels(dContext, srcPixmap.info(),
read.writable_addr(), 0, { 0, 0 });
auto readResult = surfContext->readPixels(dContext, read, {0, 0});
REPORTER_ASSERT(reporter, readResult);
if (readResult) {
comparePixels(srcPixmap, read, reporter);
@ -388,8 +384,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadOnlyTexture, reporter, context_info) {
SkAutoPixmapStorage write;
write.alloc(srcPixmap.info());
fillPixels(&write, [&srcPixmap](int x, int y) { return ~*srcPixmap.addr32(); });
auto writeResult = surfContext->writePixels(dContext, srcPixmap.info(), write.addr(),
0, {0, 0});
auto writeResult = surfContext->writePixels(dContext, write, {0, 0});
REPORTER_ASSERT(reporter, writeResult == (ioType == kRW_GrIOType));
// Try the low level write.
dContext->flushAndSubmit();

View File

@ -604,8 +604,7 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
SkBitmap readBack;
readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
SkAssertResult(rtc->readPixels(dContext, readBack.info(), readBack.getPixels(),
readBack.rowBytes(), {0, 0}));
SkAssertResult(rtc->readPixels(dContext, readBack.pixmap(), {0, 0}));
dContext->priv().testingOnly_flushAndRemoveOnFlushCallbackObject(&object);

View File

@ -246,9 +246,9 @@ void render_fp(GrDirectContext* dContext,
GrColor* outBuffer) {
test_draw_op(dContext, rtc, std::move(fp));
std::fill_n(outBuffer, rtc->width() * rtc->height(), 0);
rtc->readPixels(dContext, SkImageInfo::Make(rtc->width(), rtc->height(), kRGBA_8888_SkColorType,
kPremul_SkAlphaType),
outBuffer, /*rowBytes=*/0, /*srcPt=*/{0, 0});
auto ii = SkImageInfo::Make(rtc->dimensions(), kRGBA_8888_SkColorType, kPremul_SkAlphaType);
GrPixmap resultPM(ii, outBuffer, rtc->width()*sizeof(uint32_t));
rtc->readPixels(dContext, resultPM, {0, 0});
}
// This class is responsible for reproducibly generating a random fragment processor.
@ -413,7 +413,7 @@ bool log_texture_view(GrDirectContext* dContext, GrSurfaceProxyView src, SkStrin
auto sContext = GrSurfaceContext::Make(dContext, std::move(src), ii.colorInfo());
SkBitmap bm;
SkAssertResult(bm.tryAllocPixels(ii));
SkAssertResult(sContext->readPixels(dContext, ii, bm.getPixels(), bm.rowBytes(), {0, 0}));
SkAssertResult(sContext->readPixels(dContext, bm.pixmap(), {0, 0}));
return BipmapToBase64DataURI(bm, dst);
}

View File

@ -647,7 +647,7 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
} else if (readCT == kUnknown_SkColorType) {
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
} else if (readAT == kUnknown_SkAlphaType) {
} else if ((readAT == kUnknown_SkAlphaType) != (srcAT == kUnknown_SkAlphaType)) {
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
} else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
REPORTER_ASSERT(reporter, result != GpuReadResult::kSuccess);
@ -714,8 +714,22 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
diffs[0], diffs[1], diffs[2], diffs[3]);
});
SkAutoPixmapStorage ref;
ref.alloc(readInfo.makeWH(dstWriteRect.width(), dstWriteRect.height()));
srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
SkImageInfo refInfo = readInfo.makeDimensions(dstWriteRect.size());
ref.alloc(refInfo);
if (readAT == kUnknown_SkAlphaType) {
// Do a spoofed read where src and dst alpha type are both kUnpremul. This will
// allow SkPixmap readPixels to succeed and won't do any alpha type conversion.
SkPixmap unpremulRef(refInfo.makeAlphaType(kUnpremul_SkAlphaType),
ref.addr(),
ref.rowBytes());
SkPixmap unpremulSRc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
srcPixels.addr(),
srcPixels.rowBytes());
unpremulSRc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
} else {
srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
}
// This is the part of dstPixels that should have been updated.
SkPixmap actual;
SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
@ -755,9 +769,13 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
auto make_ref_f32_data = [](SkAlphaType srcAT, SkColorType srcCT) -> SkAutoPixmapStorage {
// Make src data in F32 with srcAT. We will convert it to each color type we test to
// initialize the src.
const auto refInfo =
auto surfInfo =
SkImageInfo::Make(kW, kH, kRGBA_F32_SkColorType, srcAT, SkColorSpace::MakeSRGB());
auto refSurf = SkSurface::MakeRaster(refInfo);
// Can't make a kUnknown_SkAlphaType surface.
if (srcAT == kUnknown_SkAlphaType) {
surfInfo = surfInfo.makeAlphaType(kUnpremul_SkAlphaType);
}
auto refSurf = SkSurface::MakeRaster(surfInfo);
static constexpr SkPoint kPts1[] = {{0, 0}, {kW, kH}};
static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
SkPaint paint;
@ -795,7 +813,15 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
const auto srcInfo = SkImageInfo::Make(kW, kH, srcCT, srcAT, SkColorSpace::MakeSRGB());
SkAutoPixmapStorage srcPixels;
srcPixels.alloc(srcInfo);
refSurf->readPixels(srcPixels, 0, 0);
SkPixmap readPixmap = srcPixels;
// Spoof the alpha type to kUnpremul so the read will succeed without doing any conversion
// (because we made our surface also be kUnpremul).
if (srcAT == kUnknown_SkAlphaType) {
readPixmap.reset(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
srcPixels.addr(),
srcPixels.rowBytes());
}
refSurf->readPixels(readPixmap, 0, 0);
return srcPixels;
};
const std::vector<SkIRect> longRectArray = {
@ -864,8 +890,7 @@ static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
readCTTestedThoroughly = {};
for (int sat = 0; sat < kLastEnum_SkAlphaType; ++sat) {
const auto srcAT = static_cast<SkAlphaType>(sat);
if (srcAT == kUnknown_SkAlphaType ||
(srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc)) {
if (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc) {
continue;
}
for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
@ -933,11 +958,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextReadPixels, reporter, ctxInfo)
GrDirectContext* direct = ctxInfo.directContext();
auto reader = std::function<GpuReadSrcFn<Surface>>(
[direct](const Surface& surface, const SkIVector& offset, const SkPixmap& pixels) {
if (surface->readPixels(direct,
pixels.info(),
pixels.writable_addr(),
pixels.rowBytes(),
{offset.fX, offset.fY})) {
if (surface->readPixels(direct, pixels, {offset.fX, offset.fY})) {
return GpuReadResult::kSuccess;
} else {
// Reading from a non-renderable format is not guaranteed to work on GL.
@ -968,11 +989,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceContextReadPixels, reporter, ctxInfo)
origin,
renderable);
if (surfContext) {
surfContext->writePixels(direct,
src.info(),
src.addr(),
src.rowBytes(),
{0, 0});
surfContext->writePixels(direct, src, {0, 0});
}
return surfContext;
});

View File

@ -98,11 +98,15 @@ static void test_copy_to_surface(skiatest::Reporter* reporter,
for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
auto origin = dstContext->origin();
auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(
dContext, renderable, origin,
{GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr, dstContext->width(),
dstContext->height()},
pixels.get(), 0);
GrImageInfo info(GrColorType::kRGBA_8888,
kPremul_SkAlphaType,
nullptr,
dstContext->dimensions());
GrPixmap pixmap(info, pixels.get(), dstContext->width()*sizeof(uint32_t));
auto srcView = sk_gpu_test::MakeTextureProxyViewFromData(dContext,
renderable,
origin,
pixmap);
// If this assert ever fails we can add a fallback to do copy as draw, but until then we can
// be more restrictive.
SkAssertResult(dstContext->testCopy(srcView.proxy()));

View File

@ -58,10 +58,9 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RenderTargetContextTest, reporter, ctxInfo) {
check_instantiation_status(reporter, rtCtx.get(), false);
SkImageInfo dstInfo = SkImageInfo::MakeN32Premul(kSize, kSize);
SkAutoTMalloc<uint32_t> dstBuffer(kSize * kSize);
static const size_t kRowBytes = sizeof(uint32_t) * kSize;
auto [dstPM, dstStorage] = GrPixmap::Allocate(dstInfo);
bool result = rtCtx->readPixels(dContext, dstInfo, dstBuffer.get(), kRowBytes, {0, 0});
bool result = rtCtx->readPixels(dContext, dstPM, {0, 0});
REPORTER_ASSERT(reporter, result);
check_instantiation_status(reporter, rtCtx.get(), true);

View File

@ -126,12 +126,11 @@ void read_and_check_pixels(skiatest::Reporter* reporter,
uint32_t* origData,
const SkImageInfo& dstInfo, CheckFn checker, float error,
const char* subtestName) {
int w = dstInfo.width();
int h = dstInfo.height();
SkAutoTMalloc<uint32_t> readData(w * h);
memset(readData.get(), 0, sizeof(uint32_t) * w * h);
auto [w, h] = dstInfo.dimensions();
auto [readPM, readStorage] = GrPixmap::Allocate(dstInfo);
memset(readPM.addr(), 0, sizeof(uint32_t)*w*h);
if (!sContext->readPixels(dContext, dstInfo, readData.get(), 0, {0, 0})) {
if (!sContext->readPixels(dContext, readPM, {0, 0})) {
ERRORF(reporter, "Could not read pixels for %s.", subtestName);
return;
}
@ -139,7 +138,7 @@ void read_and_check_pixels(skiatest::Reporter* reporter,
for (int j = 0; j < h; ++j) {
for (int i = 0; i < w; ++i) {
uint32_t orig = origData[j * w + i];
uint32_t read = readData[j * w + i];
uint32_t read = static_cast<uint32_t*>(readPM.addr())[j * w + i];
if (!checker(orig, read, error)) {
ERRORF(reporter, "Original 0x%08x, read back as 0x%08x in %s at %d, %d).", orig,
@ -212,7 +211,8 @@ static void test_write_read(Encoding contextEncoding, Encoding writeEncoding, En
auto writeII = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
encoding_as_color_space(writeEncoding));
auto data = make_data();
if (!surfaceContext->writePixels(dContext, writeII, data.get(), 0, {0, 0})) {
GrPixmap dataPM(writeII, data.get(), kW*sizeof(uint32_t));
if (!surfaceContext->writePixels(dContext, dataPM, {0, 0})) {
ERRORF(reporter, "Could not write %s to %s surface context.",
encoding_as_str(writeEncoding), encoding_as_str(contextEncoding));
return;

View File

@ -97,9 +97,10 @@ static void run_test(skiatest::Reporter* reporter, GrDirectContext* directContex
SkRect::MakeWH(1,1));
GrColor result;
rtc->readPixels(directContext,
SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType), &result,
4, {0, 0});
GrPixmap resultPM(SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
&result,
sizeof(GrColor));
rtc->readPixels(directContext, resultPM, {0, 0});
SkASSERT(expectedCrossProduct == a.cross(b));
if (expectedCrossProduct > 0) {

View File

@ -729,8 +729,7 @@ static void test_surface_context_clear(skiatest::Reporter* reporter,
readback.alloc(ii);
readback.erase(~expectedValue);
surfaceContext->readPixels(dContext, readback.info(), readback.writable_addr(),
readback.rowBytes(), {0, 0});
surfaceContext->readPixels(dContext, readback, {0, 0});
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
uint32_t pixel = readback.addr32()[y * w + x];

View File

@ -9,6 +9,7 @@
#include "include/encode/SkPngEncoder.h"
#include "include/utils/SkBase64.h"
#include "src/core/SkAutoPixmapStorage.h"
#include "src/core/SkUtils.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrDrawingManager.h"
@ -26,20 +27,22 @@ void TestReadPixels(skiatest::Reporter* reporter,
uint32_t expectedPixelValues[],
const char* testName) {
int pixelCnt = srcContext->width() * srcContext->height();
SkAutoTMalloc<uint32_t> pixels(pixelCnt);
memset(pixels.get(), 0, sizeof(uint32_t)*pixelCnt);
SkImageInfo ii = SkImageInfo::Make(srcContext->dimensions(),
kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
SkAutoPixmapStorage pm;
pm.alloc(ii);
pm.erase(SK_ColorTRANSPARENT);
SkImageInfo ii = SkImageInfo::Make(srcContext->width(), srcContext->height(),
kRGBA_8888_SkColorType, kPremul_SkAlphaType);
bool read = srcContext->readPixels(dContext, ii, pixels.get(), 0, {0, 0});
bool read = srcContext->readPixels(dContext, pm, {0, 0});
if (!read) {
ERRORF(reporter, "%s: Error reading from texture.", testName);
}
for (int i = 0; i < pixelCnt; ++i) {
if (pixels.get()[i] != expectedPixelValues[i]) {
if (pm.addr32()[i] != expectedPixelValues[i]) {
ERRORF(reporter, "%s: Error, pixel value %d should be 0x%08x, got 0x%08x.",
testName, i, expectedPixelValues[i], pixels.get()[i]);
testName, i, expectedPixelValues[i], pm.addr32()[i]);
break;
}
}
@ -50,18 +53,18 @@ void TestWritePixels(skiatest::Reporter* reporter,
GrSurfaceContext* dstContext,
bool expectedToWork,
const char* testName) {
int pixelCnt = dstContext->width() * dstContext->height();
SkAutoTMalloc<uint32_t> pixels(pixelCnt);
for (int y = 0; y < dstContext->width(); ++y) {
for (int x = 0; x < dstContext->height(); ++x) {
pixels.get()[y * dstContext->width() + x] =
SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
SkImageInfo ii = SkImageInfo::Make(dstContext->dimensions(),
kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
SkAutoPixmapStorage pm;
pm.alloc(ii);
for (int y = 0; y < dstContext->height(); ++y) {
for (int x = 0; x < dstContext->width(); ++x) {
*pm.writable_addr32(x, y) = SkColorToPremulGrColor(SkColorSetARGB(2*y, x, y, x + y));
}
}
SkImageInfo ii = SkImageInfo::Make(dstContext->width(), dstContext->height(),
kRGBA_8888_SkColorType, kPremul_SkAlphaType);
bool write = dstContext->writePixels(dContext, ii, pixels.get(), 0, {0, 0});
bool write = dstContext->writePixels(dContext, pm, {0, 0});
if (!write) {
if (expectedToWork) {
ERRORF(reporter, "%s: Error writing to texture.", testName);
@ -74,7 +77,7 @@ void TestWritePixels(skiatest::Reporter* reporter,
return;
}
TestReadPixels(reporter, dContext, dstContext, pixels.get(), testName);
TestReadPixels(reporter, dContext, dstContext, pm.writable_addr32(0, 0), testName);
}
void TestCopyFromSurface(skiatest::Reporter* reporter,

View File

@ -5,54 +5,57 @@
* found in the LICENSE file.
*/
#include "tools/gpu/ProxyUtils.h"
#include "include/core/SkColor.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "src/gpu/GrDirectContextPriv.h"
#include "src/gpu/GrDrawingManager.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrImageInfo.h"
#include "src/gpu/GrPixmap.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrSurfaceContext.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
#include "tools/gpu/ProxyUtils.h"
namespace sk_gpu_test {
GrSurfaceProxyView MakeTextureProxyViewFromData(GrDirectContext* dContext,
GrRenderable renderable,
GrSurfaceOrigin origin,
const GrImageInfo& imageInfo,
const void* data,
size_t rowBytes) {
GrPixmap pixmap) {
if (dContext->abandoned()) {
return {};
}
const GrCaps* caps = dContext->priv().caps();
const GrBackendFormat format = caps->getDefaultBackendFormat(imageInfo.colorType(), renderable);
const GrBackendFormat format = caps->getDefaultBackendFormat(pixmap.colorType(), renderable);
if (!format.isValid()) {
return {};
}
GrSwizzle swizzle = caps->getReadSwizzle(format, imageInfo.colorType());
GrSwizzle swizzle = caps->getReadSwizzle(format, pixmap.colorType());
sk_sp<GrTextureProxy> proxy;
proxy = dContext->priv().proxyProvider()->createProxy(format, imageInfo.dimensions(),
renderable, 1, GrMipmapped::kNo,
SkBackingFit::kExact, SkBudgeted::kYes,
proxy = dContext->priv().proxyProvider()->createProxy(format,
pixmap.dimensions(),
renderable,
/*sample count*/ 1,
GrMipmapped::kNo,
SkBackingFit::kExact,
SkBudgeted::kYes,
GrProtected::kNo);
if (!proxy) {
return {};
}
GrSurfaceProxyView view(proxy, origin, swizzle);
auto sContext = GrSurfaceContext::Make(dContext, std::move(view), imageInfo.colorInfo());
auto sContext = GrSurfaceContext::Make(dContext, std::move(view), pixmap.colorInfo());
if (!sContext) {
return {};
}
if (!sContext->writePixels(dContext, imageInfo, data, rowBytes, {0, 0})) {
if (!sContext->writePixels(dContext, pixmap, {0, 0})) {
return {};
}
return sContext->readSurfaceView();

View File

@ -15,6 +15,7 @@
class GrDirectContext;
class GrProgramInfo;
class GrPixmap;
namespace sk_gpu_test {
@ -22,9 +23,7 @@ namespace sk_gpu_test {
GrSurfaceProxyView MakeTextureProxyViewFromData(GrDirectContext*,
GrRenderable,
GrSurfaceOrigin,
const GrImageInfo&,
const void* data,
size_t rowBytes);
GrPixmap pixmap);
GrProgramInfo* CreateProgramInfo(const GrCaps*,
SkArenaAlloc*,