diff options
author | Jim Van Verth <jvanverth@google.com> | 2017-06-21 10:52:43 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-06-21 15:28:50 +0000 |
commit | f7037d003c936f59e4d02244821e223c2e7af8e8 (patch) | |
tree | 88949675e25db5cd8c6d136b2b59f19d9bcf2263 /src/gpu | |
parent | 44eb6d9c5ab280cacdfec734e3f3e56285f1f87f (diff) |
Clean up onTransferPixels
Bug: skia:5126
Change-Id: I323c50e7854744302007b4ae7bd25e5742c14cbc
Reviewed-on: https://skia-review.googlesource.com/19055
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrGpu.cpp | 16 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 19 | ||||
-rw-r--r-- | src/gpu/gl/GrGLBuffer.cpp | 6 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 151 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 7 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 62 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 4 |
8 files changed, 192 insertions, 83 deletions
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 262f155c24..e0766a730f 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -389,30 +389,24 @@ bool GrGpu::writePixels(GrSurface* surface, return this->writePixels(surface, left, top, width, height, config, texels); } -bool GrGpu::transferPixels(GrSurface* surface, +bool GrGpu::transferPixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, - size_t offset, size_t rowBytes, GrFence* fence) { + size_t offset, size_t rowBytes) { SkASSERT(transferBuffer); - SkASSERT(fence); // We don't allow conversion between integer configs and float/fixed configs. - if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) { + if (GrPixelConfigIsSint(texture->config()) != GrPixelConfigIsSint(config)) { return false; } this->handleDirtyContext(); - if (this->onTransferPixels(surface, left, top, width, height, config, + if (this->onTransferPixels(texture, left, top, width, height, config, transferBuffer, offset, rowBytes)) { SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); - this->didWriteToSurface(surface, &rect); + this->didWriteToSurface(texture, &rect); fStats.incTransfersToTexture(); - if (*fence) { - this->deleteFence(*fence); - } - *fence = this->insertFence(); - return true; } return false; diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 418b8b418d..d413fd62bb 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -291,23 +291,26 @@ public: size_t rowBytes); /** - * Updates the pixels in a rectangle of a surface using a buffer + * Updates the pixels in a rectangle of a texture using a buffer * - * @param surface The surface to write to. + * There are a couple of assumptions here. First, we only update the top miplevel. + * And second, that any y flip needed has already been done in the buffer. + * + * @param texture The texture to write to. * @param left left edge of the rectangle to write (inclusive) * @param top top edge of the rectangle to write (inclusive) * @param width width of rectangle to write in pixels. * @param height height of rectangle to write in pixels. * @param config the pixel config of the source buffer - * @param transferBuffer GrBuffer to read pixels from (type must be "kCpuToGpu") + * @param transferBuffer GrBuffer to read pixels from (type must be "kXferCpuToGpu") * @param offset offset from the start of the buffer - * @param rowBytes number of bytes between consecutive rows. Zero + * @param rowBytes number of bytes between consecutive rows in the buffer. Zero * means rows are tightly packed. */ - bool transferPixels(GrSurface* surface, + bool transferPixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, - size_t offset, size_t rowBytes, GrFence* fence); + size_t offset, size_t rowBytes); // After the client interacts directly with the 3D context state the GrGpu // must resync its internal state and assumptions about 3D context state. @@ -588,8 +591,8 @@ private: GrPixelConfig config, const SkTArray<GrMipLevel>& texels) = 0; - // overridden by backend-specific derived class to perform the surface write - virtual bool onTransferPixels(GrSurface*, + // overridden by backend-specific derived class to perform the texture transfer + virtual bool onTransferPixels(GrTexture*, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, size_t offset, size_t rowBytes) = 0; 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<GrGLBuffer> 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<GrGLTexture*>(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<const GrGLBuffer*>(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<GrGLTexture*>(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<const GrGLBuffer*>(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<GrMipLevel>& 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<GrMipLevel>& 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, diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index b10e9ed59d..d237632d9e 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -301,11 +301,13 @@ GrBuffer* GrVkGpu::onCreateBuffer(size_t size, GrBufferType type, GrAccessPatter buff = GrVkIndexBuffer::Create(this, size, kDynamic_GrAccessPattern == accessPattern); break; case kXferCpuToGpu_GrBufferType: - SkASSERT(kStream_GrAccessPattern == accessPattern); + SkASSERT(kDynamic_GrAccessPattern == accessPattern || + kStream_GrAccessPattern == accessPattern); buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyRead_Type); break; case kXferGpuToCpu_GrBufferType: - SkASSERT(kStream_GrAccessPattern == accessPattern); + SkASSERT(kDynamic_GrAccessPattern == accessPattern || + kStream_GrAccessPattern == accessPattern); buff = GrVkTransferBuffer::Create(this, size, GrVkBuffer::kCopyWrite_Type); break; case kTexel_GrBufferType: @@ -420,6 +422,62 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, return success; } +bool GrVkGpu::onTransferPixels(GrTexture* texture, + int left, int top, int width, int height, + GrPixelConfig config, GrBuffer* transferBuffer, + size_t bufferOffset, size_t rowBytes) { + // Vulkan only supports 4-byte aligned offsets + if (SkToBool(bufferOffset & 0x2)) { + return false; + } + GrVkTexture* vkTex = static_cast<GrVkTexture*>(texture); + if (!vkTex) { + return false; + } + GrVkTransferBuffer* vkBuffer = static_cast<GrVkTransferBuffer*>(transferBuffer); + if (!vkBuffer) { + return false; + } + + // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels. + if (GrPixelConfigIsSRGB(texture->config()) != GrPixelConfigIsSRGB(config)) { + return false; + } + + size_t bpp = GrBytesPerPixel(config); + if (rowBytes == 0) { + rowBytes = bpp*width; + } + + // Set up copy region + VkBufferImageCopy region; + memset(®ion, 0, sizeof(VkBufferImageCopy)); + region.bufferOffset = bufferOffset; + region.bufferRowLength = (uint32_t)(rowBytes/bpp); + region.bufferImageHeight = 0; + region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + region.imageOffset = { left, top, 0 }; + region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 }; + + // Change layout of our target so it can be copied to + vkTex->setImageLayout(this, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + false); + + // Copy the buffer to the image + fCurrentCmdBuffer->copyBufferToImage(this, + vkBuffer, + vkTex, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ®ion); + + vkTex->texturePriv().dirtyMipMaps(true); + return true; +} + void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { SkASSERT(dst); diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 236b34a3c1..8a3fb09296 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -203,10 +203,10 @@ private: int left, int top, int width, int height, GrPixelConfig config, const SkTArray<GrMipLevel>&) 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 { return false; } + size_t offset, size_t rowBytes) override; // Ends and submits the current command buffer to the queue and then creates a new command // buffer and begins it. If sync is set to kForce_SyncQueue, the function will wait for all |