blob: 1b459d2c2907dc160639894c2ee0f7e6b6686d26 [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"
16#include "src/gpu/GrResourceProvider.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040017#include "src/gpu/GrSurfaceProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/SkGr.h"
19#include "tests/Test.h"
Mike Klein52337de2019-07-25 09:00:52 -050020#include "tests/TestUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "tools/gpu/GrContextFactory.h"
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040022
23using sk_gpu_test::GrContextFactory;
24
25void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -040026 GrColorType dstType, char* dst) {
27 size_t dstBpp = GrColorTypeBytesPerPixel(dstType);
28 auto dstLocation = [dst, dstBpp, bufferWidth](int x, int y) {
29 return dst + y * dstBpp * bufferWidth + x * dstBpp;
30 };
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040031 // build red-green gradient
32 for (int j = top; j < top + height; ++j) {
33 for (int i = left; i < left + width; ++i) {
Brian Salomon42be09d2019-07-26 12:12:26 -040034 auto r = (unsigned int)(256.f*((i - left) / (float)width));
35 auto g = (unsigned int)(256.f*((j - top) / (float)height));
36 r -= (r >> 8);
37 g -= (g >> 8);
38 // set b and a channels to be inverse of r and g just to have interesting values to
39 // test.
40 uint32_t srcPixel = GrColorPackRGBA(r, g, 0xff - r, 0xff - g);
41 GrPixelInfo srcInfo(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, 1, 1);
42 GrPixelInfo dstInfo(dstType, kUnpremul_SkAlphaType, nullptr, 1, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -040043 GrConvertPixels(dstInfo, dstLocation(i, j), dstBpp, srcInfo, &srcPixel, 4);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040044 }
45 }
46}
47
Brian Salomon6f6d2de2019-07-26 14:10:33 -040048void determine_tolerances(GrColorType a, GrColorType b, float tolerances[4]) {
Greg Daniel7bf37e02019-07-29 10:09:21 -040049 std::fill_n(tolerances, 4, 0);
50
Brian Salomon6f6d2de2019-07-26 14:10:33 -040051 auto descA = GrGetColorTypeDesc(a);
52 auto descB = GrGetColorTypeDesc(b);
53 // For each channel x set the tolerance to 1 / (2^min(bits_in_a, bits_in_b) - 1) unless
54 // one color type is missing the channel. In that case leave it at 0. If the other color
55 // has the channel then it better be exactly 1 for alpha or 0 for rgb.
56 for (int i = 0; i < 4; ++i) {
57 if (descA[i] != descB[i]) {
58 auto m = std::min(descA[i], descB[i]);
59 if (m) {
60 tolerances[i] = 1.f / (m - 1);
61 }
62 }
63 }
64}
65
Brian Salomon42be09d2019-07-26 12:12:26 -040066bool read_pixels_from_texture(GrTexture* texture, GrColorType dstColorType, char* dst,
67 float tolerances[4]) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040068 auto* context = texture->getContext();
69 auto* gpu = context->priv().getGpu();
70 auto* caps = context->priv().caps();
71
72 int w = texture->width();
73 int h = texture->height();
Greg Danielc6dc5cf2019-07-17 16:02:00 -040074 size_t rowBytes = GrColorTypeBytesPerPixel(dstColorType) * w;
75
76 GrColorType srcCT = GrPixelConfigToColorType(texture->config());
Brian Salomon6aecd5e2019-07-16 09:47:32 -040077
78 GrCaps::SupportedRead supportedRead = caps->supportedReadPixelsColorType(
Greg Daniel00fb7242019-07-18 14:28:01 -040079 srcCT, texture->backendFormat(), dstColorType);
Brian Salomon42be09d2019-07-26 12:12:26 -040080 std::fill_n(tolerances, 4, 0);
Brian Salomon1cec69a2019-07-31 10:24:26 -040081 if (supportedRead.fColorType != dstColorType) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040082 size_t tmpRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w;
83 std::unique_ptr<char[]> tmpPixels(new char[tmpRowBytes * h]);
84 if (!gpu->readPixels(texture, 0, 0, w, h,
85 supportedRead.fColorType, tmpPixels.get(), tmpRowBytes)) {
86 return false;
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040087 }
Brian Salomon42be09d2019-07-26 12:12:26 -040088 GrPixelInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
89 GrPixelInfo dstInfo(dstColorType, kUnpremul_SkAlphaType, nullptr, w, h);
Brian Salomon6f6d2de2019-07-26 14:10:33 -040090 determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances);
Brian Salomon1cec69a2019-07-31 10:24:26 -040091 return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes,
92 false);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040093 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -040094 return gpu->readPixels(texture, 0, 0, w, h, supportedRead.fColorType, dst, rowBytes);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040095}
96
Brian Salomone05ba5a2019-04-08 11:59:07 -040097void basic_transfer_to_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
Brian Salomonf2c2ba92019-07-17 09:59:59 -040098 GrRenderable renderable) {
Robert Phillips9da87e02019-02-04 13:26:26 -050099 if (GrCaps::kNone_MapFlags == context->priv().caps()->mapBufferFlags()) {
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400100 return;
101 }
102
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400103 auto* caps = context->priv().caps();
Robert Phillips6be756b2018-01-16 15:07:54 -0500104
Robert Phillips0a15cc62019-07-30 12:49:10 -0400105 auto backendFormat = caps->getDefaultBackendFormat(colorType, renderable);
106 if (!backendFormat.isValid()) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400107 return;
Greg Daniel64329092019-07-16 16:16:21 -0400108 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400109
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400110 auto resourceProvider = context->priv().resourceProvider();
111 GrGpu* gpu = context->priv().getGpu();
112
113 const int kTextureWidth = 16;
114 const int kTextureHeight = 16;
Brian Salomonf27e51f2019-07-25 13:20:58 -0400115 int srcBufferWidth = caps->writePixelsRowBytesSupport() ? 20 : 16;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400116 const int kBufferHeight = 16;
117
Greg Daniele877dce2019-07-11 10:52:43 -0400118 GrSurfaceDesc desc;
Greg Daniele877dce2019-07-11 10:52:43 -0400119 desc.fWidth = kTextureWidth;
120 desc.fHeight = kTextureHeight;
121 desc.fConfig = GrColorTypeToPixelConfig(colorType);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400122
Brian Salomone8a766b2019-07-19 14:24:36 -0400123 sk_sp<GrTexture> tex =
Brian Salomon27b4d8d2019-07-22 14:23:45 -0400124 resourceProvider->createTexture(desc, renderable, 1, SkBudgeted::kNo, GrProtected::kNo,
Brian Salomone8a766b2019-07-19 14:24:36 -0400125 GrResourceProvider::Flags::kNoPendingIO);
Greg Daniele877dce2019-07-11 10:52:43 -0400126 if (!tex) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400127 ERRORF(reporter, "Could not create texture");
Greg Daniele877dce2019-07-11 10:52:43 -0400128 return;
129 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400130
Brian Salomon42be09d2019-07-26 12:12:26 -0400131 // We validate the results using GrGpu::readPixels, so exit if this is not supported.
132 // TODO: Do this through GrSurfaceContext once it works for all color types or support
133 // kCopyToTexture2D here.
134 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
135 caps->surfaceSupportsReadPixels(tex.get())) {
136 return;
137 }
138 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
139 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
140 // drawing to a bindable format.
141 if (!caps->isFormatRenderable(colorType, tex->backendFormat())) {
142 return;
143 }
144
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400145 // The caps tell us what color type we are allowed to upload and read back from this texture,
146 // either of which may differ from 'colorType'.
Brian Salomon42be09d2019-07-26 12:12:26 -0400147 GrCaps::SupportedWrite allowedSrc =
148 caps->supportedWritePixelsColorType(desc.fConfig, colorType);
149 size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth;
Brian Salomonf27e51f2019-07-25 13:20:58 -0400150 std::unique_ptr<char[]> srcData(new char[kTextureHeight * srcRowBytes]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400151
Brian Salomon42be09d2019-07-26 12:12:26 -0400152 fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, srcBufferWidth, allowedSrc.fColorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400153 srcData.get());
154
155 // create and fill transfer buffer
156 size_t size = srcRowBytes * kBufferHeight;
157 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu,
158 kDynamic_GrAccessPattern));
159 if (!buffer) {
160 return;
161 }
162 void* data = buffer->map();
163 if (!buffer) {
164 ERRORF(reporter, "Could not map buffer");
165 return;
166 }
167 memcpy(data, srcData.get(), size);
168 buffer->unmap();
169
Greg Daniele877dce2019-07-11 10:52:43 -0400170 //////////////////////////
171 // transfer full data
Robert Phillips16d8ec62017-07-27 16:16:25 -0400172
Greg Daniele877dce2019-07-11 10:52:43 -0400173 bool result;
Brian Salomon42be09d2019-07-26 12:12:26 -0400174 result = gpu->transferPixelsTo(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
175 allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
Greg Daniele877dce2019-07-11 10:52:43 -0400176 REPORTER_ASSERT(reporter, result);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400177
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400178 size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTextureWidth;
179 std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTextureHeight]());
180
Brian Salomon42be09d2019-07-26 12:12:26 -0400181 float compareTolerances[4] = {};
182 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400183 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400184 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
185 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400186 return;
Greg Daniele877dce2019-07-11 10:52:43 -0400187 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400188
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400189 auto error = std::function<ComparePixmapsErrorReporter>(
190 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400191 ERRORF(reporter,
192 "Error at (%d %d) in transfer, color type: %d, diffs: (%f, %f, %f, %f)", x,
193 y, colorType, diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400194 });
Brian Salomon42be09d2019-07-26 12:12:26 -0400195 GrPixelInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(),
196 tex->height());
197 GrPixelInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height());
198 compare_pixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
199 compareTolerances, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400200
Greg Daniele877dce2019-07-11 10:52:43 -0400201 //////////////////////////
202 // transfer partial data
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400203
204 // We're relying on this cap to write partial texture data
205 if (!caps->writePixelsRowBytesSupport()) {
Greg Daniele877dce2019-07-11 10:52:43 -0400206 return;
207 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400208 // We keep a 1 to 1 correspondence between pixels in the buffer and the entire texture. We
209 // update the contents of a sub-rect of the buffer and push that rect to the texture. We start
210 // with a left sub-rect inset of 2 but may adjust that so we can fulfill the transfer buffer
211 // offset alignment requirement.
212 int left = 2;
213 const int top = 10;
214 const int width = 10;
215 const int height = 2;
216 size_t offset = top * srcRowBytes + left * GrColorTypeBytesPerPixel(allowedSrc.fColorType);
217 while (offset % allowedSrc.fOffsetAlignmentForTransferBuffer) {
218 offset += GrColorTypeBytesPerPixel(allowedSrc.fColorType);
219 ++left;
220 // We're assuming that the required alignment is 1 or a small multiple of the bpp, which
221 // it is currently for all color types across all backends.
222 SkASSERT(left + width <= tex->width());
223 }
Brian Salomonc320b152018-02-20 14:05:36 -0500224
Greg Daniele877dce2019-07-11 10:52:43 -0400225 // change color of subrectangle
Brian Salomon42be09d2019-07-26 12:12:26 -0400226 fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType,
227 srcData.get());
Greg Daniele877dce2019-07-11 10:52:43 -0400228 data = buffer->map();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400229 memcpy(data, srcData.get(), size);
Greg Daniele877dce2019-07-11 10:52:43 -0400230 buffer->unmap();
Brian Salomonc320b152018-02-20 14:05:36 -0500231
Brian Salomon42be09d2019-07-26 12:12:26 -0400232 result = gpu->transferPixelsTo(tex.get(), left, top, width, height, allowedSrc.fColorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400233 buffer.get(), offset, srcRowBytes);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400234 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400235 gpu->transferPixelsTo(tex.get(), left, top, width, height, allowedSrc.fColorType,
236 buffer.get(), offset, srcRowBytes);
237 ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
238 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400239 return;
Jim Van Verth52fb02e2017-06-27 10:36:56 -0400240 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400241
242 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
243 if (!result) {
244 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
245 static_cast<int>(colorType));
246 return;
247 }
248 compare_pixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
249 compareTolerances, error);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400250}
251
Brian Salomon42cbedd2019-04-09 15:00:05 -0400252void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400253 GrColorType colorType, GrRenderable renderable) {
Brian Salomon42cbedd2019-04-09 15:00:05 -0400254 auto context = ctxInfo.grContext();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400255 auto caps = context->priv().caps();
256 if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400257 return;
258 }
Jim Van Verth686046b2019-03-18 15:39:22 -0400259
Brian Salomone05ba5a2019-04-08 11:59:07 -0400260 auto resourceProvider = context->priv().resourceProvider();
261 GrGpu* gpu = context->priv().getGpu();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400262
Brian Salomone05ba5a2019-04-08 11:59:07 -0400263 const int kTextureWidth = 16;
264 const int kTextureHeight = 16;
265
266 // We'll do a full texture read into the buffer followed by a partial read. These values
267 // describe the partial read subrect.
268 const int kPartialLeft = 2;
269 const int kPartialTop = 10;
270 const int kPartialWidth = 10;
271 const int kPartialHeight = 2;
272
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400273 // create texture
274 GrSurfaceDesc desc;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400275 desc.fWidth = kTextureWidth;
276 desc.fHeight = kTextureHeight;
277 desc.fConfig = GrColorTypeToPixelConfig(colorType);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400278
279 if (!context->priv().caps()->isConfigTexturable(desc.fConfig) ||
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400280 (renderable == GrRenderable::kYes &&
281 !context->priv().caps()->isConfigRenderable(desc.fConfig))) {
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 Salomon27b4d8d2019-07-22 14:23:45 -0400293 sk_sp<GrTexture> tex = resourceProvider->createTexture(desc, renderable, 1, SkBudgeted::kNo,
Brian Salomone8a766b2019-07-19 14:24:36 -0400294 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.
306 if (!caps->isFormatRenderable(colorType, tex->backendFormat())) {
307 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 Salomon42be09d2019-07-26 12:12:26 -0400313 GrPixelInfo 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
339 bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTextureWidth, kTextureHeight,
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 Salomon42be09d2019-07-26 12:12:26 -0400365 GrPixelInfo 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 Salomon42be09d2019-07-26 12:12:26 -0400376 GrPixelInfo 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 Salomon6aecd5e2019-07-16 09:47:32 -0400384 kPartialHeight, allowedRead.fColorType, buffer.get(),
Greg Daniele877dce2019-07-11 10:52:43 -0400385 partialReadOffset);
386 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,
440 GrColorType::kR_16,
441 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,
458 GrColorType::kBGR_565,
459 GrColorType::kABGR_4444,
460 GrColorType::kRGBA_8888,
461 GrColorType::kRGBA_8888_SRGB,
462 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
463 GrColorType::kRG_88,
464 GrColorType::kBGRA_8888,
465 GrColorType::kRGBA_1010102,
466 // GrColorType::kGray_8, Reading back to kGray is busted.
467 GrColorType::kAlpha_F16,
468 GrColorType::kRGBA_F16,
469 GrColorType::kRGBA_F16_Clamped,
470 GrColorType::kRGBA_F32,
471 GrColorType::kR_16,
472 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}