From f7037d003c936f59e4d02244821e223c2e7af8e8 Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Wed, 21 Jun 2017 10:52:43 -0400 Subject: Clean up onTransferPixels Bug: skia:5126 Change-Id: I323c50e7854744302007b4ae7bd25e5742c14cbc Reviewed-on: https://skia-review.googlesource.com/19055 Commit-Queue: Jim Van Verth Reviewed-by: Greg Daniel --- src/gpu/gl/GrGLBuffer.cpp | 6 ++ src/gpu/gl/GrGLCaps.cpp | 10 ++- src/gpu/gl/GrGLGpu.cpp | 151 ++++++++++++++++++++++++++++++---------------- src/gpu/gl/GrGLGpu.h | 7 +-- 4 files changed, 114 insertions(+), 60 deletions(-) (limited to 'src/gpu/gl') diff --git a/src/gpu/gl/GrGLBuffer.cpp b/src/gpu/gl/GrGLBuffer.cpp index 7dfc6b81e7..180dc39958 100644 --- a/src/gpu/gl/GrGLBuffer.cpp +++ b/src/gpu/gl/GrGLBuffer.cpp @@ -31,6 +31,12 @@ GrGLBuffer* GrGLBuffer::Create(GrGLGpu* gpu, size_t size, GrBufferType intendedType, GrAccessPattern accessPattern, const void* data) { + if (gpu->glCaps().transferBufferType() == GrGLCaps::kNone_TransferBufferType && + (kXferCpuToGpu_GrBufferType == intendedType || + kXferGpuToCpu_GrBufferType == intendedType)) { + return nullptr; + } + sk_sp buffer(new GrGLBuffer(gpu, size, intendedType, accessPattern, data)); if (0 == buffer->bufferID()) { return nullptr; diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 95791f12bb..faea4e6395 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -457,10 +457,14 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fTransferBufferType = kPBO_TransferBufferType; } } else { - if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_NV_pixel_buffer_object")) { + if (version >= GR_GL_VER(3, 0) || + (ctxInfo.hasExtension("GL_NV_pixel_buffer_object") && + // GL_EXT_unpack_subimage needed to support subtexture rectangles + ctxInfo.hasExtension("GL_EXT_unpack_subimage"))) { fTransferBufferType = kPBO_TransferBufferType; - } else if (ctxInfo.hasExtension("GL_CHROMIUM_pixel_transfer_buffer_object")) { - fTransferBufferType = kChromium_TransferBufferType; +// TODO: get transfer buffers working in Chrome +// } else if (ctxInfo.hasExtension("GL_CHROMIUM_pixel_transfer_buffer_object")) { +// fTransferBufferType = kChromium_TransferBufferType; } } diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index e5e8841c37..f63fc253a3 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -783,36 +783,6 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, left, top, width, height, config, texels); } -bool GrGLGpu::onTransferPixels(GrSurface* surface, - int left, int top, int width, int height, - GrPixelConfig config, GrBuffer* transferBuffer, - size_t offset, size_t rowBytes) { - GrGLTexture* glTex = static_cast(surface->asTexture()); - - if (!check_write_and_transfer_input(glTex, surface, config)) { - return false; - } - - this->setScratchTextureUnit(); - GL_CALL(BindTexture(glTex->target(), glTex->textureID())); - - SkASSERT(!transferBuffer->isMapped()); - SkASSERT(!transferBuffer->isCPUBacked()); - const GrGLBuffer* glBuffer = static_cast(transferBuffer); - this->bindBuffer(kXferCpuToGpu_GrBufferType, glBuffer); - - bool success = false; - GrMipLevel mipLevel; - mipLevel.fPixels = transferBuffer; - mipLevel.fRowBytes = rowBytes; - SkSTArray<1, GrMipLevel> texels; - texels.push_back(mipLevel); - success = this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), glTex->origin(), - glTex->target(), kTransfer_UploadType, left, top, width, height, - config, texels); - return success; -} - // For GL_[UN]PACK_ALIGNMENT. static inline GrGLint config_alignment(GrPixelConfig config) { switch (config) { @@ -839,6 +809,78 @@ static inline GrGLint config_alignment(GrPixelConfig config) { return 0; } +bool GrGLGpu::onTransferPixels(GrTexture* texture, + int left, int top, int width, int height, + GrPixelConfig config, GrBuffer* transferBuffer, + size_t offset, size_t rowBytes) { + GrGLTexture* glTex = static_cast(texture); + GrPixelConfig texConfig = glTex->config(); + SkASSERT(this->caps()->isConfigTexturable(texConfig)); + + if (!check_write_and_transfer_input(glTex, texture, config)) { + return false; + } + + if (width <= 0 || width > SK_MaxS32 || height <= 0 || height > SK_MaxS32) { + return false; + } + + this->setScratchTextureUnit(); + GL_CALL(BindTexture(glTex->target(), glTex->textureID())); + + SkASSERT(!transferBuffer->isMapped()); + SkASSERT(!transferBuffer->isCPUBacked()); + const GrGLBuffer* glBuffer = static_cast(transferBuffer); + this->bindBuffer(kXferCpuToGpu_GrBufferType, glBuffer); + + 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 (width < 0 || width < 0) { + return false; + } + + bool restoreGLRowLength = false; + if (trimRowBytes != rowBytes) { + // we should have checked for this support already + SkASSERT(this->glCaps().unpackRowLengthSupport()); + GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowBytes / bpp)); + restoreGLRowLength = true; + } + + // Internal format comes from the texture desc. + GrGLenum internalFormat; + // External format and type come from the upload data. + GrGLenum externalFormat; + GrGLenum externalType; + if (!this->glCaps().getTexImageFormats(texConfig, config, &internalFormat, + &externalFormat, &externalType)) { + return false; + } + + GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, config_alignment(texConfig))); + GL_CALL(TexSubImage2D(glTex->target(), + 0, + left, top, + width, + height, + externalFormat, externalType, + pixels)); + + if (restoreGLRowLength) { + GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); + } + + return true; +} + /** * Creates storage space for the texture and fills it with texels. * @@ -971,6 +1013,13 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight const SkTArray& texels) { SkASSERT(this->caps()->isConfigTexturable(texConfig)); + // unbind any previous transfer buffer + auto& xferBufferState = fHWBufferState[kXferCpuToGpu_GrBufferType]; + if (!xferBufferState.fBoundBufferUniqueID.isInvalid()) { + GL_CALL(BindBuffer(xferBufferState.fGLTarget, 0)); + xferBufferState.invalidate(); + } + // texels is const. // But we may need to flip the texture vertically to prepare it. // Rather than flip in place and alter the incoming data, @@ -980,7 +1029,7 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight for (int currentMipLevel = texelsShallowCopy.count() - 1; currentMipLevel >= 0; currentMipLevel--) { - SkASSERT(texelsShallowCopy[currentMipLevel].fPixels || kTransfer_UploadType == uploadType); + SkASSERT(texelsShallowCopy[currentMipLevel].fPixels); } const GrGLInterface* interface = this->glInterface(); @@ -1086,30 +1135,26 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); restoreGLRowLength = true; } - } else if (kTransfer_UploadType != uploadType) { - if (trimRowBytes != rowBytes || swFlipY) { - // copy data into our new storage, skipping the trailing bytes - const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels; - if (swFlipY && currentHeight >= 1) { - src += (currentHeight - 1) * rowBytes; - } - char* dst = buffer + individual_mip_offsets[currentMipLevel]; - for (int y = 0; y < currentHeight; y++) { - memcpy(dst, src, trimRowBytes); - if (swFlipY) { - src -= rowBytes; - } else { - src += rowBytes; - } - dst += trimRowBytes; + } else if (trimRowBytes != rowBytes || swFlipY) { + // copy data into our new storage, skipping the trailing bytes + const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels; + if (swFlipY && currentHeight >= 1) { + src += (currentHeight - 1) * rowBytes; + } + char* dst = buffer + individual_mip_offsets[currentMipLevel]; + for (int y = 0; y < currentHeight; y++) { + memcpy(dst, src, trimRowBytes); + if (swFlipY) { + src -= rowBytes; + } else { + src += rowBytes; } - // now point data to our copied version - texelsShallowCopy[currentMipLevel].fPixels = buffer + - individual_mip_offsets[currentMipLevel]; - texelsShallowCopy[currentMipLevel].fRowBytes = trimRowBytes; + dst += trimRowBytes; } - } else { - return false; + // now point data to our copied version + texelsShallowCopy[currentMipLevel].fPixels = buffer + + individual_mip_offsets[currentMipLevel]; + texelsShallowCopy[currentMipLevel].fRowBytes = trimRowBytes; } } diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 80a12eb7cc..5897f5dae5 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -247,7 +247,7 @@ private: GrPixelConfig config, const SkTArray& texels) override; - bool onTransferPixels(GrSurface*, + bool onTransferPixels(GrTexture*, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, size_t offset, size_t rowBytes) override; @@ -373,9 +373,8 @@ private: // helper for onCreateTexture and writeTexturePixels enum UploadType { - kNewTexture_UploadType, // we are creating a new texture - kWrite_UploadType, // we are using TexSubImage2D to copy data to an existing texture - kTransfer_UploadType, // we are using a transfer buffer to copy data + kNewTexture_UploadType, // we are creating a new texture + kWrite_UploadType, // we are using TexSubImage2D to copy data to an existing texture }; bool uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight, GrSurfaceOrigin texOrigin, GrGLenum target, UploadType uploadType, int left, -- cgit v1.2.3