blob: 91f82063658cbcbfae1a69a2e855e46189796fc3 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
14#include "src/gpu/GrGpu.h"
Brian Salomonf2ebdd92019-09-30 12:15:30 -040015#include "src/gpu/GrImageInfo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrResourceProvider.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040017#include "src/gpu/GrSurfaceProxy.h"
Greg Daniel456f9b52020-03-05 19:14:18 +000018#include "src/gpu/GrTexture.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
Brian Salomonf77c1462019-08-01 15:19:29 -040077 GrCaps::SupportedRead supportedRead =
Greg Danield51fa2f2020-01-22 16:53:38 -050078 caps->supportedReadPixelsColorType(colorType, texture->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -040079 std::fill_n(tolerances, 4, 0);
Brian Salomonf77c1462019-08-01 15:19:29 -040080 if (supportedRead.fColorType != colorType) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040081 size_t tmpRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w;
82 std::unique_ptr<char[]> tmpPixels(new char[tmpRowBytes * h]);
Brian Salomonf77c1462019-08-01 15:19:29 -040083 if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType,
84 tmpPixels.get(), tmpRowBytes)) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040085 return false;
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040086 }
Brian Salomonf2ebdd92019-09-30 12:15:30 -040087 GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
88 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, w, h);
Brian Salomon6f6d2de2019-07-26 14:10:33 -040089 determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances);
Brian Salomon8f8354a2019-07-31 20:12:02 -040090 return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes,
91 false);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040092 }
Brian Salomonf77c1462019-08-01 15:19:29 -040093 return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040094}
95
Brian Salomone05ba5a2019-04-08 11:59:07 -040096void basic_transfer_to_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
Brian Salomonf2c2ba92019-07-17 09:59:59 -040097 GrRenderable renderable) {
Robert Phillips9da87e02019-02-04 13:26:26 -050098 if (GrCaps::kNone_MapFlags == context->priv().caps()->mapBufferFlags()) {
Brian Salomon7f56d3d2017-10-09 13:02:49 -040099 return;
100 }
101
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400102 auto* caps = context->priv().caps();
Robert Phillips6be756b2018-01-16 15:07:54 -0500103
Robert Phillips0a15cc62019-07-30 12:49:10 -0400104 auto backendFormat = caps->getDefaultBackendFormat(colorType, renderable);
105 if (!backendFormat.isValid()) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400106 return;
Greg Daniel64329092019-07-16 16:16:21 -0400107 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400108
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400109 auto resourceProvider = context->priv().resourceProvider();
110 GrGpu* gpu = context->priv().getGpu();
111
Brian Salomona56a7462020-02-07 14:17:25 -0500112 static constexpr SkISize kTexDims = {16, 16};
Brian Salomonf27e51f2019-07-25 13:20:58 -0400113 int srcBufferWidth = caps->writePixelsRowBytesSupport() ? 20 : 16;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400114 const int kBufferHeight = 16;
115
Brian Salomona90382f2019-09-17 09:01:56 -0400116 sk_sp<GrTexture> tex =
Brian Salomona56a7462020-02-07 14:17:25 -0500117 resourceProvider->createTexture(kTexDims, backendFormat, renderable, 1,
118 GrMipMapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
Greg Daniele877dce2019-07-11 10:52:43 -0400119 if (!tex) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400120 ERRORF(reporter, "Could not create texture");
Greg Daniele877dce2019-07-11 10:52:43 -0400121 return;
122 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400123
Brian Salomon42be09d2019-07-26 12:12:26 -0400124 // We validate the results using GrGpu::readPixels, so exit if this is not supported.
125 // TODO: Do this through GrSurfaceContext once it works for all color types or support
126 // kCopyToTexture2D here.
127 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
128 caps->surfaceSupportsReadPixels(tex.get())) {
129 return;
130 }
131 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
132 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
133 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400134 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400135 return;
136 }
137
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400138 // The caps tell us what color type we are allowed to upload and read back from this texture,
139 // either of which may differ from 'colorType'.
Brian Salomon42be09d2019-07-26 12:12:26 -0400140 GrCaps::SupportedWrite allowedSrc =
Brian Salomon01915c02019-08-02 09:57:21 -0400141 caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -0400142 size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth;
Brian Salomona56a7462020-02-07 14:17:25 -0500143 std::unique_ptr<char[]> srcData(new char[kTexDims.fHeight * srcRowBytes]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400144
Brian Salomona56a7462020-02-07 14:17:25 -0500145 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, srcBufferWidth,
146 allowedSrc.fColorType, srcData.get());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400147
148 // create and fill transfer buffer
149 size_t size = srcRowBytes * kBufferHeight;
150 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu,
151 kDynamic_GrAccessPattern));
152 if (!buffer) {
153 return;
154 }
155 void* data = buffer->map();
156 if (!buffer) {
157 ERRORF(reporter, "Could not map buffer");
158 return;
159 }
160 memcpy(data, srcData.get(), size);
161 buffer->unmap();
162
Greg Daniele877dce2019-07-11 10:52:43 -0400163 //////////////////////////
164 // transfer full data
Robert Phillips16d8ec62017-07-27 16:16:25 -0400165
Greg Daniele877dce2019-07-11 10:52:43 -0400166 bool result;
Brian Salomona56a7462020-02-07 14:17:25 -0500167 result = gpu->transferPixelsTo(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, colorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400168 allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
Greg Daniele877dce2019-07-11 10:52:43 -0400169 REPORTER_ASSERT(reporter, result);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400170
Brian Salomona56a7462020-02-07 14:17:25 -0500171 size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTexDims.fWidth;
172 std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTexDims.fHeight]());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400173
Brian Salomon42be09d2019-07-26 12:12:26 -0400174 float compareTolerances[4] = {};
175 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400176 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400177 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
178 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400179 return;
Greg Daniele877dce2019-07-11 10:52:43 -0400180 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400181
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400182 auto error = std::function<ComparePixmapsErrorReporter>(
183 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400184 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400185 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
186 x, y, GrColorTypeToStr(colorType),
187 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400188 });
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400189 GrImageInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(),
Brian Salomon42be09d2019-07-26 12:12:26 -0400190 tex->height());
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400191 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height());
Brian Salomon28a8f282019-10-24 20:07:39 -0400192 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
193 compareTolerances, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400194
Greg Daniele877dce2019-07-11 10:52:43 -0400195 //////////////////////////
196 // transfer partial data
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400197
198 // We're relying on this cap to write partial texture data
199 if (!caps->writePixelsRowBytesSupport()) {
Greg Daniele877dce2019-07-11 10:52:43 -0400200 return;
201 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400202 // We keep a 1 to 1 correspondence between pixels in the buffer and the entire texture. We
203 // update the contents of a sub-rect of the buffer and push that rect to the texture. We start
204 // with a left sub-rect inset of 2 but may adjust that so we can fulfill the transfer buffer
205 // offset alignment requirement.
206 int left = 2;
207 const int top = 10;
208 const int width = 10;
209 const int height = 2;
210 size_t offset = top * srcRowBytes + left * GrColorTypeBytesPerPixel(allowedSrc.fColorType);
211 while (offset % allowedSrc.fOffsetAlignmentForTransferBuffer) {
212 offset += GrColorTypeBytesPerPixel(allowedSrc.fColorType);
213 ++left;
214 // We're assuming that the required alignment is 1 or a small multiple of the bpp, which
215 // it is currently for all color types across all backends.
216 SkASSERT(left + width <= tex->width());
217 }
Brian Salomonc320b152018-02-20 14:05:36 -0500218
Greg Daniele877dce2019-07-11 10:52:43 -0400219 // change color of subrectangle
Brian Salomon42be09d2019-07-26 12:12:26 -0400220 fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType,
221 srcData.get());
Greg Daniele877dce2019-07-11 10:52:43 -0400222 data = buffer->map();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400223 memcpy(data, srcData.get(), size);
Greg Daniele877dce2019-07-11 10:52:43 -0400224 buffer->unmap();
Brian Salomonc320b152018-02-20 14:05:36 -0500225
Brian Salomonf77c1462019-08-01 15:19:29 -0400226 result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
227 allowedSrc.fColorType, buffer.get(), offset, srcRowBytes);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400228 if (!result) {
Brian Salomonf77c1462019-08-01 15:19:29 -0400229 gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400230 buffer.get(), offset, srcRowBytes);
231 ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
232 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400233 return;
Jim Van Verth52fb02e2017-06-27 10:36:56 -0400234 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400235
236 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
237 if (!result) {
238 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
239 static_cast<int>(colorType));
240 return;
241 }
Brian Salomon28a8f282019-10-24 20:07:39 -0400242 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
243 compareTolerances, error);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400244}
245
Brian Salomon42cbedd2019-04-09 15:00:05 -0400246void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400247 GrColorType colorType, GrRenderable renderable) {
Brian Salomon42cbedd2019-04-09 15:00:05 -0400248 auto context = ctxInfo.grContext();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400249 auto caps = context->priv().caps();
250 if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400251 return;
252 }
Jim Van Verth686046b2019-03-18 15:39:22 -0400253
Brian Salomone05ba5a2019-04-08 11:59:07 -0400254 auto resourceProvider = context->priv().resourceProvider();
255 GrGpu* gpu = context->priv().getGpu();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400256
Brian Salomona56a7462020-02-07 14:17:25 -0500257 static constexpr SkISize kTexDims = {16, 16};
Brian Salomone05ba5a2019-04-08 11:59:07 -0400258
259 // We'll do a full texture read into the buffer followed by a partial read. These values
260 // describe the partial read subrect.
261 const int kPartialLeft = 2;
262 const int kPartialTop = 10;
263 const int kPartialWidth = 10;
264 const int kPartialHeight = 2;
265
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400266 // create texture
Brian Salomon4eb38b72019-08-05 12:58:39 -0400267 auto format = context->priv().caps()->getDefaultBackendFormat(colorType, renderable);
268 if (!format.isValid()) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400269 return;
270 }
271
272 size_t textureDataBpp = GrColorTypeBytesPerPixel(colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500273 size_t textureDataRowBytes = kTexDims.fWidth * textureDataBpp;
274 std::unique_ptr<char[]> textureData(new char[kTexDims.fHeight * textureDataRowBytes]);
275 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, kTexDims.fHeight, colorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400276 textureData.get());
277 GrMipLevel data;
278 data.fPixels = textureData.get();
279 data.fRowBytes = textureDataRowBytes;
Brian Salomona56a7462020-02-07 14:17:25 -0500280 sk_sp<GrTexture> tex =
281 resourceProvider->createTexture(kTexDims, format, colorType, renderable, 1,
282 SkBudgeted::kNo, GrProtected::kNo, &data, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400283 if (!tex) {
284 return;
285 }
286
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400287 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
288 caps->surfaceSupportsReadPixels(tex.get())) {
289 return;
290 }
291 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
292 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
293 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400294 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400295 return;
296 }
297
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400298 // Create the transfer buffer.
299 auto allowedRead =
Greg Daniel00fb7242019-07-18 14:28:01 -0400300 caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500301 GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400302
303 size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500304 size_t fullBufferRowBytes = kTexDims.fWidth * bpp;
Brian Salomon26de56e2019-04-10 12:14:26 -0400305 size_t partialBufferRowBytes = kPartialWidth * bpp;
Greg Danielba88ab62019-07-26 09:14:01 -0400306 size_t offsetAlignment = allowedRead.fOffsetAlignmentForTransferBuffer;
Brian Salomon26de56e2019-04-10 12:14:26 -0400307 SkASSERT(offsetAlignment);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400308
Brian Salomona56a7462020-02-07 14:17:25 -0500309 size_t bufferSize = fullBufferRowBytes * kTexDims.fHeight;
Brian Salomone05ba5a2019-04-08 11:59:07 -0400310 // Arbitrary starting offset for the partial read.
Brian Salomone9943802020-01-03 13:07:07 -0500311 size_t partialReadOffset = GrAlignTo(11, offsetAlignment);
Brian Osman788b9162020-02-07 10:36:46 -0500312 bufferSize = std::max(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400313
314 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(
315 bufferSize, GrGpuBufferType::kXferGpuToCpu, kDynamic_GrAccessPattern));
316 REPORTER_ASSERT(reporter, buffer);
317 if (!buffer) {
318 return;
319 }
320
321 int expectedTransferCnt = 0;
322 gpu->stats()->reset();
Greg Daniele877dce2019-07-11 10:52:43 -0400323
324 //////////////////////////
325 // transfer full data
Brian Salomona56a7462020-02-07 14:17:25 -0500326 bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight,
327 colorType, allowedRead.fColorType, buffer.get(), 0);
Greg Daniele877dce2019-07-11 10:52:43 -0400328 if (!result) {
329 ERRORF(reporter, "transferPixelsFrom failed.");
330 return;
331 }
332 ++expectedTransferCnt;
333
Greg Daniele877dce2019-07-11 10:52:43 -0400334 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000335 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400336 }
337
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400338 // Copy the transfer buffer contents to a temporary so we can manipulate it.
339 const auto* map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400340 REPORTER_ASSERT(reporter, map);
341 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400342 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400343 return;
344 }
Brian Salomona56a7462020-02-07 14:17:25 -0500345 std::unique_ptr<char[]> transferData(new char[kTexDims.fHeight * fullBufferRowBytes]);
346 memcpy(transferData.get(), map, fullBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400347 buffer->unmap();
348
Brian Salomona56a7462020-02-07 14:17:25 -0500349 GrImageInfo transferInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400350
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400351 float tol[4];
352 determine_tolerances(allowedRead.fColorType, colorType, tol);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400353 auto error = std::function<ComparePixmapsErrorReporter>(
354 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400355 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400356 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
357 x, y, GrColorTypeToStr(colorType),
358 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400359 });
Brian Salomona56a7462020-02-07 14:17:25 -0500360 GrImageInfo textureDataInfo(colorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon28a8f282019-10-24 20:07:39 -0400361 ComparePixels(textureDataInfo, textureData.get(), textureDataRowBytes, transferInfo,
362 transferData.get(), fullBufferRowBytes, tol, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400363
Greg Daniele877dce2019-07-11 10:52:43 -0400364 ///////////////////////
365 // Now test a partial read at an offset into the buffer.
366 result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
Brian Salomonf77c1462019-08-01 15:19:29 -0400367 kPartialHeight, colorType, allowedRead.fColorType,
368 buffer.get(), partialReadOffset);
Greg Daniele877dce2019-07-11 10:52:43 -0400369 if (!result) {
370 ERRORF(reporter, "transferPixelsFrom failed.");
371 return;
372 }
373 ++expectedTransferCnt;
374
375 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000376 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400377 }
378
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400379 map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400380 REPORTER_ASSERT(reporter, map);
381 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400382 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400383 return;
384 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400385 const char* bufferStart = reinterpret_cast<const char*>(map) + partialReadOffset;
Brian Salomona56a7462020-02-07 14:17:25 -0500386 memcpy(transferData.get(), bufferStart, partialBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400387 buffer->unmap();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400388
389 transferInfo = transferInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400390 const char* textureDataStart =
391 textureData.get() + textureDataRowBytes * kPartialTop + textureDataBpp * kPartialLeft;
392 textureDataInfo = textureDataInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon28a8f282019-10-24 20:07:39 -0400393 ComparePixels(textureDataInfo, textureDataStart, textureDataRowBytes, transferInfo,
394 transferData.get(), partialBufferRowBytes, tol, error);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400395#if GR_GPU_STATS
396 REPORTER_ASSERT(reporter, gpu->stats()->transfersFromSurface() == expectedTransferCnt);
397#else
398 (void)expectedTransferCnt;
399#endif
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400400}
Jim Van Verth686046b2019-03-18 15:39:22 -0400401
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500402DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsToTextureTest, reporter, ctxInfo) {
403 if (!ctxInfo.grContext()->priv().caps()->transferFromBufferToTextureSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400404 return;
405 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400406 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400407 for (auto colorType : {
408 GrColorType::kAlpha_8,
409 GrColorType::kBGR_565,
410 GrColorType::kABGR_4444,
411 GrColorType::kRGBA_8888,
412 GrColorType::kRGBA_8888_SRGB,
413 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
414 GrColorType::kRG_88,
415 GrColorType::kBGRA_8888,
416 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400417 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500418 GrColorType::kGray_8,
Brian Salomon42be09d2019-07-26 12:12:26 -0400419 GrColorType::kAlpha_F16,
420 GrColorType::kRGBA_F16,
421 GrColorType::kRGBA_F16_Clamped,
422 GrColorType::kRGBA_F32,
Robert Phillips429f0d32019-09-11 17:03:28 -0400423 GrColorType::kAlpha_16,
Brian Salomon42be09d2019-07-26 12:12:26 -0400424 GrColorType::kRG_1616,
425 GrColorType::kRGBA_16161616,
426 GrColorType::kRG_F16,
427 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400428 basic_transfer_to_test(reporter, ctxInfo.grContext(), colorType, renderable);
429 }
430 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400431}
432
Brian Salomona585fe92019-04-09 14:57:00 -0400433// TODO(bsalomon): Metal
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500434DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsFromTextureTest, reporter, ctxInfo) {
435 if (!ctxInfo.grContext()->priv().caps()->transferFromSurfaceToBufferSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400436 return;
437 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400438 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400439 for (auto colorType : {
Brian Salomonb3bd8642019-11-04 16:59:29 -0500440 GrColorType::kAlpha_8,
441 GrColorType::kAlpha_16,
442 GrColorType::kBGR_565,
443 GrColorType::kABGR_4444,
444 GrColorType::kRGBA_8888,
445 GrColorType::kRGBA_8888_SRGB,
446 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
447 GrColorType::kRG_88,
448 GrColorType::kBGRA_8888,
449 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400450 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500451 GrColorType::kGray_8,
452 GrColorType::kAlpha_F16,
453 GrColorType::kRGBA_F16,
454 GrColorType::kRGBA_F16_Clamped,
455 GrColorType::kRGBA_F32,
456 GrColorType::kRG_1616,
457 GrColorType::kRGBA_16161616,
458 GrColorType::kRG_F16,
459 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400460 basic_transfer_from_test(reporter, ctxInfo, colorType, renderable);
461 }
462 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400463}