Restrict acceptable bounds for uploading data to mip levels on GPU

The help simplify the code (and currect a current bug) inside the uploadPixel
functions in GL and Vulkan, we not restrict the bounds upload/write bounds
on a higher level. For non mipped uploads, we requiring the bounds to be within
the bounds on the texture, and for mipped uploads we require the bounds to be
the full texture.

Bug: skia:6780
Change-Id: Ia1cff3ee48edd3676afce6265d60e81ccea6ca6a
Reviewed-on: https://skia-review.googlesource.com/20825
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Greg Daniel 2017-06-26 14:55:05 -04:00 committed by Skia Commit-Bot
parent 4e942a301a
commit 660cc9910f
3 changed files with 55 additions and 51 deletions

View File

@ -354,6 +354,17 @@ bool GrGpu::writePixels(GrSurface* surface,
int left, int top, int width, int height,
GrPixelConfig config, const SkTArray<GrMipLevel>& texels) {
SkASSERT(surface);
if (1 == texels.count()) {
// We require that if we are not mipped, then the write region is contained in the surface
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(surface->width(), surface->height());
if (!bounds.contains(subRect)) {
return false;
}
} else if (0 != left || 0 != top || width != surface->width() || height != surface->height()) {
// We require that if the texels are mipped, than the write region is the entire surface
return false;
}
for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) {
if (!texels[currentMipLevel].fPixels ) {
@ -400,6 +411,13 @@ bool GrGpu::transferPixels(GrTexture* texture,
return false;
}
// We require that the write region is contained in the texture
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
if (!bounds.contains(subRect)) {
return false;
}
this->handleDirtyContext();
if (this->onTransferPixels(texture, left, top, width, height, config,
transferBuffer, offset, rowBytes)) {

View File

@ -833,16 +833,18 @@ bool GrGLGpu::onTransferPixels(GrTexture* texture,
const GrGLBuffer* glBuffer = static_cast<const GrGLBuffer*>(transferBuffer);
this->bindBuffer(kXferCpuToGpu_GrBufferType, glBuffer);
SkDEBUGCODE(
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
SkASSERT(bounds.contains(subRect));
)
size_t bpp = GrBytesPerPixel(config);
const size_t trimRowBytes = width * bpp;
const void* pixels = (void*)offset;
if (!GrSurfacePriv::AdjustWritePixelParams(glTex->width(), glTex->height(), bpp,
&left, &top,
&width, &height,
&pixels,
&rowBytes)) {
return false;
if (!rowBytes) {
rowBytes = trimRowBytes;
}
const void* pixels = (void*)offset;
if (width < 0 || width < 0) {
return false;
}
@ -1012,6 +1014,13 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight
int left, int top, int width, int height, GrPixelConfig dataConfig,
const SkTArray<GrMipLevel>& texels) {
SkASSERT(this->caps()->isConfigTexturable(texConfig));
SkDEBUGCODE(
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(texWidth, texHeight);
SkASSERT(bounds.contains(subRect));
)
SkASSERT(1 == texels.count() ||
(0 == left && 0 == top && width == texWidth && height == texHeight));
// unbind any previous transfer buffer
auto& xferBufferState = fHWBufferState[kXferCpuToGpu_GrBufferType];
@ -1041,26 +1050,6 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight
return false;
}
for (int currentMipLevel = 0; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) {
int twoToTheMipLevel = 1 << currentMipLevel;
int currentWidth = SkTMax(1, width / twoToTheMipLevel);
int currentHeight = SkTMax(1, height / twoToTheMipLevel);
if (currentHeight > SK_MaxS32 ||
currentWidth > SK_MaxS32) {
return false;
}
if (!GrSurfacePriv::AdjustWritePixelParams(texWidth, texHeight, bpp, &left, &top,
&currentWidth, &currentHeight,
&texelsShallowCopy[currentMipLevel].fPixels,
&texelsShallowCopy[currentMipLevel].fRowBytes)) {
return false;
}
if (currentWidth < 0 || currentHeight < 0) {
return false;
}
}
// Internal format comes from the texture desc.
GrGLenum internalFormat;
// External format and type come from the upload data.
@ -1122,8 +1111,10 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight
*/
restoreGLRowLength = false;
const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes;
const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes ?
texelsShallowCopy[currentMipLevel].fRowBytes :
trimRowBytes;
// TODO: This optimization should be enabled with or without mips.
// For use with mips, we must set GR_GL_UNPACK_ROW_LENGTH once per
// mip level, before calling glTexImage2D.

View File

@ -444,6 +444,11 @@ bool GrVkGpu::onTransferPixels(GrTexture* texture,
return false;
}
SkDEBUGCODE(
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
SkASSERT(bounds.contains(subRect));
)
size_t bpp = GrBytesPerPixel(config);
if (rowBytes == 0) {
rowBytes = bpp*width;
@ -555,13 +560,16 @@ bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex,
SkASSERT(data);
SkASSERT(tex->isLinearTiled());
SkDEBUGCODE(
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(tex->width(), tex->height());
SkASSERT(bounds.contains(subRect));
)
size_t bpp = GrBytesPerPixel(dataConfig);
if (!GrSurfacePriv::AdjustWritePixelParams(tex->width(), tex->height(), bpp, &left, &top,
&width, &height, &data, &rowBytes)) {
return false;
}
size_t trimRowBytes = width * bpp;
if (!rowBytes) {
rowBytes = trimRowBytes;
}
SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
@ -643,16 +651,6 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex,
// Determine whether we need to flip when we copy into the buffer
bool flipY = (kBottomLeft_GrSurfaceOrigin == tex->origin() && !texelsShallowCopy.empty());
// adjust any params (left, top, currentWidth, currentHeight
// find the combined size of all the mip levels and the relative offset of
// each into the collective buffer
// Do the first level separately because we may need to adjust width and height
// (for the non-mipped case).
if (!GrSurfacePriv::AdjustWritePixelParams(tex->width(), tex->height(), bpp, &left, &top,
&width, &height, &texelsShallowCopy[0].fPixels,
&texelsShallowCopy[0].fRowBytes)) {
return false;
}
SkTArray<size_t> individualMipOffsets(texelsShallowCopy.count());
individualMipOffsets.push_back(0);
size_t combinedBufferSize = width * bpp * height;
@ -665,12 +663,7 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex,
for (int currentMipLevel = 1; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) {
currentWidth = SkTMax(1, currentWidth/2);
currentHeight = SkTMax(1, currentHeight/2);
if (!GrSurfacePriv::AdjustWritePixelParams(tex->width(), tex->height(), bpp, &left, &top,
&currentWidth, &currentHeight,
&texelsShallowCopy[currentMipLevel].fPixels,
&texelsShallowCopy[currentMipLevel].fRowBytes)) {
return false;
}
const size_t trimmedSize = currentWidth * bpp * currentHeight;
const size_t alignmentDiff = combinedBufferSize & alignmentMask;
if (alignmentDiff != 0) {
@ -695,7 +688,9 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex,
for (int currentMipLevel = 0; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) {
SkASSERT(1 == texelsShallowCopy.count() || currentHeight == layerHeight);
const size_t trimRowBytes = currentWidth * bpp;
const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes;
const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes ?
texelsShallowCopy[currentMipLevel].fRowBytes :
trimRowBytes;
// copy data into the buffer, skipping the trailing bytes
char* dst = buffer + individualMipOffsets[currentMipLevel];