aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-06-21 15:55:46 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-22 13:14:01 +0000
commit2e5eaf022e9389b1382cc856fcd7a8e90a078e13 (patch)
tree99948f1cd1d90d74538e17c972f102268a9e64be
parent222958d5cbd46af9e643eb77186efceb176dd95d (diff)
Revert "Revert "Clean up onTransferPixels""
Bug: skia:5126 Change-Id: Ia1eaef56cca266ad4c413e711e63646e913222be Reviewed-on: https://skia-review.googlesource.com/20445 Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
-rw-r--r--gn/tests.gni1
-rw-r--r--src/gpu/GrGpu.cpp16
-rw-r--r--src/gpu/GrGpu.h19
-rw-r--r--src/gpu/gl/GrGLBuffer.cpp6
-rw-r--r--src/gpu/gl/GrGLCaps.cpp12
-rw-r--r--src/gpu/gl/GrGLGpu.cpp151
-rw-r--r--src/gpu/gl/GrGLGpu.h7
-rw-r--r--src/gpu/vk/GrVkGpu.cpp62
-rw-r--r--src/gpu/vk/GrVkGpu.h4
-rwxr-xr-xtests/TransferPixelsTest.cpp177
-rw-r--r--tools/gpu/GrTest.cpp2
11 files changed, 372 insertions, 85 deletions
diff --git a/gn/tests.gni b/gn/tests.gni
index 80af7146e7..6843a6f555 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -252,6 +252,7 @@ tests_sources = [
"$_tests/TopoSortTest.cpp",
"$_tests/TraceMemoryDumpTest.cpp",
"$_tests/TracingTest.cpp",
+ "$_tests/TransferPixelsTest.cpp",
"$_tests/TypefaceTest.cpp",
"$_tests/UnicodeTest.cpp",
"$_tests/UtilsTest.cpp",
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 cdd9538009..a7ec88ea87 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -456,11 +456,15 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_ARB_pixel_buffer_object")) {
fTransferBufferType = kPBO_TransferBufferType;
}
- } else {
- if (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_NV_pixel_buffer_object")) {
+ } else if (kANGLE_GrGLDriver != ctxInfo.driver()) { // TODO: re-enable for ANGLE
+ 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(&region, 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,
+ &region);
+
+ 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
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
new file mode 100755
index 0000000000..3b221ee531
--- /dev/null
+++ b/tests/TransferPixelsTest.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// This is a GPU-backend specific test. It relies on static intializers to work
+
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrContextFactory.h"
+#include "GrContextPriv.h"
+#include "GrGpu.h"
+#include "GrResourceProvider.h"
+#include "GrSurfaceProxy.h"
+#include "GrTexture.h"
+#include "GrTest.h"
+#include "SkGr.h"
+#include "SkSurface.h"
+#include "Test.h"
+
+using sk_gpu_test::GrContextFactory;
+
+void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
+ GrColor* data) {
+
+ // build red-green gradient
+ for (int j = top; j < top + height; ++j) {
+ for (int i = left; i < left + width; ++i) {
+ unsigned int red = (unsigned int)(256.f*((i - left) / (float)width));
+ unsigned int green = (unsigned int)(256.f*((j - top) / (float)height));
+ data[i + j*bufferWidth] = GrColorPackRGBA(red - (red>>8),
+ green - (green>>8), 0xff, 0xff);
+ }
+ }
+}
+
+bool does_full_buffer_contain_correct_values(GrColor* srcBuffer,
+ GrColor* dstBuffer,
+ int width,
+ int height,
+ int bufferWidth,
+ int bufferHeight,
+ GrSurfaceOrigin origin) {
+ GrColor* srcPtr = srcBuffer;
+ bool bottomUp = SkToBool(kBottomLeft_GrSurfaceOrigin == origin);
+ GrColor* dstPtr = bottomUp ? dstBuffer + bufferWidth*(bufferHeight-1) : dstBuffer;
+ int dstIncrement = bottomUp ? -bufferWidth : +bufferWidth;
+
+ for (int j = 0; j < height; ++j) {
+ for (int i = 0; i < width; ++i) {
+ if (srcPtr[i] != dstPtr[i]) {
+ return false;
+ }
+ }
+ srcPtr += bufferWidth;
+ dstPtr += dstIncrement;
+ }
+ return true;
+}
+
+void basic_transfer_test(skiatest::Reporter* reporter, GrContext* context, GrPixelConfig config,
+ GrSurfaceOrigin origin, bool renderTarget) {
+ // set up the data
+ const int kTextureWidth = 16;
+ const int kTextureHeight = 16;
+ const int kBufferWidth = 20;
+ const int kBufferHeight = 16;
+ size_t rowBytes = kBufferWidth * sizeof(GrColor);
+ SkAutoTMalloc<GrColor> srcBuffer(kBufferWidth*kBufferHeight);
+ SkAutoTMalloc<GrColor> dstBuffer(kBufferWidth*kBufferHeight);
+
+ fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, kBufferWidth, srcBuffer.get());
+
+ // create and fill transfer buffer
+ size_t size = rowBytes*kBufferHeight;
+ uint32_t bufferFlags = GrResourceProvider::kNoPendingIO_Flag;
+ sk_sp<GrBuffer> buffer(context->resourceProvider()->createBuffer(size,
+ kXferCpuToGpu_GrBufferType,
+ kDynamic_GrAccessPattern,
+ bufferFlags));
+ if (!buffer) {
+ return;
+ }
+
+ void* data = buffer->map();
+ memcpy(data, srcBuffer.get(), size);
+ buffer->unmap();
+
+ // create texture
+ GrSurfaceDesc desc;
+ desc.fConfig = config;
+ desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
+ desc.fOrigin = origin;
+ desc.fWidth = kTextureWidth;
+ desc.fHeight = kTextureHeight;
+ desc.fSampleCnt = 0;
+ sk_sp<GrTexture> tex = context->resourceProvider()->createTexture(desc, SkBudgeted::kNo);
+
+ //////////////////////////
+ // transfer full data
+
+ bool result;
+ result = context->getGpu()->transferPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
+ config, buffer.get(), 0, rowBytes);
+ REPORTER_ASSERT(reporter, result);
+
+ memset(dstBuffer.get(), 0xCDCD, size);
+ result = context->getGpu()->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, config,
+ dstBuffer.get(), rowBytes);
+ REPORTER_ASSERT(reporter, result);
+ REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
+ dstBuffer,
+ kTextureWidth,
+ kTextureHeight,
+ kBufferWidth,
+ kBufferHeight,
+ origin));
+ //////////////////////////
+ // transfer partial data
+
+ const int kLeft = 2;
+ const int kTop = 10;
+ const int kWidth = 10;
+ const int kHeight = 2;
+
+ // change color of subrectangle
+ fill_transfer_data(kLeft, kTop, kWidth, kHeight, kBufferWidth, srcBuffer.get());
+ data = buffer->map();
+ memcpy(data, srcBuffer.get(), size);
+ buffer->unmap();
+
+ size_t offset = sizeof(GrColor)*(kTop*kBufferWidth + kLeft);
+ result = context->getGpu()->transferPixels(tex.get(), kLeft, kTop, kWidth, kHeight, config,
+ buffer.get(), offset, rowBytes);
+ REPORTER_ASSERT(reporter, result);
+
+ memset(dstBuffer.get(), 0xCDCD, size);
+ result = context->getGpu()->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, config,
+ dstBuffer.get(), rowBytes);
+ REPORTER_ASSERT(reporter, result);
+
+ REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
+ dstBuffer,
+ kTextureWidth,
+ kTextureHeight,
+ kBufferWidth,
+ kBufferHeight,
+ origin));
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsTest, reporter, ctxInfo) {
+ // RGBA
+ basic_transfer_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig,
+ kTopLeft_GrSurfaceOrigin, false);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig,
+ kTopLeft_GrSurfaceOrigin, true);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig,
+ kBottomLeft_GrSurfaceOrigin, false);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig,
+ kBottomLeft_GrSurfaceOrigin, true);
+
+ // BGRA
+ basic_transfer_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig,
+ kTopLeft_GrSurfaceOrigin, false);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig,
+ kTopLeft_GrSurfaceOrigin, true);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig,
+ kBottomLeft_GrSurfaceOrigin, false);
+ basic_transfer_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig,
+ kBottomLeft_GrSurfaceOrigin, true);
+}
+
+#endif
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index 93e5f6e3b9..301ba6709b 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -402,7 +402,7 @@ private:
return false;
}
- bool onTransferPixels(GrSurface* surface,
+ bool onTransferPixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, GrBuffer* transferBuffer,
size_t offset, size_t rowBytes) override {