GrSurface -> GrGpuBuffer transfer improvements:

GrCaps now only provides the offset alignment requirement. The row bytes
is always bpp * width.

GrGpu::transferPixelsFrom now just returns bool since row bytes value is
implicit. It now asserts offset is aligned with GrCap's provided value
in base class.

Implement caps for GL.

Bug: skia:8962
Change-Id: I3299b62efe9fe05bfe02f2a6a4c2704f647d0f8a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/206686
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2019-04-10 12:14:26 -04:00 committed by Skia Commit-Bot
parent c0d79e525f
commit 26de56ef09
18 changed files with 165 additions and 158 deletions

View File

@ -68,6 +68,7 @@ typedef unsigned char GrGLubyte;
typedef unsigned short GrGLushort;
typedef unsigned int GrGLuint;
typedef uint64_t GrGLuint64;
typedef unsigned short int GrGLhalf;
typedef float GrGLfloat;
typedef float GrGLclampf;
typedef double GrGLdouble;

View File

@ -277,13 +277,30 @@ bool GrCaps::surfaceSupportsWritePixels(const GrSurface* surface) const {
return surface->readOnly() ? false : this->onSurfaceSupportsWritePixels(surface);
}
bool GrCaps::transferFromBufferRequirements(GrColorType bufferColorType, int width,
size_t* rowBytes, size_t* offsetAlignment) const {
size_t GrCaps::transferFromOffsetAlignment(GrColorType bufferColorType) const {
if (!this->transferBufferSupport()) {
return false;
return 0;
}
return this->onTransferFromBufferRequirements(bufferColorType, width, rowBytes,
offsetAlignment);
size_t result = this->onTransferFromOffsetAlignment(bufferColorType);
if (!result) {
return 0;
}
// It's very convenient to access 1 byte-per-channel 32 bitvRGB/RGBA color types as uint32_t.
// Make those aligned reads out of the buffer even if the underlying API doesn't require it.
auto componentFlags = GrColorTypeComponentFlags(bufferColorType);
if ((componentFlags == kRGBA_SkColorTypeComponentFlags ||
componentFlags == kRGB_SkColorTypeComponentFlags) &&
GrColorTypeBytesPerPixel(bufferColorType) == 4) {
switch (result & 0b11) {
// offset alignment already a multiple of 4
case 0: return result;
// offset alignment is a multiple of 2 but not 4.
case 2: return 2 * result;
// offset alignment is not a multiple of 2.
default: return 4 * result;
}
}
return result;
}
bool GrCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
@ -329,12 +346,3 @@ bool GrCaps::validateSurfaceDesc(const GrSurfaceDesc& desc, GrMipMapped mipped)
GrBackendFormat GrCaps::getBackendFormatFromColorType(SkColorType ct) const {
return this->getBackendFormatFromGrColorType(SkColorTypeToGrColorType(ct), GrSRGBEncoded::kNo);
}
bool GrCaps::onTransferFromBufferRequirements(GrColorType bufferColorType, int width,
size_t* rowBytes, size_t* offsetAlignment) const {
// TODO(bsalomon): Provide backend-specific overrides of this the return the true requirements.
// Currently assuming tight row bytes rounded up to a multiple of 4 and 4 byte offset alignment.
*rowBytes = GrSizeAlignUp(GrColorTypeBytesPerPixel(bufferColorType) * width, 4);
*offsetAlignment = 4;
return true;
}

View File

@ -224,21 +224,16 @@ public:
bool transferBufferSupport() const { return fTransferBufferSupport; }
/**
* Gets the requirements to use GrGpu::transferPixelsFrom for a given GrColorType. To check
* whether a pixels as GrColorType can be read for a given surface see
* supportedReadPixelsColorType() and surfaceSupportsReadPixels().
* Gets the alignment requirement for the buffer offset used with GrGpu::transferPixelsFrom for
* a given GrColorType. To check whether a pixels as GrColorType can be read for a given surface
* see supportedReadPixelsColorType() and surfaceSupportsReadPixels().
*
* @param bufferColorType The color type of the pixel data that will be stored in the transfer
* buffer.
* @param width The number of color values per row that will be stored in the buffer.
* @param rowBytes The number of bytes per row that will be used in the transfer buffer.
* @param alignment The required alignment of the offset into the transfer buffer passed
* to GrGpu::transferPixelsFrom.
* @return true if transferPixelFrom is supported, false otherwise. If false then rowBytes and
* alignment are not updated.
* @return minimum required alignment for the buffer offset or zero if reading to the color type
* is not supported.
*/
bool transferFromBufferRequirements(GrColorType bufferColorType, int width, size_t* rowBytes,
size_t* offsetAlignment) const;
size_t transferFromOffsetAlignment(GrColorType bufferColorType) const;
bool suppressPrints() const { return fSuppressPrints; }
@ -426,8 +421,7 @@ private:
virtual bool onSurfaceSupportsWritePixels(const GrSurface*) const = 0;
virtual bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const = 0;
virtual bool onTransferFromBufferRequirements(GrColorType bufferColorType, int width,
size_t* rowBytes, size_t* offsetAlignment) const;
virtual size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const = 0;
// Backends should implement this if they have any extra requirements for use of window
// rectangles for a specific GrBackendRenderTarget outside of basic support.

View File

@ -330,11 +330,13 @@ bool GrGpu::transferPixelsTo(GrTexture* texture, int left, int top, int width, i
return false;
}
size_t GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
bool GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
SkASSERT(surface);
SkASSERT(transferBuffer);
SkASSERT(this->caps()->transferFromOffsetAlignment(bufferColorType));
SkASSERT(offset % this->caps()->transferFromOffsetAlignment(bufferColorType) == 0);
// We require that the write region is contained in the texture
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
@ -344,12 +346,12 @@ size_t GrGpu::transferPixelsFrom(GrSurface* surface, int left, int top, int widt
}
this->handleDirtyContext();
if (auto result = this->onTransferPixelsFrom(surface, left, top, width, height, bufferColorType,
transferBuffer, offset)) {
if (this->onTransferPixelsFrom(surface, left, top, width, height, bufferColorType,
transferBuffer, offset)) {
fStats.incTransfersFromSurface();
return result;
return true;
}
return 0;
return false;
}
bool GrGpu::regenerateMipMapLevels(GrTexture* texture) {

View File

@ -227,10 +227,14 @@ public:
/**
* Reads the pixels from a rectangle of a surface into a buffer. Use
* GrCaps::transferFromBufferRequirements to determine the requirements for the buffer size
* and offset alignment. If the surface is a MIP mapped texture, the base level is read.
* GrCaps::transferFromOffsetAlignment to determine the requirements for the buffer offset
* alignment. If the surface is a MIP mapped texture, the base level is read.
*
* Returns the number of bytes per row in the buffer or zero on failure.
* If successful the row bytes in the buffer is always:
* GrColorTypeBytesPerPixel(bufferColorType) * width
*
* Asserts that the caller has passed a properly aligned offset and that the buffer is
* large enough to hold the result
*
* @param surface The surface to read from.
* @param left left edge of the rectangle to read (inclusive)
@ -241,9 +245,9 @@ public:
* @param transferBuffer GrBuffer to write pixels to (type must be "kXferGpuToCpu")
* @param offset offset from the start of the buffer
*/
size_t transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset);
bool transferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset);
// After the client interacts directly with the 3D context state the GrGpu
// must resync its internal state and assumptions about 3D context state.
@ -532,9 +536,9 @@ private:
GrColorType colorType, GrGpuBuffer* transferBuffer,
size_t offset, size_t rowBytes) = 0;
// overridden by backend-specific derived class to perform the surface transfer
virtual size_t onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
GrColorType colorType, GrGpuBuffer* transferBuffer,
size_t offset) = 0;
virtual bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height,
GrColorType colorType, GrGpuBuffer* transferBuffer,
size_t offset) = 0;
// overridden by backend-specific derived class to perform the resolve
virtual void onResolveRenderTarget(GrRenderTarget* target) = 0;

