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