blob: 96857431865504df4907c214abdc391f327d7130 [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"
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"
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
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
Brian Salomona56a7462020-02-07 14:17:25 -0500113 static constexpr SkISize kTexDims = {16, 16};
Brian Salomonf27e51f2019-07-25 13:20:58 -0400114 int srcBufferWidth = caps->writePixelsRowBytesSupport() ? 20 : 16;
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400115 const int kBufferHeight = 16;
116
Brian Salomona90382f2019-09-17 09:01:56 -0400117 sk_sp<GrTexture> tex =
Brian Salomona56a7462020-02-07 14:17:25 -0500118 resourceProvider->createTexture(kTexDims, backendFormat, renderable, 1,
119 GrMipMapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
Greg Daniele877dce2019-07-11 10:52:43 -0400120 if (!tex) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400121 ERRORF(reporter, "Could not create texture");
Greg Daniele877dce2019-07-11 10:52:43 -0400122 return;
123 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400124
Brian Salomon42be09d2019-07-26 12:12:26 -0400125 // We validate the results using GrGpu::readPixels, so exit if this is not supported.
126 // TODO: Do this through GrSurfaceContext once it works for all color types or support
127 // kCopyToTexture2D here.
128 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
129 caps->surfaceSupportsReadPixels(tex.get())) {
130 return;
131 }
132 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
133 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
134 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400135 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400136 return;
137 }
138
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400139 // The caps tell us what color type we are allowed to upload and read back from this texture,
140 // either of which may differ from 'colorType'.
Brian Salomon42be09d2019-07-26 12:12:26 -0400141 GrCaps::SupportedWrite allowedSrc =
Brian Salomon01915c02019-08-02 09:57:21 -0400142 caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomon42be09d2019-07-26 12:12:26 -0400143 size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth;
Brian Salomona56a7462020-02-07 14:17:25 -0500144 std::unique_ptr<char[]> srcData(new char[kTexDims.fHeight * srcRowBytes]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400145
Brian Salomona56a7462020-02-07 14:17:25 -0500146 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, srcBufferWidth,
147 allowedSrc.fColorType, srcData.get());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400148
149 // create and fill transfer buffer
150 size_t size = srcRowBytes * kBufferHeight;
151 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(size, GrGpuBufferType::kXferCpuToGpu,
152 kDynamic_GrAccessPattern));
153 if (!buffer) {
154 return;
155 }
156 void* data = buffer->map();
157 if (!buffer) {
158 ERRORF(reporter, "Could not map buffer");
159 return;
160 }
161 memcpy(data, srcData.get(), size);
162 buffer->unmap();
163
Greg Daniele877dce2019-07-11 10:52:43 -0400164 //////////////////////////
165 // transfer full data
Robert Phillips16d8ec62017-07-27 16:16:25 -0400166
Greg Daniele877dce2019-07-11 10:52:43 -0400167 bool result;
Brian Salomona56a7462020-02-07 14:17:25 -0500168 result = gpu->transferPixelsTo(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, colorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400169 allowedSrc.fColorType, buffer.get(), 0, srcRowBytes);
Greg Daniele877dce2019-07-11 10:52:43 -0400170 REPORTER_ASSERT(reporter, result);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400171
Brian Salomona56a7462020-02-07 14:17:25 -0500172 size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTexDims.fWidth;
173 std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTexDims.fHeight]());
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400174
Brian Salomon42be09d2019-07-26 12:12:26 -0400175 float compareTolerances[4] = {};
176 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400177 if (!result) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400178 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
179 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400180 return;
Greg Daniele877dce2019-07-11 10:52:43 -0400181 }
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400182
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400183 auto error = std::function<ComparePixmapsErrorReporter>(
184 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400185 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400186 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
187 x, y, GrColorTypeToStr(colorType),
188 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400189 });
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400190 GrImageInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(),
Brian Salomon42be09d2019-07-26 12:12:26 -0400191 tex->height());
Brian Salomonf2ebdd92019-09-30 12:15:30 -0400192 GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height());
Brian Salomon28a8f282019-10-24 20:07:39 -0400193 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
194 compareTolerances, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400195
Greg Daniele877dce2019-07-11 10:52:43 -0400196 //////////////////////////
197 // transfer partial data
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400198
199 // We're relying on this cap to write partial texture data
200 if (!caps->writePixelsRowBytesSupport()) {
Greg Daniele877dce2019-07-11 10:52:43 -0400201 return;
202 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400203 // We keep a 1 to 1 correspondence between pixels in the buffer and the entire texture. We
204 // update the contents of a sub-rect of the buffer and push that rect to the texture. We start
205 // with a left sub-rect inset of 2 but may adjust that so we can fulfill the transfer buffer
206 // offset alignment requirement.
207 int left = 2;
208 const int top = 10;
209 const int width = 10;
210 const int height = 2;
211 size_t offset = top * srcRowBytes + left * GrColorTypeBytesPerPixel(allowedSrc.fColorType);
212 while (offset % allowedSrc.fOffsetAlignmentForTransferBuffer) {
213 offset += GrColorTypeBytesPerPixel(allowedSrc.fColorType);
214 ++left;
215 // We're assuming that the required alignment is 1 or a small multiple of the bpp, which
216 // it is currently for all color types across all backends.
217 SkASSERT(left + width <= tex->width());
218 }
Brian Salomonc320b152018-02-20 14:05:36 -0500219
Greg Daniele877dce2019-07-11 10:52:43 -0400220 // change color of subrectangle
Brian Salomon42be09d2019-07-26 12:12:26 -0400221 fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType,
222 srcData.get());
Greg Daniele877dce2019-07-11 10:52:43 -0400223 data = buffer->map();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400224 memcpy(data, srcData.get(), size);
Greg Daniele877dce2019-07-11 10:52:43 -0400225 buffer->unmap();
Brian Salomonc320b152018-02-20 14:05:36 -0500226
Brian Salomonf77c1462019-08-01 15:19:29 -0400227 result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType,
228 allowedSrc.fColorType, buffer.get(), offset, srcRowBytes);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400229 if (!result) {
Brian Salomonf77c1462019-08-01 15:19:29 -0400230 gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType,
Brian Salomon42be09d2019-07-26 12:12:26 -0400231 buffer.get(), offset, srcRowBytes);
232 ERRORF(reporter, "Could not transfer pixels to texture, color type: %d",
233 static_cast<int>(colorType));
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400234 return;
Jim Van Verth52fb02e2017-06-27 10:36:56 -0400235 }
Brian Salomon42be09d2019-07-26 12:12:26 -0400236
237 result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances);
238 if (!result) {
239 ERRORF(reporter, "Could not read pixels from texture, color type: %d",
240 static_cast<int>(colorType));
241 return;
242 }
Brian Salomon28a8f282019-10-24 20:07:39 -0400243 ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes,
244 compareTolerances, error);
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400245}
246
Brian Salomon42cbedd2019-04-09 15:00:05 -0400247void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo,
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400248 GrColorType colorType, GrRenderable renderable) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400249 auto context = ctxInfo.directContext();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400250 auto caps = context->priv().caps();
251 if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400252 return;
253 }
Jim Van Verth686046b2019-03-18 15:39:22 -0400254
Brian Salomone05ba5a2019-04-08 11:59:07 -0400255 auto resourceProvider = context->priv().resourceProvider();
256 GrGpu* gpu = context->priv().getGpu();
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400257
Brian Salomona56a7462020-02-07 14:17:25 -0500258 static constexpr SkISize kTexDims = {16, 16};
Brian Salomone05ba5a2019-04-08 11:59:07 -0400259
260 // We'll do a full texture read into the buffer followed by a partial read. These values
261 // describe the partial read subrect.
262 const int kPartialLeft = 2;
263 const int kPartialTop = 10;
264 const int kPartialWidth = 10;
265 const int kPartialHeight = 2;
266
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400267 // create texture
Brian Salomon4eb38b72019-08-05 12:58:39 -0400268 auto format = context->priv().caps()->getDefaultBackendFormat(colorType, renderable);
269 if (!format.isValid()) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400270 return;
271 }
272
273 size_t textureDataBpp = GrColorTypeBytesPerPixel(colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500274 size_t textureDataRowBytes = kTexDims.fWidth * textureDataBpp;
275 std::unique_ptr<char[]> textureData(new char[kTexDims.fHeight * textureDataRowBytes]);
276 fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, kTexDims.fHeight, colorType,
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400277 textureData.get());
278 GrMipLevel data;
279 data.fPixels = textureData.get();
280 data.fRowBytes = textureDataRowBytes;
Brian Salomona56a7462020-02-07 14:17:25 -0500281 sk_sp<GrTexture> tex =
282 resourceProvider->createTexture(kTexDims, format, colorType, renderable, 1,
283 SkBudgeted::kNo, GrProtected::kNo, &data, 1);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400284 if (!tex) {
285 return;
286 }
287
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400288 if (GrCaps::SurfaceReadPixelsSupport::kSupported !=
289 caps->surfaceSupportsReadPixels(tex.get())) {
290 return;
291 }
292 // GL requires a texture to be framebuffer bindable to call glReadPixels. However, we have not
293 // incorporated that test into surfaceSupportsReadPixels(). TODO: Remove this once we handle
294 // drawing to a bindable format.
Greg Daniel900583a2019-08-06 12:05:31 -0400295 if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400296 return;
297 }
298
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400299 // Create the transfer buffer.
300 auto allowedRead =
Greg Daniel00fb7242019-07-18 14:28:01 -0400301 caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500302 GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400303
304 size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType);
Brian Salomona56a7462020-02-07 14:17:25 -0500305 size_t fullBufferRowBytes = kTexDims.fWidth * bpp;
Brian Salomon26de56e2019-04-10 12:14:26 -0400306 size_t partialBufferRowBytes = kPartialWidth * bpp;
Greg Danielba88ab62019-07-26 09:14:01 -0400307 size_t offsetAlignment = allowedRead.fOffsetAlignmentForTransferBuffer;
Brian Salomon26de56e2019-04-10 12:14:26 -0400308 SkASSERT(offsetAlignment);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400309
Brian Salomona56a7462020-02-07 14:17:25 -0500310 size_t bufferSize = fullBufferRowBytes * kTexDims.fHeight;
Brian Salomone05ba5a2019-04-08 11:59:07 -0400311 // Arbitrary starting offset for the partial read.
Brian Salomone9943802020-01-03 13:07:07 -0500312 size_t partialReadOffset = GrAlignTo(11, offsetAlignment);
Brian Osman788b9162020-02-07 10:36:46 -0500313 bufferSize = std::max(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400314
315 sk_sp<GrGpuBuffer> buffer(resourceProvider->createBuffer(
316 bufferSize, GrGpuBufferType::kXferGpuToCpu, kDynamic_GrAccessPattern));
317 REPORTER_ASSERT(reporter, buffer);
318 if (!buffer) {
319 return;
320 }
321
322 int expectedTransferCnt = 0;
323 gpu->stats()->reset();
Greg Daniele877dce2019-07-11 10:52:43 -0400324
325 //////////////////////////
326 // transfer full data
Brian Salomona56a7462020-02-07 14:17:25 -0500327 bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight,
328 colorType, allowedRead.fColorType, buffer.get(), 0);
Greg Daniele877dce2019-07-11 10:52:43 -0400329 if (!result) {
330 ERRORF(reporter, "transferPixelsFrom failed.");
331 return;
332 }
333 ++expectedTransferCnt;
334
Greg Daniele877dce2019-07-11 10:52:43 -0400335 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000336 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400337 }
338
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400339 // Copy the transfer buffer contents to a temporary so we can manipulate it.
340 const auto* map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400341 REPORTER_ASSERT(reporter, map);
342 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400343 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400344 return;
345 }
Brian Salomona56a7462020-02-07 14:17:25 -0500346 std::unique_ptr<char[]> transferData(new char[kTexDims.fHeight * fullBufferRowBytes]);
347 memcpy(transferData.get(), map, fullBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400348 buffer->unmap();
349
Brian Salomona56a7462020-02-07 14:17:25 -0500350 GrImageInfo transferInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400351
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400352 float tol[4];
353 determine_tolerances(allowedRead.fColorType, colorType, tol);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400354 auto error = std::function<ComparePixmapsErrorReporter>(
355 [reporter, colorType](int x, int y, const float diffs[4]) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400356 ERRORF(reporter,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400357 "Error at (%d %d) in transfer, color type: %s, diffs: (%f, %f, %f, %f)",
358 x, y, GrColorTypeToStr(colorType),
359 diffs[0], diffs[1], diffs[2], diffs[3]);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400360 });
Brian Salomona56a7462020-02-07 14:17:25 -0500361 GrImageInfo textureDataInfo(colorType, kUnpremul_SkAlphaType, nullptr, kTexDims);
Brian Salomon28a8f282019-10-24 20:07:39 -0400362 ComparePixels(textureDataInfo, textureData.get(), textureDataRowBytes, transferInfo,
363 transferData.get(), fullBufferRowBytes, tol, error);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400364
Greg Daniele877dce2019-07-11 10:52:43 -0400365 ///////////////////////
366 // Now test a partial read at an offset into the buffer.
367 result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth,
Brian Salomonf77c1462019-08-01 15:19:29 -0400368 kPartialHeight, colorType, allowedRead.fColorType,
369 buffer.get(), partialReadOffset);
Greg Daniele877dce2019-07-11 10:52:43 -0400370 if (!result) {
371 ERRORF(reporter, "transferPixelsFrom failed.");
372 return;
373 }
374 ++expectedTransferCnt;
375
376 if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) {
Greg Danielfe159622020-04-10 17:43:51 +0000377 gpu->submitToGpu(true);
Greg Daniele877dce2019-07-11 10:52:43 -0400378 }
379
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400380 map = reinterpret_cast<const char*>(buffer->map());
Greg Daniele877dce2019-07-11 10:52:43 -0400381 REPORTER_ASSERT(reporter, map);
382 if (!map) {
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400383 ERRORF(reporter, "Failed to map transfer buffer.");
Greg Daniele877dce2019-07-11 10:52:43 -0400384 return;
385 }
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400386 const char* bufferStart = reinterpret_cast<const char*>(map) + partialReadOffset;
Brian Salomona56a7462020-02-07 14:17:25 -0500387 memcpy(transferData.get(), bufferStart, partialBufferRowBytes * kTexDims.fHeight);
Greg Daniele877dce2019-07-11 10:52:43 -0400388 buffer->unmap();
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400389
390 transferInfo = transferInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon6aecd5e2019-07-16 09:47:32 -0400391 const char* textureDataStart =
392 textureData.get() + textureDataRowBytes * kPartialTop + textureDataBpp * kPartialLeft;
393 textureDataInfo = textureDataInfo.makeWH(kPartialWidth, kPartialHeight);
Brian Salomon28a8f282019-10-24 20:07:39 -0400394 ComparePixels(textureDataInfo, textureDataStart, textureDataRowBytes, transferInfo,
395 transferData.get(), partialBufferRowBytes, tol, error);
Brian Salomone05ba5a2019-04-08 11:59:07 -0400396#if GR_GPU_STATS
397 REPORTER_ASSERT(reporter, gpu->stats()->transfersFromSurface() == expectedTransferCnt);
398#else
399 (void)expectedTransferCnt;
400#endif
Jim Van Verth2e5eaf02017-06-21 15:55:46 -0400401}
Jim Van Verth686046b2019-03-18 15:39:22 -0400402
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500403DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsToTextureTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400404 if (!ctxInfo.directContext()->priv().caps()->transferFromBufferToTextureSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400405 return;
406 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400407 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon42be09d2019-07-26 12:12:26 -0400408 for (auto colorType : {
409 GrColorType::kAlpha_8,
410 GrColorType::kBGR_565,
411 GrColorType::kABGR_4444,
412 GrColorType::kRGBA_8888,
413 GrColorType::kRGBA_8888_SRGB,
414 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
415 GrColorType::kRG_88,
416 GrColorType::kBGRA_8888,
417 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400418 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500419 GrColorType::kGray_8,
Brian Salomon42be09d2019-07-26 12:12:26 -0400420 GrColorType::kAlpha_F16,
421 GrColorType::kRGBA_F16,
422 GrColorType::kRGBA_F16_Clamped,
423 GrColorType::kRGBA_F32,
Robert Phillips429f0d32019-09-11 17:03:28 -0400424 GrColorType::kAlpha_16,
Brian Salomon42be09d2019-07-26 12:12:26 -0400425 GrColorType::kRG_1616,
426 GrColorType::kRGBA_16161616,
427 GrColorType::kRG_F16,
428 }) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400429 basic_transfer_to_test(reporter, ctxInfo.directContext(), colorType, renderable);
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400430 }
431 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400432}
433
Brian Salomona585fe92019-04-09 14:57:00 -0400434// TODO(bsalomon): Metal
Brian Salomonfb28c6f2020-01-10 13:04:45 -0500435DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsFromTextureTest, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400436 if (!ctxInfo.directContext()->priv().caps()->transferFromSurfaceToBufferSupport()) {
Brian Salomone05ba5a2019-04-08 11:59:07 -0400437 return;
438 }
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400439 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
Brian Salomon6f6d2de2019-07-26 14:10:33 -0400440 for (auto colorType : {
Brian Salomonb3bd8642019-11-04 16:59:29 -0500441 GrColorType::kAlpha_8,
442 GrColorType::kAlpha_16,
443 GrColorType::kBGR_565,
444 GrColorType::kABGR_4444,
445 GrColorType::kRGBA_8888,
446 GrColorType::kRGBA_8888_SRGB,
447 // GrColorType::kRGB_888x, Broken in GL until we have kRGB_888
448 GrColorType::kRG_88,
449 GrColorType::kBGRA_8888,
450 GrColorType::kRGBA_1010102,
Robert Phillips9a30ee02020-04-29 08:58:39 -0400451 GrColorType::kBGRA_1010102,
Brian Salomonb3bd8642019-11-04 16:59:29 -0500452 GrColorType::kGray_8,
453 GrColorType::kAlpha_F16,
454 GrColorType::kRGBA_F16,
455 GrColorType::kRGBA_F16_Clamped,
456 GrColorType::kRGBA_F32,
457 GrColorType::kRG_1616,
458 GrColorType::kRGBA_16161616,
459 GrColorType::kRG_F16,
460 }) {
Brian Salomonf2c2ba92019-07-17 09:59:59 -0400461 basic_transfer_from_test(reporter, ctxInfo, colorType, renderable);
462 }
463 }
Brian Salomone05ba5a2019-04-08 11:59:07 -0400464}