View File

@ -3259,3 +3259,44 @@ GrBackendFormat GrGLCaps::getBackendFormatFromGrColorType(GrColorType ct,
return GrBackendFormat::MakeGL(this->configSizedInternalFormat(config), GR_GL_TEXTURE_2D);
}
size_t GrGLCaps::onTransferFromOffsetAlignment(GrColorType bufferColorType) const {
// This implementation is highly coupled with decisions made in initConfigTable and GrGLGpu's
// read pixels implementation and may not be correct for all types. TODO(bsalomon): This will be
// cleaned up/unified as part of removing GrPixelConfig.
// There are known problems with 24 vs 32 bit BPP with this color type. Just fail for now.
if (GrColorType::kRGB_888x == bufferColorType) {
return 0;
}
auto config = GrColorTypeToPixelConfig(bufferColorType, GrSRGBEncoded::kNo);
// This switch is derived from a table titled "Pixel data type parameter values and the
// corresponding GL data types" in the OpenGL spec (Table 8.2 in OpenGL 4.5).
switch (fConfigTable[config].fFormats.fExternalType) {
case GR_GL_UNSIGNED_BYTE: return sizeof(GrGLubyte);
case GR_GL_BYTE: return sizeof(GrGLbyte);
case GR_GL_UNSIGNED_SHORT: return sizeof(GrGLushort);
case GR_GL_SHORT: return sizeof(GrGLshort);
case GR_GL_UNSIGNED_INT: return sizeof(GrGLuint);
case GR_GL_INT: return sizeof(GrGLint);
case GR_GL_HALF_FLOAT: return sizeof(GrGLhalf);
case GR_GL_FLOAT: return sizeof(GrGLfloat);
case GR_GL_UNSIGNED_SHORT_5_6_5: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_SHORT_4_4_4_4: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_SHORT_5_5_5_1: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GrGLuint);
#if 0 // GL types we currently don't use. Here for future reference.
case GR_GL_UNSIGNED_BYTE_3_3_2: return sizeof(GrGLubyte);
case GR_GL_UNSIGNED_BYTE_2_3_3_REV: return sizeof(GrGLubyte);
case GR_GL_UNSIGNED_SHORT_5_6_5_REV: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_SHORT_4_4_4_4_REV: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_SHORT_1_5_5_5_REV: return sizeof(GrGLushort);
case GR_GL_UNSIGNED_INT_8_8_8_8: return sizeof(GrGLuint);
case GR_GL_UNSIGNED_INT_8_8_8_8_REV: return sizeof(GrGLuint);
case GR_GL_UNSIGNED_INT_10_10_10_2: return sizeof(GrGLuint);
case GR_GL_UNSIGNED_INT_24_8: return sizeof(GrGLuint);
case GR_GL_UNSIGNED_INT_10F_11F_11F_REV: return sizeof(GrGLuint);
case GR_GL_UNSIGNED_INT_5_9_9_9_REV: return sizeof(GrGLuint);
case GR_GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return sizeof(GrGLuint);
#endif
default: return 0;
}
}

