blob: 4c369584e72ca5bcc1c4d56e59486d6ac9cf06be [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"
Robert Phillips6d344c32020-07-06 10:56:46 -040013#include "include/gpu/GrDirectContext.h"
Adlai Hollera0693042020-10-14 11:23:11 -040014#include "src/gpu/GrDirectContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#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"
Greg Daniel456f9b52020-03-05 19:14:18 +000019#include "src/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/SkGr.h"
21#include "tests/Test.h"
Mike Klein52337de2019-07-25 09:00:52 -050022#include "tests/TestUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "tools/gpu/GrContextFactory.h"
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040024
25using sk_gpu_test::GrContextFactory;
26
27void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
Brian Salomon6aecd5e2019-07-16 09:47:32 -040028 GrColorType dstType, char* dst) {
29 size_t dstBpp = GrColorTypeBytesPerPixel(dstType);
30 auto dstLocation = [dst, dstBpp, bufferWidth](int x, int y) {
31 return dst + y * dstBpp * bufferWidth + x * dstBpp;
32 };
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040033 // build red-green gradient
34 for (int j = top; j < top + height; ++j) {
35 for (int i = left; i < left + width; ++i) {
Brian Salomon42be09d2019-07-26 12:12:26 -040036 auto r = (unsigned int)(256.f*((i - left) / (float)width));
37 auto g = (unsigned int)(256.f*((j - top) / (float)height));
38 r -= (r >> 8);
39 g -= (g >> 8);
40 // set b and a channels to be inverse of r and g just to have interesting values to
41 // test.
42 uint32_t srcPixel = GrColorPackRGBA(r, g, 0xff - r, 0xff - g);
Brian Salomonf2ebdd92019-09-30 12:15:30 -040043 GrImageInfo srcInfo(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, 1, 1);
44 GrImageInfo dstInfo(dstType, kUnpremul_SkAlphaType, nullptr, 1, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -040045 GrConvertPixels(dstInfo, dstLocation(i, j), dstBpp, srcInfo, &srcPixel, 4);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040046 }
47 }
48}
49
Brian Salomon6f6d2de2019-07-26 14:10:33 -040050void determine_tolerances(GrColorType a, GrColorType b, float tolerances[4]) {
Greg Daniel7bf37e02019-07-29 10:09:21 -040051 std::fill_n(tolerances, 4, 0);
52
Brian Salomon6f6d2de2019-07-26 14:10:33 -040053 auto descA = GrGetColorTypeDesc(a);
54 auto descB = GrGetColorTypeDesc(b);
55 // For each channel x set the tolerance to 1 / (2^min(bits_in_a, bits_in_b) - 1) unless
56 // one color type is missing the channel. In that case leave it at 0. If the other color
57 // has the channel then it better be exactly 1 for alpha or 0 for rgb.
58 for (int i = 0; i < 4; ++i) {
59 if (descA[i] != descB[i]) {
60 auto m = std::min(descA[i], descB[i]);
61 if (m) {
62 tolerances[i] = 1.f / (m - 1);
63 }
64 }
65 }
66}
67
Brian Salomonf77c1462019-08-01 15:19:29 -040068bool read_pixels_from_texture(GrTexture* texture, GrColorType colorType, char* dst,
Brian Salomon42be09d2019-07-26 12:12:26 -040069 float tolerances[4]) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040070 auto* context = texture->getContext();
71 auto* gpu = context->priv().getGpu();
72 auto* caps = context->priv().caps();
73
74 int w = texture->width();
75 int h = texture->height();
Brian Salomonf77c1462019-08-01 15:19:29 -040076 size_t rowBytes = GrColorTypeBytesPerPixel(colorType) * w;
Greg Danielc6dc5cf2019-07-17 16:02:00 -040077
Brian Salomonf77c1462019-08-01 15:19:29 -040078 GrCaps::SupportedRead supportedRead =
Greg Danield51fa2f2020-01-22 16:53:38 -050079 caps->supportedReadPixelsColorType(colorType, texture->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -040080 std::fill_n(tolerances, 4, 0);
Brian Salomonf77c1462019-08-01 15:19:29 -040081 if (supportedRead.fColorType != colorType) {
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]);
Brian Salomonf77c1462019-08-01 15:19:29 -040084 if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType,
85 tmpPixels.get(), tmpRowBytes)) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -040086 return false;
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040087 }
Brian Salomonf2ebdd92019-09-30 12:15:30 -040088 GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h);
89 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, w, h);
Brian Salomon6f6d2de2019-07-26 14:10:33 -040090 determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances);
Brian Salomon8f8354a2019-07-31 20:12:02 -040091 return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes,
92 false);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040093 }
Brian Salomonf77c1462019-08-01 15:19:29 -040094 return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -040095}
96
Robert Phillips58adb342020-07-23 09:41:57 -040097void basic_transfer_to_test(skiatest::Reporter* reporter,
98 GrDirectContext* dContext,
99 GrColorType colorType,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400100 GrRenderable renderable) {
Robert Phillips58adb342020-07-23 09:41:57 -0400101 if (GrCaps::kNone_MapFlags == dContext->priv().caps()->mapBufferFlags()) {
Brian Salomon7f56d3d2017-10-09 13:02:49 -0400102 return;
103 }
104
Robert Phillips58adb342020-07-23 09:41:57 -0400105 auto* caps = dContext->priv().caps();
Robert Phillips6be756b2018-01-16 15:07:54 -0500106
Robert Phillips0a15cc62019-07-30 12:49:10 -0400107 auto backendFormat = caps->getDefaultBackendFormat(colorType, renderable);
108 if (!backendFormat.isValid()) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400109 return;
Greg Daniel64329092019-07-16 16:16:21 -0400110 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400111
Robert Phillips58adb342020-07-23 09:41:57 -0400112 auto resourceProvider = dContext->priv().resourceProvider();
113 GrGpu* gpu = dContext->priv().getGpu();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400114
Brian Salomona56a7462020-02-07 14:17:25 -0500115 static constexpr SkISize kTexDims = {16, 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
Brian Salomona90382f2019-09-17 09:01:56 -0400119 sk_sp<GrTexture> tex =
Brian Salomona56a7462020-02-07 14:17:25 -0500120 resourceProvider->createTexture(kTexDims, backendFormat, renderable, 1,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400121 GrMipmapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
Greg Daniele877dce2019-07-11 10:52:43 -0400122 if (!tex) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400123 ERRORF(reporter, "Could not create texture");
Greg Daniele877dce2019-07-11 10:52:43 -0400124 return;
125 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400126
Brian Salomon42be09d2019-07-26 12:12:26 -0400127 // We validate the results using GrGpu::readPixels, so exit if this is not supported.
128 // TODO: Do this through GrSurfaceContext once it works for all color types or support
129 // kCopyToTexture2D here.
130 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
131 caps->surfaceSupportsReadPixels(tex.get())) {
132 return;
133 }
134 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
135 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
136 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400137 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400138 return;
139 }
140
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400141 // The caps tell us what color type we are allowed to upload and read back from this texture,
142 // either of which may differ from 'colorType'.
Brian Salomon42be09d2019-07-26 12:12:26 -0400143 GrCaps::SupportedWrite allowedSrc =
Brian Salomon01915c02019-08-02 09:57:21 -0400144 caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -0400145 size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth;
Brian Salomona56a7462020-02-07 14:17:25 -0500146 std::unique_ptr<char[]> srcData(new char[kTexDims.fHeight * srcRowBytes]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400147
Brian Salomona56a7462020-02-07 14:17:25 -0500148 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, srcBufferWidth,
149 allowedSrc.fColorType, srcData.get());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400150
151 // create and fill transfer buffer
152 size_t size = srcRowBytes * kBufferHeight;
153 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu,
154 kDynamic_GrAccessPattern));
155 if (!buffer) {
156 return;
157 }
158 void* data = buffer->map();
159 if (!buffer) {
160 ERRORF(reporter, "Could not map buffer");
161 return;
162 }
163 memcpy(data, srcData.get(), size);
164 buffer->unmap();
165
Greg Daniele877dce2019-07-11 10:52:43 -0400166 //////////////////////////
167 // transfer full data
Robert Phillips16d8ec62017-07-27 16:16:25 -0400168
Greg Daniele877dce2019-07-11 10:52:43 -0400169 bool result;
Brian Salomona56a7462020-02-07 14:17:25 -0500170 result = gpu->transferPixelsTo(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, colorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400171 allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
Greg Daniele877dce2019-07-11 10:52:43 -0400172 REPORTER_ASSERT(reporter, result);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400173
Brian Salomona56a7462020-02-07 14:17:25 -0500174 size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTexDims.fWidth;
175 std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTexDims.fHeight]());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400176
Brian Salomon42be09d2019-07-26 12:12:26 -0400177 float compareTolerances[4] = {};
178 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400179 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400180 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
181 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400182 return;
Greg Daniele877dce2019-07-11 10:52:43 -0400183 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400184
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400185 auto error = std::function<ComparePixmapsErrorReporter>(
186 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400187 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400188 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
189 x, y, GrColorTypeToStr(colorType),
190 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400191 });
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400192 GrImageInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(),
Brian Salomon42be09d2019-07-26 12:12:26 -0400193 tex->height());
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400194 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height());
Brian Salomon28a8f282019-10-24 20:07:39 -0400195 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
196 compareTolerances, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400197
Greg Daniele877dce2019-07-11 10:52:43 -0400198 //////////////////////////
199 // transfer partial data
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400200
201 // We're relying on this cap to write partial texture data
202 if (!caps->writePixelsRowBytesSupport()) {
Greg Daniele877dce2019-07-11 10:52:43 -0400203 return;
204 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400205 // We keep a 1 to 1 correspondence between pixels in the buffer and the entire texture. We
206 // update the contents of a sub-rect of the buffer and push that rect to the texture. We start
207 // with a left sub-rect inset of 2 but may adjust that so we can fulfill the transfer buffer
208 // offset alignment requirement.
209 int left = 2;
210 const int top = 10;
211 const int width = 10;
212 const int height = 2;
213 size_t offset = top * srcRowBytes + left * GrColorTypeBytesPerPixel(allowedSrc.fColorType);
214 while (offset % allowedSrc.fOffsetAlignmentForTransferBuffer) {
215 offset += GrColorTypeBytesPerPixel(allowedSrc.fColorType);
216 ++left;
217 // We're assuming that the required alignment is 1 or a small multiple of the bpp, which
218 // it is currently for all color types across all backends.
219 SkASSERT(left + width <= tex->width());
220 }
Brian Salomonc320b152018-02-20 14:05:36 -0500221
Greg Daniele877dce2019-07-11 10:52:43 -0400222 // change color of subrectangle
Brian Salomon42be09d2019-07-26 12:12:26 -0400223 fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType,
224 srcData.get());
Greg Daniele877dce2019-07-11 10:52:43 -0400225 data = buffer->map();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400226 memcpy(data, srcData.get(), size);
Greg Daniele877dce2019-07-11 10:52:43 -0400227 buffer->unmap();
Brian Salomonc320b152018-02-20 14:05:36 -0500228
Brian Salomonf77c1462019-08-01 15:19:29 -0400229 result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
230 allowedSrc.fColorType, buffer.get(), offset, srcRowBytes);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400231 if (!result) {
Brian Salomonf77c1462019-08-01 15:19:29 -0400232 gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400233 buffer.get(), offset, srcRowBytes);
234 ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
235 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400236 return;
Jim Van Verth52fb02e2017-06-27 10:36:56 -0400237 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400238
239 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
240 if (!result) {
241 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
242 static_cast<int>(colorType));
243 return;
244 }
Brian Salomon28a8f282019-10-24 20:07:39 -0400245 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
246 compareTolerances, error);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400247}
248
Brian Salomon42cbedd2019-04-09 15:00:05 -0400249void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400250 GrColorType colorType, GrRenderable renderable) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400251 auto context = ctxInfo.directContext();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400252 auto caps = context->priv().caps();
253 if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400254 return;
255 }
Jim Van Verth686046b2019-03-18 15:39:22 -0400256
Brian Salomone05ba5a2019-04-08 11:59:07 -0400257 auto resourceProvider = context->priv().resourceProvider();
258 GrGpu* gpu = context->priv().getGpu();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400259
Brian Salomona56a7462020-02-07 14:17:25 -0500260 static constexpr SkISize kTexDims = {16, 16};
Brian Salomone05ba5a2019-04-08 11:59:07 -0400261
262 // We'll do a full texture read into the buffer followed by a partial read. These values
263 // describe the partial read subrect.
264 const int kPartialLeft = 2;
265 const int kPartialTop = 10;
266 const int kPartialWidth = 10;
267 const int kPartialHeight = 2;
268
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400269 // create texture
Brian Salomon4eb38b72019-08-05 12:58:39 -0400270 auto format = context->priv().caps()->getDefaultBackendFormat(colorType, renderable);
271 if (!format.isValid()) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400272 return;
273 }
274
275 size_t textureDataBpp = GrColorTypeBytesPerPixel(colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500276 size_t textureDataRowBytes = kTexDims.fWidth * textureDataBpp;
277 std::unique_ptr<char[]> textureData(new char[kTexDims.fHeight * textureDataRowBytes]);
278 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, kTexDims.fHeight, colorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400279 textureData.get());
280 GrMipLevel data;
281 data.fPixels = textureData.get();
282 data.fRowBytes = textureDataRowBytes;
Brian Salomona56a7462020-02-07 14:17:25 -0500283 sk_sp<GrTexture> tex =
284 resourceProvider->createTexture(kTexDims, format, colorType, renderable, 1,
285 SkBudgeted::kNo, GrProtected::kNo, &data, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400286 if (!tex) {
287 return;
288 }
289
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400290 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
291 caps->surfaceSupportsReadPixels(tex.get())) {
292 return;
293 }
294 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
295 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
296 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400297 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400298 return;
299 }
300
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400301 // Create the transfer buffer.
302 auto allowedRead =
Greg Daniel00fb7242019-07-18 14:28:01 -0400303 caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500304 GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400305
306 size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500307 size_t fullBufferRowBytes = kTexDims.fWidth * bpp;
Brian Salomon26de56e2019-04-10 12:14:26 -0400308 size_t partialBufferRowBytes = kPartialWidth * bpp;
Greg Danielba88ab62019-07-26 09:14:01 -0400309 size_t offsetAlignment = allowedRead.fOffsetAlignmentForTransferBuffer;
Brian Salomon26de56e2019-04-10 12:14:26 -0400310 SkASSERT(offsetAlignment);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400311
Brian Salomona56a7462020-02-07 14:17:25 -0500312 size_t bufferSize = fullBufferRowBytes * kTexDims.fHeight;
Brian Salomone05ba5a2019-04-08 11:59:07 -0400313 // Arbitrary starting offset for the partial read.
Brian Salomone9943802020-01-03 13:07:07 -0500314 size_t partialReadOffset = GrAlignTo(11, offsetAlignment);
Brian Osman788b9162020-02-07 10:36:46 -0500315 bufferSize = std::max(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400316
317 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(
318 bufferSize, GrGpuBufferType::kXferGpuToCpu, kDynamic_GrAccessPattern));
319 REPORTER_ASSERT(reporter, buffer);
320 if (!buffer) {
321 return;
322 }
323
324 int expectedTransferCnt = 0;
325 gpu->stats()->reset();
Greg Daniele877dce2019-07-11 10:52:43 -0400326
327 //////////////////////////
328 // transfer full data
Brian Salomona56a7462020-02-07 14:17:25 -0500329 bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight,
330 colorType, allowedRead.fColorType, buffer.get(), 0);
Greg Daniele877dce2019-07-11 10:52:43 -0400331 if (!result) {
332 ERRORF(reporter, "transferPixelsFrom failed.");
333 return;
334 }
335 ++expectedTransferCnt;
336
Greg Daniele877dce2019-07-11 10:52:43 -0400337 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000338 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400339 }
340
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400341 // Copy the transfer buffer contents to a temporary so we can manipulate it.
342 const auto* map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400343 REPORTER_ASSERT(reporter, map);
344 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400345 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400346 return;
347 }
Brian Salomona56a7462020-02-07 14:17:25 -0500348 std::unique_ptr<char[]> transferData(new char[kTexDims.fHeight * fullBufferRowBytes]);
349 memcpy(transferData.get(), map, fullBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400350 buffer->unmap();
351
Brian Salomona56a7462020-02-07 14:17:25 -0500352 GrImageInfo transferInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400353
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400354 float tol[4];
355 determine_tolerances(allowedRead.fColorType, colorType, tol);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400356 auto error = std::function<ComparePixmapsErrorReporter>(
357 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400358 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400359 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
360 x, y, GrColorTypeToStr(colorType),
361 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400362 });
Brian Salomona56a7462020-02-07 14:17:25 -0500363 GrImageInfo textureDataInfo(colorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon28a8f282019-10-24 20:07:39 -0400364 ComparePixels(textureDataInfo, textureData.get(), textureDataRowBytes, transferInfo,
365 transferData.get(), fullBufferRowBytes, tol, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400366
Greg Daniele877dce2019-07-11 10:52:43 -0400367 ///////////////////////
368 // Now test a partial read at an offset into the buffer.
369 result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
Brian Salomonf77c1462019-08-01 15:19:29 -0400370 kPartialHeight, colorType, allowedRead.fColorType,
371 buffer.get(), partialReadOffset);
Greg Daniele877dce2019-07-11 10:52:43 -0400372 if (!result) {
373 ERRORF(reporter, "transferPixelsFrom failed.");
374 return;
375 }
376 ++expectedTransferCnt;
377
378 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000379 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400380 }
381
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400382 map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400383 REPORTER_ASSERT(reporter, map);
384 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400385 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400386 return;
387 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400388 const char* bufferStart = reinterpret_cast<const char*>(map) + partialReadOffset;
Brian Salomona56a7462020-02-07 14:17:25 -0500389 memcpy(transferData.get(), bufferStart, partialBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400390 buffer->unmap();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400391
392 transferInfo = transferInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400393 const char* textureDataStart =
394 textureData.get() + textureDataRowBytes * kPartialTop + textureDataBpp * kPartialLeft;
395 textureDataInfo = textureDataInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon28a8f282019-10-24 20:07:39 -0400396 ComparePixels(textureDataInfo, textureDataStart, textureDataRowBytes, transferInfo,
397 transferData.get(), partialBufferRowBytes, tol, error);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400398#if GR_GPU_STATS
399 REPORTER_ASSERT(reporter, gpu->stats()->transfersFromSurface() == expectedTransferCnt);
400#else
401 (void)expectedTransferCnt;
402#endif
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400403}
Jim Van Verth686046b2019-03-18 15:39:22 -0400404
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500405DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsToTextureTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400406 if (!ctxInfo.directContext()->priv().caps()->transferFromBufferToTextureSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400407 return;
408 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400409 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400410 for (auto colorType : {
411 GrColorType::kAlpha_8,
412 GrColorType::kBGR_565,
413 GrColorType::kABGR_4444,
414 GrColorType::kRGBA_8888,
415 GrColorType::kRGBA_8888_SRGB,
416 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
417 GrColorType::kRG_88,
418 GrColorType::kBGRA_8888,
419 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400420 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500421 GrColorType::kGray_8,
Brian Salomon42be09d2019-07-26 12:12:26 -0400422 GrColorType::kAlpha_F16,
423 GrColorType::kRGBA_F16,
424 GrColorType::kRGBA_F16_Clamped,
425 GrColorType::kRGBA_F32,
Robert Phillips429f0d32019-09-11 17:03:28 -0400426 GrColorType::kAlpha_16,
Brian Salomon42be09d2019-07-26 12:12:26 -0400427 GrColorType::kRG_1616,
428 GrColorType::kRGBA_16161616,
429 GrColorType::kRG_F16,
430 }) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400431 basic_transfer_to_test(reporter, ctxInfo.directContext(), colorType, renderable);
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400432 }
433 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400434}
435
Brian Salomona585fe92019-04-09 14:57:00 -0400436// TODO(bsalomon): Metal
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500437DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsFromTextureTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400438 if (!ctxInfo.directContext()->priv().caps()->transferFromSurfaceToBufferSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400439 return;
440 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400441 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400442 for (auto colorType : {
Brian Salomonb3bd8642019-11-04 16:59:29 -0500443 GrColorType::kAlpha_8,
444 GrColorType::kAlpha_16,
445 GrColorType::kBGR_565,
446 GrColorType::kABGR_4444,
447 GrColorType::kRGBA_8888,
448 GrColorType::kRGBA_8888_SRGB,
449 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
450 GrColorType::kRG_88,
451 GrColorType::kBGRA_8888,
452 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400453 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500454 GrColorType::kGray_8,
455 GrColorType::kAlpha_F16,
456 GrColorType::kRGBA_F16,
457 GrColorType::kRGBA_F16_Clamped,
458 GrColorType::kRGBA_F32,
459 GrColorType::kRG_1616,
460 GrColorType::kRGBA_16161616,
461 GrColorType::kRG_F16,
462 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400463 basic_transfer_from_test(reporter, ctxInfo, colorType, renderable);
464 }
465 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400466}