Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 1 | /* |
| 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 Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 10 | #include "include/core/SkTypes.h" |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 11 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 12 | #include "include/core/SkSurface.h" |
Robert Phillips | 6d344c3 | 2020-07-06 10:56:46 -0400 | [diff] [blame] | 13 | #include "include/gpu/GrDirectContext.h" |
Adlai Holler | a069304 | 2020-10-14 11:23:11 -0400 | [diff] [blame^] | 14 | #include "src/gpu/GrDirectContextPriv.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 15 | #include "src/gpu/GrGpu.h" |
Brian Salomon | f2ebdd9 | 2019-09-30 12:15:30 -0400 | [diff] [blame] | 16 | #include "src/gpu/GrImageInfo.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 17 | #include "src/gpu/GrResourceProvider.h" |
Greg Daniel | f91aeb2 | 2019-06-18 09:58:02 -0400 | [diff] [blame] | 18 | #include "src/gpu/GrSurfaceProxy.h" |
Greg Daniel | 456f9b5 | 2020-03-05 19:14:18 +0000 | [diff] [blame] | 19 | #include "src/gpu/GrTexture.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 20 | #include "src/gpu/SkGr.h" |
| 21 | #include "tests/Test.h" |
Mike Klein | 52337de | 2019-07-25 09:00:52 -0500 | [diff] [blame] | 22 | #include "tests/TestUtils.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 23 | #include "tools/gpu/GrContextFactory.h" |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 24 | |
| 25 | using sk_gpu_test::GrContextFactory; |
| 26 | |
| 27 | void fill_transfer_data(int left, int top, int width, int height, int bufferWidth, |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 28 | 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 Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 33 | // build red-green gradient |
| 34 | for (int j = top; j < top + height; ++j) { |
| 35 | for (int i = left; i < left + width; ++i) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 36 | 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 Salomon | f2ebdd9 | 2019-09-30 12:15:30 -0400 | [diff] [blame] | 43 | GrImageInfo srcInfo(GrColorType::kRGBA_8888, kUnpremul_SkAlphaType, nullptr, 1, 1); |
| 44 | GrImageInfo dstInfo(dstType, kUnpremul_SkAlphaType, nullptr, 1, 1); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 45 | GrConvertPixels(dstInfo, dstLocation(i, j), dstBpp, srcInfo, &srcPixel, 4); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 50 | void determine_tolerances(GrColorType a, GrColorType b, float tolerances[4]) { |
Greg Daniel | 7bf37e0 | 2019-07-29 10:09:21 -0400 | [diff] [blame] | 51 | std::fill_n(tolerances, 4, 0); |
| 52 | |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 53 | 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 Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 68 | bool read_pixels_from_texture(GrTexture* texture, GrColorType colorType, char* dst, |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 69 | float tolerances[4]) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 70 | 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 Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 76 | size_t rowBytes = GrColorTypeBytesPerPixel(colorType) * w; |
Greg Daniel | c6dc5cf | 2019-07-17 16:02:00 -0400 | [diff] [blame] | 77 | |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 78 | GrCaps::SupportedRead supportedRead = |
Greg Daniel | d51fa2f | 2020-01-22 16:53:38 -0500 | [diff] [blame] | 79 | caps->supportedReadPixelsColorType(colorType, texture->backendFormat(), colorType); |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 80 | std::fill_n(tolerances, 4, 0); |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 81 | if (supportedRead.fColorType != colorType) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 82 | size_t tmpRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w; |
| 83 | std::unique_ptr<char[]> tmpPixels(new char[tmpRowBytes * h]); |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 84 | if (!gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, |
| 85 | tmpPixels.get(), tmpRowBytes)) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 86 | return false; |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 87 | } |
Brian Salomon | f2ebdd9 | 2019-09-30 12:15:30 -0400 | [diff] [blame] | 88 | GrImageInfo tmpInfo(supportedRead.fColorType, kUnpremul_SkAlphaType, nullptr, w, h); |
| 89 | GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, w, h); |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 90 | determine_tolerances(tmpInfo.colorType(), dstInfo.colorType(), tolerances); |
Brian Salomon | 8f8354a | 2019-07-31 20:12:02 -0400 | [diff] [blame] | 91 | return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, tmpPixels.get(), tmpRowBytes, |
| 92 | false); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 93 | } |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 94 | return gpu->readPixels(texture, 0, 0, w, h, colorType, supportedRead.fColorType, dst, rowBytes); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 95 | } |
| 96 | |
Robert Phillips | 58adb34 | 2020-07-23 09:41:57 -0400 | [diff] [blame] | 97 | void basic_transfer_to_test(skiatest::Reporter* reporter, |
| 98 | GrDirectContext* dContext, |
| 99 | GrColorType colorType, |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 100 | GrRenderable renderable) { |
Robert Phillips | 58adb34 | 2020-07-23 09:41:57 -0400 | [diff] [blame] | 101 | if (GrCaps::kNone_MapFlags == dContext->priv().caps()->mapBufferFlags()) { |
Brian Salomon | 7f56d3d | 2017-10-09 13:02:49 -0400 | [diff] [blame] | 102 | return; |
| 103 | } |
| 104 | |
Robert Phillips | 58adb34 | 2020-07-23 09:41:57 -0400 | [diff] [blame] | 105 | auto* caps = dContext->priv().caps(); |
Robert Phillips | 6be756b | 2018-01-16 15:07:54 -0500 | [diff] [blame] | 106 | |
Robert Phillips | 0a15cc6 | 2019-07-30 12:49:10 -0400 | [diff] [blame] | 107 | auto backendFormat = caps->getDefaultBackendFormat(colorType, renderable); |
| 108 | if (!backendFormat.isValid()) { |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 109 | return; |
Greg Daniel | 6432909 | 2019-07-16 16:16:21 -0400 | [diff] [blame] | 110 | } |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 111 | |
Robert Phillips | 58adb34 | 2020-07-23 09:41:57 -0400 | [diff] [blame] | 112 | auto resourceProvider = dContext->priv().resourceProvider(); |
| 113 | GrGpu* gpu = dContext->priv().getGpu(); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 114 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 115 | static constexpr SkISize kTexDims = {16, 16}; |
Brian Salomon | f27e51f | 2019-07-25 13:20:58 -0400 | [diff] [blame] | 116 | int srcBufferWidth = caps->writePixelsRowBytesSupport() ? 20 : 16; |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 117 | const int kBufferHeight = 16; |
| 118 | |
Brian Salomon | a90382f | 2019-09-17 09:01:56 -0400 | [diff] [blame] | 119 | sk_sp<GrTexture> tex = |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 120 | resourceProvider->createTexture(kTexDims, backendFormat, renderable, 1, |
Brian Salomon | 7e67dca | 2020-07-21 09:27:25 -0400 | [diff] [blame] | 121 | GrMipmapped::kNo, SkBudgeted::kNo, GrProtected::kNo); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 122 | if (!tex) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 123 | ERRORF(reporter, "Could not create texture"); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 124 | return; |
| 125 | } |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 126 | |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 127 | // 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 Daniel | 900583a | 2019-08-06 12:05:31 -0400 | [diff] [blame] | 137 | if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 138 | return; |
| 139 | } |
| 140 | |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 141 | // 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 Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 143 | GrCaps::SupportedWrite allowedSrc = |
Brian Salomon | 01915c0 | 2019-08-02 09:57:21 -0400 | [diff] [blame] | 144 | caps->supportedWritePixelsColorType(colorType, tex->backendFormat(), colorType); |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 145 | size_t srcRowBytes = GrColorTypeBytesPerPixel(allowedSrc.fColorType) * srcBufferWidth; |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 146 | std::unique_ptr<char[]> srcData(new char[kTexDims.fHeight * srcRowBytes]); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 147 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 148 | fill_transfer_data(0, 0, kTexDims.fWidth, kTexDims.fHeight, srcBufferWidth, |
| 149 | allowedSrc.fColorType, srcData.get()); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 150 | |
| 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 Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 166 | ////////////////////////// |
| 167 | // transfer full data |
Robert Phillips | 16d8ec6 | 2017-07-27 16:16:25 -0400 | [diff] [blame] | 168 | |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 169 | bool result; |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 170 | result = gpu->transferPixelsTo(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, colorType, |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 171 | allowedSrc.fColorType, buffer.get(), 0, srcRowBytes); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 172 | REPORTER_ASSERT(reporter, result); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 173 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 174 | size_t dstRowBytes = GrColorTypeBytesPerPixel(colorType) * kTexDims.fWidth; |
| 175 | std::unique_ptr<char[]> dstBuffer(new char[dstRowBytes * kTexDims.fHeight]()); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 176 | |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 177 | float compareTolerances[4] = {}; |
| 178 | result = read_pixels_from_texture(tex.get(), colorType, dstBuffer.get(), compareTolerances); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 179 | if (!result) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 180 | ERRORF(reporter, "Could not read pixels from texture, color type: %d", |
| 181 | static_cast<int>(colorType)); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 182 | return; |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 183 | } |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 184 | |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 185 | auto error = std::function<ComparePixmapsErrorReporter>( |
| 186 | [reporter, colorType](int x, int y, const float diffs[4]) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 187 | ERRORF(reporter, |
Robert Phillips | 9a30ee0 | 2020-04-29 08:58:39 -0400 | [diff] [blame] | 188 | "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 Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 191 | }); |
Brian Salomon | f2ebdd9 | 2019-09-30 12:15:30 -0400 | [diff] [blame] | 192 | GrImageInfo srcInfo(allowedSrc.fColorType, kUnpremul_SkAlphaType, nullptr, tex->width(), |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 193 | tex->height()); |
Brian Salomon | f2ebdd9 | 2019-09-30 12:15:30 -0400 | [diff] [blame] | 194 | GrImageInfo dstInfo(colorType, kUnpremul_SkAlphaType, nullptr, tex->width(), tex->height()); |
Brian Salomon | 28a8f28 | 2019-10-24 20:07:39 -0400 | [diff] [blame] | 195 | ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes, |
| 196 | compareTolerances, error); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 197 | |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 198 | ////////////////////////// |
| 199 | // transfer partial data |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 200 | |
| 201 | // We're relying on this cap to write partial texture data |
| 202 | if (!caps->writePixelsRowBytesSupport()) { |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 203 | return; |
| 204 | } |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 205 | // 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 Salomon | c320b15 | 2018-02-20 14:05:36 -0500 | [diff] [blame] | 221 | |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 222 | // change color of subrectangle |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 223 | fill_transfer_data(left, top, width, height, srcBufferWidth, allowedSrc.fColorType, |
| 224 | srcData.get()); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 225 | data = buffer->map(); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 226 | memcpy(data, srcData.get(), size); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 227 | buffer->unmap(); |
Brian Salomon | c320b15 | 2018-02-20 14:05:36 -0500 | [diff] [blame] | 228 | |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 229 | result = gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, |
| 230 | allowedSrc.fColorType, buffer.get(), offset, srcRowBytes); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 231 | if (!result) { |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 232 | gpu->transferPixelsTo(tex.get(), left, top, width, height, colorType, allowedSrc.fColorType, |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 233 | buffer.get(), offset, srcRowBytes); |
| 234 | ERRORF(reporter, "Could not transfer pixels to texture, color type: %d", |
| 235 | static_cast<int>(colorType)); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 236 | return; |
Jim Van Verth | 52fb02e | 2017-06-27 10:36:56 -0400 | [diff] [blame] | 237 | } |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 238 | |
| 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 Salomon | 28a8f28 | 2019-10-24 20:07:39 -0400 | [diff] [blame] | 245 | ComparePixels(srcInfo, srcData.get(), srcRowBytes, dstInfo, dstBuffer.get(), dstRowBytes, |
| 246 | compareTolerances, error); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 247 | } |
| 248 | |
Brian Salomon | 42cbedd | 2019-04-09 15:00:05 -0400 | [diff] [blame] | 249 | void basic_transfer_from_test(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& ctxInfo, |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 250 | GrColorType colorType, GrRenderable renderable) { |
Robert Phillips | 6d344c3 | 2020-07-06 10:56:46 -0400 | [diff] [blame] | 251 | auto context = ctxInfo.directContext(); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 252 | auto caps = context->priv().caps(); |
| 253 | if (GrCaps::kNone_MapFlags == caps->mapBufferFlags()) { |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 254 | return; |
| 255 | } |
Jim Van Verth | 686046b | 2019-03-18 15:39:22 -0400 | [diff] [blame] | 256 | |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 257 | auto resourceProvider = context->priv().resourceProvider(); |
| 258 | GrGpu* gpu = context->priv().getGpu(); |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 259 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 260 | static constexpr SkISize kTexDims = {16, 16}; |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 261 | |
| 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 Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 269 | // create texture |
Brian Salomon | 4eb38b7 | 2019-08-05 12:58:39 -0400 | [diff] [blame] | 270 | auto format = context->priv().caps()->getDefaultBackendFormat(colorType, renderable); |
| 271 | if (!format.isValid()) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 272 | return; |
| 273 | } |
| 274 | |
| 275 | size_t textureDataBpp = GrColorTypeBytesPerPixel(colorType); |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 276 | 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 Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 279 | textureData.get()); |
| 280 | GrMipLevel data; |
| 281 | data.fPixels = textureData.get(); |
| 282 | data.fRowBytes = textureDataRowBytes; |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 283 | sk_sp<GrTexture> tex = |
| 284 | resourceProvider->createTexture(kTexDims, format, colorType, renderable, 1, |
| 285 | SkBudgeted::kNo, GrProtected::kNo, &data, 1); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 286 | if (!tex) { |
| 287 | return; |
| 288 | } |
| 289 | |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 290 | 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 Daniel | 900583a | 2019-08-06 12:05:31 -0400 | [diff] [blame] | 297 | if (!caps->isFormatAsColorTypeRenderable(colorType, tex->backendFormat())) { |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 298 | return; |
| 299 | } |
| 300 | |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 301 | // Create the transfer buffer. |
| 302 | auto allowedRead = |
Greg Daniel | 00fb724 | 2019-07-18 14:28:01 -0400 | [diff] [blame] | 303 | caps->supportedReadPixelsColorType(colorType, tex->backendFormat(), colorType); |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 304 | GrImageInfo readInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 305 | |
| 306 | size_t bpp = GrColorTypeBytesPerPixel(allowedRead.fColorType); |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 307 | size_t fullBufferRowBytes = kTexDims.fWidth * bpp; |
Brian Salomon | 26de56e | 2019-04-10 12:14:26 -0400 | [diff] [blame] | 308 | size_t partialBufferRowBytes = kPartialWidth * bpp; |
Greg Daniel | ba88ab6 | 2019-07-26 09:14:01 -0400 | [diff] [blame] | 309 | size_t offsetAlignment = allowedRead.fOffsetAlignmentForTransferBuffer; |
Brian Salomon | 26de56e | 2019-04-10 12:14:26 -0400 | [diff] [blame] | 310 | SkASSERT(offsetAlignment); |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 311 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 312 | size_t bufferSize = fullBufferRowBytes * kTexDims.fHeight; |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 313 | // Arbitrary starting offset for the partial read. |
Brian Salomon | e994380 | 2020-01-03 13:07:07 -0500 | [diff] [blame] | 314 | size_t partialReadOffset = GrAlignTo(11, offsetAlignment); |
Brian Osman | 788b916 | 2020-02-07 10:36:46 -0500 | [diff] [blame] | 315 | bufferSize = std::max(bufferSize, partialReadOffset + partialBufferRowBytes * kPartialHeight); |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 316 | |
| 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 Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 326 | |
| 327 | ////////////////////////// |
| 328 | // transfer full data |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 329 | bool result = gpu->transferPixelsFrom(tex.get(), 0, 0, kTexDims.fWidth, kTexDims.fHeight, |
| 330 | colorType, allowedRead.fColorType, buffer.get(), 0); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 331 | if (!result) { |
| 332 | ERRORF(reporter, "transferPixelsFrom failed."); |
| 333 | return; |
| 334 | } |
| 335 | ++expectedTransferCnt; |
| 336 | |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 337 | if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) { |
Greg Daniel | fe15962 | 2020-04-10 17:43:51 +0000 | [diff] [blame] | 338 | gpu->submitToGpu(true); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 339 | } |
| 340 | |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 341 | // Copy the transfer buffer contents to a temporary so we can manipulate it. |
| 342 | const auto* map = reinterpret_cast<const char*>(buffer->map()); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 343 | REPORTER_ASSERT(reporter, map); |
| 344 | if (!map) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 345 | ERRORF(reporter, "Failed to map transfer buffer."); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 346 | return; |
| 347 | } |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 348 | std::unique_ptr<char[]> transferData(new char[kTexDims.fHeight * fullBufferRowBytes]); |
| 349 | memcpy(transferData.get(), map, fullBufferRowBytes * kTexDims.fHeight); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 350 | buffer->unmap(); |
| 351 | |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 352 | GrImageInfo transferInfo(allowedRead.fColorType, kUnpremul_SkAlphaType, nullptr, kTexDims); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 353 | |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 354 | float tol[4]; |
| 355 | determine_tolerances(allowedRead.fColorType, colorType, tol); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 356 | auto error = std::function<ComparePixmapsErrorReporter>( |
| 357 | [reporter, colorType](int x, int y, const float diffs[4]) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 358 | ERRORF(reporter, |
Robert Phillips | 9a30ee0 | 2020-04-29 08:58:39 -0400 | [diff] [blame] | 359 | "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 Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 362 | }); |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 363 | GrImageInfo textureDataInfo(colorType, kUnpremul_SkAlphaType, nullptr, kTexDims); |
Brian Salomon | 28a8f28 | 2019-10-24 20:07:39 -0400 | [diff] [blame] | 364 | ComparePixels(textureDataInfo, textureData.get(), textureDataRowBytes, transferInfo, |
| 365 | transferData.get(), fullBufferRowBytes, tol, error); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 366 | |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 367 | /////////////////////// |
| 368 | // Now test a partial read at an offset into the buffer. |
| 369 | result = gpu->transferPixelsFrom(tex.get(), kPartialLeft, kPartialTop, kPartialWidth, |
Brian Salomon | f77c146 | 2019-08-01 15:19:29 -0400 | [diff] [blame] | 370 | kPartialHeight, colorType, allowedRead.fColorType, |
| 371 | buffer.get(), partialReadOffset); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 372 | if (!result) { |
| 373 | ERRORF(reporter, "transferPixelsFrom failed."); |
| 374 | return; |
| 375 | } |
| 376 | ++expectedTransferCnt; |
| 377 | |
| 378 | if (context->priv().caps()->mapBufferFlags() & GrCaps::kAsyncRead_MapFlag) { |
Greg Daniel | fe15962 | 2020-04-10 17:43:51 +0000 | [diff] [blame] | 379 | gpu->submitToGpu(true); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 380 | } |
| 381 | |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 382 | map = reinterpret_cast<const char*>(buffer->map()); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 383 | REPORTER_ASSERT(reporter, map); |
| 384 | if (!map) { |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 385 | ERRORF(reporter, "Failed to map transfer buffer."); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 386 | return; |
| 387 | } |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 388 | const char* bufferStart = reinterpret_cast<const char*>(map) + partialReadOffset; |
Brian Salomon | a56a746 | 2020-02-07 14:17:25 -0500 | [diff] [blame] | 389 | memcpy(transferData.get(), bufferStart, partialBufferRowBytes * kTexDims.fHeight); |
Greg Daniel | e877dce | 2019-07-11 10:52:43 -0400 | [diff] [blame] | 390 | buffer->unmap(); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 391 | |
| 392 | transferInfo = transferInfo.makeWH(kPartialWidth, kPartialHeight); |
Brian Salomon | 6aecd5e | 2019-07-16 09:47:32 -0400 | [diff] [blame] | 393 | const char* textureDataStart = |
| 394 | textureData.get() + textureDataRowBytes * kPartialTop + textureDataBpp * kPartialLeft; |
| 395 | textureDataInfo = textureDataInfo.makeWH(kPartialWidth, kPartialHeight); |
Brian Salomon | 28a8f28 | 2019-10-24 20:07:39 -0400 | [diff] [blame] | 396 | ComparePixels(textureDataInfo, textureDataStart, textureDataRowBytes, transferInfo, |
| 397 | transferData.get(), partialBufferRowBytes, tol, error); |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 398 | #if GR_GPU_STATS |
| 399 | REPORTER_ASSERT(reporter, gpu->stats()->transfersFromSurface() == expectedTransferCnt); |
| 400 | #else |
| 401 | (void)expectedTransferCnt; |
| 402 | #endif |
Jim Van Verth | 2e5eaf0 | 2017-06-21 15:55:46 -0400 | [diff] [blame] | 403 | } |
Jim Van Verth | 686046b | 2019-03-18 15:39:22 -0400 | [diff] [blame] | 404 | |
Brian Salomon | fb28c6f | 2020-01-10 13:04:45 -0500 | [diff] [blame] | 405 | DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsToTextureTest, reporter, ctxInfo) { |
Robert Phillips | 6d344c3 | 2020-07-06 10:56:46 -0400 | [diff] [blame] | 406 | if (!ctxInfo.directContext()->priv().caps()->transferFromBufferToTextureSupport()) { |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 407 | return; |
| 408 | } |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 409 | for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) { |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 410 | 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 Phillips | 9a30ee0 | 2020-04-29 08:58:39 -0400 | [diff] [blame] | 420 | GrColorType::kBGRA_1010102, |
Brian Salomon | b3bd864 | 2019-11-04 16:59:29 -0500 | [diff] [blame] | 421 | GrColorType::kGray_8, |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 422 | GrColorType::kAlpha_F16, |
| 423 | GrColorType::kRGBA_F16, |
| 424 | GrColorType::kRGBA_F16_Clamped, |
| 425 | GrColorType::kRGBA_F32, |
Robert Phillips | 429f0d3 | 2019-09-11 17:03:28 -0400 | [diff] [blame] | 426 | GrColorType::kAlpha_16, |
Brian Salomon | 42be09d | 2019-07-26 12:12:26 -0400 | [diff] [blame] | 427 | GrColorType::kRG_1616, |
| 428 | GrColorType::kRGBA_16161616, |
| 429 | GrColorType::kRG_F16, |
| 430 | }) { |
Robert Phillips | 6d344c3 | 2020-07-06 10:56:46 -0400 | [diff] [blame] | 431 | basic_transfer_to_test(reporter, ctxInfo.directContext(), colorType, renderable); |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 432 | } |
| 433 | } |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 434 | } |
| 435 | |
Brian Salomon | a585fe9 | 2019-04-09 14:57:00 -0400 | [diff] [blame] | 436 | // TODO(bsalomon): Metal |
Brian Salomon | fb28c6f | 2020-01-10 13:04:45 -0500 | [diff] [blame] | 437 | DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsFromTextureTest, reporter, ctxInfo) { |
Robert Phillips | 6d344c3 | 2020-07-06 10:56:46 -0400 | [diff] [blame] | 438 | if (!ctxInfo.directContext()->priv().caps()->transferFromSurfaceToBufferSupport()) { |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 439 | return; |
| 440 | } |
Brian Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 441 | for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) { |
Brian Salomon | 6f6d2de | 2019-07-26 14:10:33 -0400 | [diff] [blame] | 442 | for (auto colorType : { |
Brian Salomon | b3bd864 | 2019-11-04 16:59:29 -0500 | [diff] [blame] | 443 | 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 Phillips | 9a30ee0 | 2020-04-29 08:58:39 -0400 | [diff] [blame] | 453 | GrColorType::kBGRA_1010102, |
Brian Salomon | b3bd864 | 2019-11-04 16:59:29 -0500 | [diff] [blame] | 454 | 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 Salomon | f2c2ba9 | 2019-07-17 09:59:59 -0400 | [diff] [blame] | 463 | basic_transfer_from_test(reporter, ctxInfo, colorType, renderable); |
| 464 | } |
| 465 | } |
Brian Salomon | e05ba5a | 2019-04-08 11:59:07 -0400 | [diff] [blame] | 466 | } |