View File

@ -465,6 +465,7 @@ private:
bool onSurfaceSupportsWritePixels(const GrSurface*) const override;
bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override;
GrGLStandard fStandard;

View File

@ -959,31 +959,14 @@ bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int widt
return true;
}
size_t GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType dstColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
size_t offsetAlignment;
size_t rowBytes;
if (!this->glCaps().transferFromBufferRequirements(dstColorType, width, &rowBytes,
&offsetAlignment)) {
return false;
}
if (offset % offsetAlignment) {
return false;
}
if (offset + rowBytes * height > transferBuffer->size()) {
return false;
}
bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType dstColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
auto* glBuffer = static_cast<GrGLBuffer*>(transferBuffer);
this->bindBuffer(GrGpuBufferType::kXferGpuToCpu, glBuffer);
auto offsetAsPtr = reinterpret_cast<void*>(offset);
if (this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType, offsetAsPtr,
rowBytes)) {
return rowBytes;
}
return 0;
return this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType,
offsetAsPtr, width);
}
/**
@ -2363,7 +2346,7 @@ bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig rea
bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType dstColorType, void* offsetOrPtr,
size_t rowBytes) {
int rowWidthInPixels) {
SkASSERT(surface);
GrGLRenderTarget* renderTarget = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
@ -2413,13 +2396,10 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
GrGLIRect readRect;
readRect.setRelativeTo(glvp, left, top, width, height, kTopLeft_GrSurfaceOrigin);
int bytesPerPixel = GrBytesPerPixel(dstAsConfig);
size_t tightRowBytes = bytesPerPixel * width;
// determine if GL can read using the passed rowBytes or if we need a scratch buffer.
if (rowBytes != tightRowBytes) {
if (rowWidthInPixels != width) {
SkASSERT(this->glCaps().packRowLengthSupport());
SkASSERT(!(rowBytes % bytesPerPixel));
GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, static_cast<GrGLint>(rowBytes / bytesPerPixel)));
GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowWidthInPixels));
}
GL_CALL(PixelStorei(GR_GL_PACK_ALIGNMENT, config_alignment(dstAsConfig)));
@ -2444,7 +2424,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
GR_GL_RENDERBUFFER, stencilAttachment->renderbufferID()));
}
if (rowBytes != tightRowBytes) {
if (rowWidthInPixels != width) {
SkASSERT(this->glCaps().packRowLengthSupport());
GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
}
@ -2459,36 +2439,37 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int
GrColorType dstColorType, void* buffer, size_t rowBytes) {
SkASSERT(surface);
// TODO: Avoid this conversion by making GrGLCaps work with color types.
auto dstAsConfig = GrColorTypeToPixelConfig(dstColorType, GrSRGBEncoded::kNo);
int bytesPerPixel = GrColorTypeBytesPerPixel(dstColorType);
int bytesPerPixel = GrBytesPerPixel(dstAsConfig);
size_t tightRowBytes = bytesPerPixel * width;
size_t readDstRowBytes = tightRowBytes;
// GL_PACK_ROW_LENGTH is in terms of pixels not bytes.
int rowPixelWidth;
void* readDst = buffer;
// determine if GL can read using the passed rowBytes or if we need a scratch buffer.
SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
if (rowBytes != tightRowBytes) {
if (!rowBytes || rowBytes == (size_t)(width * bytesPerPixel)) {
rowPixelWidth = width;
} else {
if (this->glCaps().packRowLengthSupport() && !(rowBytes % bytesPerPixel)) {
readDstRowBytes = rowBytes;
rowPixelWidth = rowBytes / bytesPerPixel;
} else {
scratch.reset(tightRowBytes * height);
scratch.reset(width * bytesPerPixel * height);
readDst = scratch.get();
rowPixelWidth = width;
}
}
if (!this->readOrTransferPixelsFrom(surface, left, top, width, height, dstColorType, readDst,
readDstRowBytes)) {
rowPixelWidth)) {
return false;
}
if (readDst != buffer) {
SkASSERT(readDst != buffer);
SkASSERT(rowBytes != tightRowBytes);
SkASSERT(rowBytes != (size_t)(rowPixelWidth * bytesPerPixel));
const char* src = reinterpret_cast<const char*>(readDst);
char* dst = reinterpret_cast<char*>(buffer);
SkRectMemcpy(dst, rowBytes, src, readDstRowBytes, tightRowBytes, height);
SkRectMemcpy(dst, rowBytes, src, rowPixelWidth * bytesPerPixel, width * bytesPerPixel,
height);
}
return true;
}

View File

@ -239,10 +239,10 @@ private:
bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height, GrColorType,
GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override;
size_t onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
GrGpuBuffer* transferBuffer, size_t offset) override;
bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
GrGpuBuffer* transferBuffer, size_t offset) override;
bool readOrTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
void* offsetOrPtr, size_t rowBytes);
void* offsetOrPtr, int rowWidthInPixels);
// Before calling any variation of TexImage, TexSubImage, etc..., call this to ensure that the
// PIXEL_UNPACK_BUFFER is unbound.

View File

@ -112,6 +112,10 @@ private:
const SkIRect& srcRect, const SkIPoint& dstPoint) const override {
return true;
}
size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override {
// arbitrary
return GrSizeAlignUp(GrColorTypeBytesPerPixel(bufferColorType), 4);
}
static const int kMaxSampleCnt = 16;

View File

@ -96,8 +96,8 @@ private:
size_t rowBytes) override {
return true;
}
size_t onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override {
bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override {
return true;
}
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,

View File

@ -85,6 +85,10 @@ private:
bool onSurfaceSupportsWritePixels(const GrSurface*) const override;
bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override {
// Transfer buffers not yet supported.
return 0;
}
struct ConfigInfo {
ConfigInfo() : fFlags(0) {}

View File

@ -169,12 +169,10 @@ private:
// TODO: not sure this is worth the work since nobody uses it
return false;
}
size_t onTransferPixelsFrom(GrSurface*,
int left, int top, int width, int height,
GrColorType, GrGpuBuffer*,
size_t offset) override {
bool onTransferPixelsFrom(GrSurface*, int left, int top, int width, int height, GrColorType,
GrGpuBuffer*, size_t offset) override {
// TODO: Will need to implement this to support async read backs.
return 0;
return false;
}
bool onRegenerateMipMapLevels(GrTexture*) override;

View File

@ -951,8 +951,7 @@ GrBackendFormat GrVkCaps::getBackendFormatFromGrColorType(GrColorType ct,
return GrBackendFormat::MakeVk(format);
}
bool GrVkCaps::onTransferFromBufferRequirements(GrColorType bufferColorType, int width,
size_t* rowBytes, size_t* offsetAlignment) const {
size_t GrVkCaps::onTransferFromOffsetAlignment(GrColorType bufferColorType) const {
// This GrColorType has 32 bpp but the Vulkan pixel format we use for with may have 24bpp
// (VK_FORMAT_R8G8B8_...) or may be 32 bpp. We don't support post transforming the pixel data
// for transfer-from currently and don't want to have to pass info about the src surface here.
@ -962,19 +961,11 @@ bool GrVkCaps::onTransferFromBufferRequirements(GrColorType bufferColorType, int
size_t bpp = GrColorTypeBytesPerPixel(bufferColorType);
// The VkBufferImageCopy bufferOffset field must be both a multiple of 4 and of a single texel.
switch (bpp & 0b11) {
case 0: // bpp is a multiple of 4
*offsetAlignment = bpp;
break;
case 2: // bpp is a multiple of 2
*offsetAlignment = 2 * bpp;
break;
case 1:
case 3: // bpp neither a multiple of 2 nor 4.
*offsetAlignment = 4 * bpp;
break;
// bpp is already a multiple of 4.
case 0: return bpp;
// bpp is a multiple of 2 but not 4.
case 2: return 2 * bpp;
// bpp is not a multiple of 2.
default: return 4 * bpp;
}
// The bufferRowLength member of VkBufferImageCopy is in texel units and must be >= the extent
// of the src VkImage region.
*rowBytes = width * bpp;
return true;
}

View File

@ -199,8 +199,7 @@ private:
bool onSurfaceSupportsWritePixels(const GrSurface*) const override;
bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
bool onTransferFromBufferRequirements(GrColorType bufferColorType, int width, size_t* rowBytes,
size_t* offsetAlignment) const override;
size_t onTransferFromOffsetAlignment(GrColorType bufferColorType) const override;
struct ConfigInfo {
ConfigInfo() : fOptimalFlags(0), fLinearFlags(0) {}

View File

@ -493,23 +493,12 @@ bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int widt
return true;
}
size_t GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType bufferColorType, GrGpuBuffer* transferBuffer,
size_t offset) {
SkASSERT(surface);
SkASSERT(transferBuffer);
size_t rowBytes;
size_t offsetAlignment;
if (!this->vkCaps().transferFromBufferRequirements(bufferColorType, width, &rowBytes,
&offsetAlignment)) {
return 0;
}
if (offset % offsetAlignment || offset + height * rowBytes > transferBuffer->size()) {
return 0;
}
GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer);
GrVkImage* srcImage;
@ -541,12 +530,7 @@ size_t GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int
VkBufferImageCopy region;
memset(&region, 0, sizeof(VkBufferImageCopy));
region.bufferOffset = offset;
// We're assuming that GrVkCaps made the row bytes tight.
region.bufferRowLength = 0;
#ifdef SK_DEBUG
int bpp = GrColorTypeBytesPerPixel(bufferColorType);
SkASSERT(rowBytes == width * (size_t)bpp);
#endif
region.bufferRowLength = width;
region.bufferImageHeight = 0;
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.imageOffset = { left, top, 0 };
@ -572,7 +556,7 @@ size_t GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int
// The caller is responsible for syncing.
this->submitCommandBuffer(kSkip_SyncQueue);
return rowBytes;
return true;
}
void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,

View File

@ -213,8 +213,8 @@ private:
bool onTransferPixelsTo(GrTexture*, int left, int top, int width, int height, GrColorType,
GrGpuBuffer* transferBuffer, size_t offset, size_t rowBytes) override;
size_t onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override;
bool onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height,
GrColorType, GrGpuBuffer* transferBuffer, size_t offset) override;
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,
GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,

View File

@ -212,21 +212,16 @@ void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::C
const int kPartialWidth = 10;
const int kPartialHeight = 2;
size_t fullBufferRowBytes;
size_t partialBufferRowBytes;
size_t fullBufferOffsetAlignment;
size_t partialBufferOffsetAlignment;
SkAssertResult(context->priv().caps()->transferFromBufferRequirements(
colorType, kTextureWidth, &fullBufferRowBytes, &fullBufferOffsetAlignment));
SkAssertResult(context->priv().caps()->transferFromBufferRequirements(
colorType, kPartialWidth, &partialBufferRowBytes, &partialBufferOffsetAlignment));
size_t bpp = GrColorTypeBytesPerPixel(readColorType);
size_t fullBufferRowBytes = kTextureWidth * bpp;
size_t partialBufferRowBytes = kPartialWidth * bpp;
size_t offsetAlignment = context->priv().caps()->transferFromOffsetAlignment(readColorType);
SkASSERT(offsetAlignment);
size_t bufferSize = fullBufferRowBytes * kTextureHeight;
// Arbitrary starting offset for the partial read.
size_t partialReadOffset = GrSizeAlignUp(11, partialBufferOffsetAlignment);
bufferSize =
SkTMax(bufferSize, partialReadOffset + partialBufferRowBytes * partialBufferRowBytes);
size_t partialReadOffset = GrSizeAlignUp(11, offsetAlignment);
bufferSize = SkTMax(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight);
sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(
bufferSize, GrGpuBufferType::kXferGpuToCpu, kDynamic_GrAccessPattern));
@ -269,10 +264,10 @@ void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::C
//////////////////////////
// transfer full data
auto bufferRowBytes = gpu->transferPixelsFrom(
tex.get(), 0, 0, kTextureWidth, kTextureHeight, readColorType, buffer.get(), 0);
REPORTER_ASSERT(reporter, bufferRowBytes = fullBufferRowBytes);
if (!bufferRowBytes) {
bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
readColorType, buffer.get(), 0);
if (!result) {
ERRORF(reporter, "transferPixelsFrom failed.");
continue;
}
++expectedTransferCnt;
@ -291,17 +286,17 @@ void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::C
kTextureWidth,
kTextureHeight,
textureDataRowBytes,
bufferRowBytes,
fullBufferRowBytes,
readColorType != colorType));
buffer->unmap();
///////////////////////
// Now test a partial read at an offset into the buffer.
bufferRowBytes = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop,
kPartialWidth, kPartialHeight, readColorType,
buffer.get(), partialReadOffset);
REPORTER_ASSERT(reporter, bufferRowBytes = partialBufferRowBytes);
if (!bufferRowBytes) {
result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
kPartialHeight, readColorType, buffer.get(),
partialReadOffset);
if (!result) {
ERRORF(reporter, "transferPixelsFrom failed.");
continue;
}
++expectedTransferCnt;
@ -325,7 +320,7 @@ void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::C
kPartialWidth,
kPartialHeight,
textureDataRowBytes,
bufferRowBytes,
partialBufferRowBytes,
readColorType != colorType));
buffer->unmap();
}