blob: cd88277fafcd1e3448417de887079ee9e30323df [file] [log] [blame]
Jim Van Verth2e5eaf02017-06-21 15:55:46 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8// This is a GPU-backend specific test. It relies on static intializers to work
9
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkTypes.h"
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkSurface.h"
13#include "include/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrContextPriv.h"
15#include "src/gpu/GrGpu.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040016#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrResourceProvider.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040018#include "src/gpu/GrSurfaceProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/SkGr.h"
20#include "tests/Test.h"
Mike Klein52337de2019-07-25 09:00:52 -050021#include "tests/TestUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "tools/gpu/GrContextFactory.h"
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040023
24using sk_gpu_test::GrContextFactory;
25
26void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -040027 GrColorType dstType, char* dst) {
28 size_t dstBpp = GrColorTypeBytesPerPixel(dstType);
29 auto dstLocation = [dst, dstBpp, bufferWidth](int x, int y) {
30 return dst + y * dstBpp * bufferWidth + x * dstBpp;
31 };
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040032 // build red-green gradient
33 for (int j = top; j < top + height; ++j) {
34 for (int i = left; i < left + width; ++i) {
Brian Salomon42be09d2019-07-26 12:12:26 -040035 auto r = (unsigned int)(256.f*((i - left) / (float)width));
36 auto g = (unsigned int)(256.f*((j - top) / (float)height));
37 r -= (r >> 8);
38 g -= (g >> 8);
39 // set b and a channels to be inverse of r and g just to have interesting values to
40 // test.
41 uint32_t srcPixel = GrColorPackRGBA(r, g, 0xff - r, 0xff - g);
Brian Salomonf2ebdd92019-09-30 12:15:30 -040042 GrImageInfo srcInfo(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, 1, 1);
43 GrImageInfo dstInfo(dstType, kUnpremul_SkAlphaType, nullptr, 1, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -040044 GrConvertPixels(dstInfo, dstLocation(i, j), dstBpp, srcInfo, &srcPixel, 4);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040045 }
46 }
47}
48
Brian Salomon6f6d2de2019-07-26 14:10:33 -040049void determine_tolerances(GrColorType a, GrColorType b, float tolerances[4]) {
Greg Daniel7bf37e02019-07-29 10:09:21 -040050 std::fill_n(tolerances, 4, 0);
51
Brian Salomon6f6d2de2019-07-26 14:10:33 -040052 auto descA = GrGetColorTypeDesc(a);
53 auto descB = GrGetColorTypeDesc(b);
54 // For each channel x set the tolerance to 1 / (2^min(bits_in_a, bits_in_b) - 1) unless
55 // one color type is missing the channel. In that case leave it at 0. If the other color
56 // has the channel then it better be exactly 1 for alpha or 0 for rgb.
57 for (int i = 0; i < 4; ++i) {
58 if (descA[i] != descB[i]) {
59 auto m = std::min(descA[i], descB[i]);
60 if (m) {
61 tolerances[i] = 1.f / (m - 1);
62 }
63 }
64 }
65}
66
Brian Salomonf77c1462019-08-01 15:19:29 -040067bool read_pixels_from_texture(GrTexture* texture, GrColorType colorType, char* dst,
Brian Salomon42be09d2019-07-26 12:12:26 -040068 float tolerances[4]) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040069 auto* context = texture->getContext();
70 auto* gpu = context->priv().getGpu();
71 auto* caps = context->priv().caps();
72
73 int w = texture->width();
74 int h = texture->height();
Brian Salomonf77c1462019-08-01 15:19:29 -040075 size_t rowBytes = GrColorTypeBytesPerPixel(colorType) * w;
Greg Danielc6dc5cf2019-07-17 16:02:00 -040076
77 GrColorType srcCT = GrPixelConfigToColorType(texture->config());
Brian Salomon6aecd5e2019-07-16 09:47:32 -040078
Brian Salomonf77c1462019-08-01 15:19:29 -040079 GrCaps::SupportedRead supportedRead =
80 caps->supportedReadPixelsColorType(srcCT, texture->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -040081 std::fill_n(tolerances, 4, 0);
Brian Salomonf77c1462019-08-01 15:19:29 -040082 if (supportedRead.fColorType != colorType) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040083 size_t tmpRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w;
84 std::unique_ptr<char[]> tmpPixels(new char[tmpRowBytes * h]);
Brian Salomonf77c1462019-08-01 15:19:29 -040085 if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType,
86 tmpPixels.get(), tmpRowBytes)) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040087 return false;
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040088 }
Brian Salomonf2ebdd92019-09-30 12:15:30 -040089 GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
90 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, w, h);
Brian Salomon6f6d2de2019-07-26 14:10:33 -040091 determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances);
Brian Salomon8f8354a2019-07-31 20:12:02 -040092 return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes,
93 false);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040094 }
Brian Salomonf77c1462019-08-01 15:19:29 -040095 return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040096}
97
Brian Salomone05ba5a2019-04-08 11:59:07 -040098void basic_transfer_to_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
Brian Salomonf2c2ba92019-07-17 09:59:59 -040099 GrRenderable renderable) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500100 if (GrCaps::kNone_MapFlags == context->priv().caps()->mapBufferFlags()) {
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400101 return;
102 }
103
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400104 auto* caps = context->priv().caps();
Robert Phillips6be756b2018-01-16 15:07:54 -0500105
Robert Phillips0a15cc62019-07-30 12:49:10 -0400106 auto backendFormat = caps->getDefaultBackendFormat(colorType, renderable);
107 if (!backendFormat.isValid()) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400108 return;
Greg Daniel64329092019-07-16 16:16:21 -0400109 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400110
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400111 auto resourceProvider = context->priv().resourceProvider();
112 GrGpu* gpu = context->priv().getGpu();
113
114 const int kTextureWidth = 16;
115 const int kTextureHeight = 16;
Brian Salomonf27e51f2019-07-25 13:20:58 -0400116 int srcBufferWidth = caps->writePixelsRowBytesSupport() ? 20 : 16;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400117 const int kBufferHeight = 16;
118
Greg Daniele877dce2019-07-11 10:52:43 -0400119 GrSurfaceDesc desc;
Greg Daniele877dce2019-07-11 10:52:43 -0400120 desc.fWidth = kTextureWidth;
121 desc.fHeight = kTextureHeight;
122 desc.fConfig = GrColorTypeToPixelConfig(colorType);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400123
Brian Salomona90382f2019-09-17 09:01:56 -0400124 sk_sp<GrTexture> tex =
125 resourceProvider->createTexture(desc, backendFormat, renderable, 1, GrMipMapped::kNo,
126 SkBudgeted::kNo, GrProtected::kNo);
Greg Daniele877dce2019-07-11 10:52:43 -0400127 if (!tex) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400128 ERRORF(reporter, "Could not create texture");
Greg Daniele877dce2019-07-11 10:52:43 -0400129 return;
130 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400131
Brian Salomon42be09d2019-07-26 12:12:26 -0400132 // We validate the results using GrGpu::readPixels, so exit if this is not supported.
133 // TODO: Do this through GrSurfaceContext once it works for all color types or support
134 // kCopyToTexture2D here.
135 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
136 caps->surfaceSupportsReadPixels(tex.get())) {
137 return;
138 }
139 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
140 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
141 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400142 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400143 return;
144 }
145
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400146 // The caps tell us what color type we are allowed to upload and read back from this texture,
147 // either of which may differ from 'colorType'.
Brian Salomon42be09d2019-07-26 12:12:26 -0400148 GrCaps::SupportedWrite allowedSrc =
Brian Salomon01915c02019-08-02 09:57:21 -0400149 caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -0400150 size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth;
Brian Salomonf27e51f2019-07-25 13:20:58 -0400151 std::unique_ptr<char[]> srcData(new char[kTextureHeight * srcRowBytes]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400152
Brian Salomon42be09d2019-07-26 12:12:26 -0400153 fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, srcBufferWidth, allowedSrc.fColorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400154 srcData.get());
155
156 // create and fill transfer buffer
157 size_t size = srcRowBytes * kBufferHeight;
158 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu,
159 kDynamic_GrAccessPattern));
160 if (!buffer) {
161 return;
162 }
163 void* data = buffer->map();
164 if (!buffer) {
165 ERRORF(reporter, "Could not map buffer");
166 return;
167 }
168 memcpy(data, srcData.get(), size);
169 buffer->unmap();
170
Greg Daniele877dce2019-07-11 10:52:43 -0400171 //////////////////////////
172 // transfer full data
Robert Phillips16d8ec62017-07-27 16:16:25 -0400173
Greg Daniele877dce2019-07-11 10:52:43 -0400174 bool result;
Brian Salomonf77c1462019-08-01 15:19:29 -0400175 result = gpu->transferPixelsTo(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400176 allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
Greg Daniele877dce2019-07-11 10:52:43 -0400177 REPORTER_ASSERT(reporter, result);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400178
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400179 size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTextureWidth;
180 std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTextureHeight]());
181
Brian Salomon42be09d2019-07-26 12:12:26 -0400182 float compareTolerances[4] = {};
183 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400184 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400185 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
186 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400187 return;
Greg Daniele877dce2019-07-11 10:52:43 -0400188 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400189
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400190 auto error = std::function<ComparePixmapsErrorReporter>(
191 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400192 ERRORF(reporter,
193 "Error at (%d %d) in transfer, color type: %d, diffs: (%f, %f, %f, %f)", x,
194 y, colorType, diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400195 });
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400196 GrImageInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(),
Brian Salomon42be09d2019-07-26 12:12:26 -0400197 tex->height());
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400198 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height());
Brian Salomon42be09d2019-07-26 12:12:26 -0400199 compare_pixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
200 compareTolerances, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400201
Greg Daniele877dce2019-07-11 10:52:43 -0400202 //////////////////////////
203 // transfer partial data
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400204
205 // We're relying on this cap to write partial texture data
206 if (!caps->writePixelsRowBytesSupport()) {
Greg Daniele877dce2019-07-11 10:52:43 -0400207 return;
208 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400209 // We keep a 1 to 1 correspondence between pixels in the buffer and the entire texture. We
210 // update the contents of a sub-rect of the buffer and push that rect to the texture. We start
211 // with a left sub-rect inset of 2 but may adjust that so we can fulfill the transfer buffer
212 // offset alignment requirement.
213 int left = 2;
214 const int top = 10;
215 const int width = 10;
216 const int height = 2;
217 size_t offset = top * srcRowBytes + left * GrColorTypeBytesPerPixel(allowedSrc.fColorType);
218 while (offset % allowedSrc.fOffsetAlignmentForTransferBuffer) {
219 offset += GrColorTypeBytesPerPixel(allowedSrc.fColorType);
220 ++left;
221 // We're assuming that the required alignment is 1 or a small multiple of the bpp, which
222 // it is currently for all color types across all backends.
223 SkASSERT(left + width <= tex->width());
224 }
Brian Salomonc320b152018-02-20 14:05:36 -0500225
Greg Daniele877dce2019-07-11 10:52:43 -0400226 // change color of subrectangle
Brian Salomon42be09d2019-07-26 12:12:26 -0400227 fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType,
228 srcData.get());
Greg Daniele877dce2019-07-11 10:52:43 -0400229 data = buffer->map();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400230 memcpy(data, srcData.get(), size);
Greg Daniele877dce2019-07-11 10:52:43 -0400231 buffer->unmap();
Brian Salomonc320b152018-02-20 14:05:36 -0500232
Brian Salomonf77c1462019-08-01 15:19:29 -0400233 result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
234 allowedSrc.fColorType, buffer.get(), offset, srcRowBytes);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400235 if (!result) {
Brian Salomonf77c1462019-08-01 15:19:29 -0400236 gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400237 buffer.get(), offset, srcRowBytes);
238 ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
239 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400240 return;
Jim Van Verth52fb02e2017-06-27 10:36:56 -0400241 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400242
243 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
244 if (!result) {
245 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
246 static_cast<int>(colorType));
247 return;
248 }
249 compare_pixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
250 compareTolerances, error);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400251}
252
Brian Salomon42cbedd2019-04-09 15:00:05 -0400253void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400254 GrColorType colorType, GrRenderable renderable) {
Brian Salomon42cbedd2019-04-09 15:00:05 -0400255 auto context = ctxInfo.grContext();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400256 auto caps = context->priv().caps();
257 if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400258 return;
259 }
Jim Van Verth686046b2019-03-18 15:39:22 -0400260
Brian Salomone05ba5a2019-04-08 11:59:07 -0400261 auto resourceProvider = context->priv().resourceProvider();
262 GrGpu* gpu = context->priv().getGpu();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400263
Brian Salomone05ba5a2019-04-08 11:59:07 -0400264 const int kTextureWidth = 16;
265 const int kTextureHeight = 16;
266
267 // We'll do a full texture read into the buffer followed by a partial read. These values
268 // describe the partial read subrect.
269 const int kPartialLeft = 2;
270 const int kPartialTop = 10;
271 const int kPartialWidth = 10;
272 const int kPartialHeight = 2;
273
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400274 // create texture
275 GrSurfaceDesc desc;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400276 desc.fWidth = kTextureWidth;
277 desc.fHeight = kTextureHeight;
278 desc.fConfig = GrColorTypeToPixelConfig(colorType);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400279
Brian Salomon4eb38b72019-08-05 12:58:39 -0400280 auto format = context->priv().caps()->getDefaultBackendFormat(colorType, renderable);
281 if (!format.isValid()) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400282 return;
283 }
284
285 size_t textureDataBpp = GrColorTypeBytesPerPixel(colorType);
286 size_t textureDataRowBytes = kTextureWidth * textureDataBpp;
287 std::unique_ptr<char[]> textureData(new char[kTextureHeight * textureDataRowBytes]);
288 fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, kTextureWidth, colorType,
289 textureData.get());
290 GrMipLevel data;
291 data.fPixels = textureData.get();
292 data.fRowBytes = textureDataRowBytes;
Brian Salomon4eb38b72019-08-05 12:58:39 -0400293 sk_sp<GrTexture> tex = resourceProvider->createTexture(
Brian Salomona90382f2019-09-17 09:01:56 -0400294 desc, format, colorType, renderable, 1, SkBudgeted::kNo, GrProtected::kNo, &data, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400295 if (!tex) {
296 return;
297 }
298
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400299 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
300 caps->surfaceSupportsReadPixels(tex.get())) {
301 return;
302 }
303 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
304 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
305 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400306 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400307 return;
308 }
309
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400310 // Create the transfer buffer.
311 auto allowedRead =
Greg Daniel00fb7242019-07-18 14:28:01 -0400312 caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400313 GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTextureWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400314 kTextureHeight);
315
316 size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType);
Brian Salomon26de56e2019-04-10 12:14:26 -0400317 size_t fullBufferRowBytes = kTextureWidth * bpp;
318 size_t partialBufferRowBytes = kPartialWidth * bpp;
Greg Danielba88ab62019-07-26 09:14:01 -0400319 size_t offsetAlignment = allowedRead.fOffsetAlignmentForTransferBuffer;
Brian Salomon26de56e2019-04-10 12:14:26 -0400320 SkASSERT(offsetAlignment);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400321
322 size_t bufferSize = fullBufferRowBytes * kTextureHeight;
323 // Arbitrary starting offset for the partial read.
Brian Salomon26de56e2019-04-10 12:14:26 -0400324 size_t partialReadOffset = GrSizeAlignUp(11, offsetAlignment);
325 bufferSize = SkTMax(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400326
327 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(
328 bufferSize, GrGpuBufferType::kXferGpuToCpu, kDynamic_GrAccessPattern));
329 REPORTER_ASSERT(reporter, buffer);
330 if (!buffer) {
331 return;
332 }
333
334 int expectedTransferCnt = 0;
335 gpu->stats()->reset();
Greg Daniele877dce2019-07-11 10:52:43 -0400336
337 //////////////////////////
338 // transfer full data
Brian Salomonf77c1462019-08-01 15:19:29 -0400339 bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400340 allowedRead.fColorType, buffer.get(), 0);
Greg Daniele877dce2019-07-11 10:52:43 -0400341 if (!result) {
342 ERRORF(reporter, "transferPixelsFrom failed.");
343 return;
344 }
345 ++expectedTransferCnt;
346
347 GrFlushInfo flushInfo;
348 flushInfo.fFlags = kSyncCpu_GrFlushFlag;
349 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
350 gpu->finishFlush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo,
351 GrPrepareForExternalIORequests());
352 }
353
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400354 // Copy the transfer buffer contents to a temporary so we can manipulate it.
355 const auto* map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400356 REPORTER_ASSERT(reporter, map);
357 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400358 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400359 return;
360 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400361 std::unique_ptr<char[]> transferData(new char[kTextureHeight * fullBufferRowBytes]);
362 memcpy(transferData.get(), map, fullBufferRowBytes * kTextureHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400363 buffer->unmap();
364
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400365 GrImageInfo transferInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTextureWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400366 kTextureHeight);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400367
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400368 float tol[4];
369 determine_tolerances(allowedRead.fColorType, colorType, tol);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400370 auto error = std::function<ComparePixmapsErrorReporter>(
371 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400372 ERRORF(reporter,
373 "Error at (%d %d) in transfer, color type: %d, diffs: (%f, %f, %f, %f)", x,
374 y, colorType, diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400375 });
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400376 GrImageInfo textureDataInfo(colorType, kUnpremul_SkAlphaType, nullptr, kTextureWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400377 kTextureHeight);
378 compare_pixels(textureDataInfo, textureData.get(), textureDataRowBytes, transferInfo,
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400379 transferData.get(), fullBufferRowBytes, tol, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400380
Greg Daniele877dce2019-07-11 10:52:43 -0400381 ///////////////////////
382 // Now test a partial read at an offset into the buffer.
383 result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
Brian Salomonf77c1462019-08-01 15:19:29 -0400384 kPartialHeight, colorType, allowedRead.fColorType,
385 buffer.get(), partialReadOffset);
Greg Daniele877dce2019-07-11 10:52:43 -0400386 if (!result) {
387 ERRORF(reporter, "transferPixelsFrom failed.");
388 return;
389 }
390 ++expectedTransferCnt;
391
392 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
393 gpu->finishFlush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo,
394 GrPrepareForExternalIORequests());
395 }
396
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400397 map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400398 REPORTER_ASSERT(reporter, map);
399 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400400 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400401 return;
402 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400403 const char* bufferStart = reinterpret_cast<const char*>(map) + partialReadOffset;
404 memcpy(transferData.get(), bufferStart, partialBufferRowBytes * kTextureHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400405 buffer->unmap();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400406
407 transferInfo = transferInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400408 const char* textureDataStart =
409 textureData.get() + textureDataRowBytes * kPartialTop + textureDataBpp * kPartialLeft;
410 textureDataInfo = textureDataInfo.makeWH(kPartialWidth, kPartialHeight);
411 compare_pixels(textureDataInfo, textureDataStart, textureDataRowBytes, transferInfo,
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400412 transferData.get(), partialBufferRowBytes, tol, error);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400413#if GR_GPU_STATS
414 REPORTER_ASSERT(reporter, gpu->stats()->transfersFromSurface() == expectedTransferCnt);
415#else
416 (void)expectedTransferCnt;
417#endif
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400418}
Jim Van Verth686046b2019-03-18 15:39:22 -0400419
Brian Salomone05ba5a2019-04-08 11:59:07 -0400420DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsToTest, reporter, ctxInfo) {
421 if (!ctxInfo.grContext()->priv().caps()->transferBufferSupport()) {
422 return;
423 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400424 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400425 for (auto colorType : {
426 GrColorType::kAlpha_8,
427 GrColorType::kBGR_565,
428 GrColorType::kABGR_4444,
429 GrColorType::kRGBA_8888,
430 GrColorType::kRGBA_8888_SRGB,
431 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
432 GrColorType::kRG_88,
433 GrColorType::kBGRA_8888,
434 GrColorType::kRGBA_1010102,
435 // GrColorType::kGray_8, Reading back to kGray is busted.
436 GrColorType::kAlpha_F16,
437 GrColorType::kRGBA_F16,
438 GrColorType::kRGBA_F16_Clamped,
439 GrColorType::kRGBA_F32,
Robert Phillips429f0d32019-09-11 17:03:28 -0400440 GrColorType::kAlpha_16,
Brian Salomon42be09d2019-07-26 12:12:26 -0400441 GrColorType::kRG_1616,
442 GrColorType::kRGBA_16161616,
443 GrColorType::kRG_F16,
444 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400445 basic_transfer_to_test(reporter, ctxInfo.grContext(), colorType, renderable);
446 }
447 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400448}
449
Brian Salomona585fe92019-04-09 14:57:00 -0400450// TODO(bsalomon): Metal
451DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsFromTest, reporter, ctxInfo) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400452 if (!ctxInfo.grContext()->priv().caps()->transferBufferSupport()) {
453 return;
454 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400455 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400456 for (auto colorType : {
457 GrColorType::kAlpha_8,
Robert Phillips429f0d32019-09-11 17:03:28 -0400458 GrColorType::kAlpha_16,
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400459 GrColorType::kBGR_565,
460 GrColorType::kABGR_4444,
461 GrColorType::kRGBA_8888,
462 GrColorType::kRGBA_8888_SRGB,
463 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
464 GrColorType::kRG_88,
465 GrColorType::kBGRA_8888,
466 GrColorType::kRGBA_1010102,
467 // GrColorType::kGray_8, Reading back to kGray is busted.
468 GrColorType::kAlpha_F16,
469 GrColorType::kRGBA_F16,
470 GrColorType::kRGBA_F16_Clamped,
471 GrColorType::kRGBA_F32,
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400472 GrColorType::kRG_1616,
473 GrColorType::kRGBA_16161616,
474 GrColorType::kRG_F16,
475 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400476 basic_transfer_from_test(reporter, ctxInfo, colorType, renderable);
477 }
478 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400479}