blob: ce06ff73e200a14f9c805b1ee5f7932ca5187c6e [file] [log] [blame]
Robert Phillips3e5e2f22019-12-19 11:19:16 -05001/*
2 * Copyright 2019 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
Robert Phillipse19babf2020-04-06 13:57:30 -04008#include "include/core/SkCanvas.h"
Robert Phillips6d344c32020-07-06 10:56:46 -04009#include "include/gpu/GrDirectContext.h"
Robert Phillipsc8ae4942020-07-20 10:56:01 -040010#include "include/gpu/GrRecordingContext.h"
Robert Phillips3e5e2f22019-12-19 11:19:16 -050011#include "src/core/SkAutoPixmapStorage.h"
Robert Phillips99dead92020-01-27 16:11:57 -050012#include "src/core/SkCompressedDataUtils.h"
Mike Reed13711eb2020-07-14 17:16:32 -040013#include "src/core/SkMipmap.h"
Greg Daniel01f278c2020-06-12 16:58:17 -040014#include "src/gpu/GrBackendUtils.h"
Robert Phillips3e5e2f22019-12-19 11:19:16 -050015#include "src/gpu/GrContextPriv.h"
16#include "src/image/SkImage_Base.h"
17#include "tests/Test.h"
18#include "tests/TestUtils.h"
19#include "tools/ToolUtils.h"
20
Robert Phillips07f0e412020-01-17 15:20:00 -050021// Just verify that 'actual' is entirely 'expected'
Robert Phillips3e5e2f22019-12-19 11:19:16 -050022static void check_solid_pixmap(skiatest::Reporter* reporter,
23 const SkColor4f& expected, const SkPixmap& actual,
24 const char* label0, const char* label1, const char* label2) {
25 const float tols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
26
27 auto error = std::function<ComparePixmapsErrorReporter>(
28 [reporter, label0, label1, label2](int x, int y, const float diffs[4]) {
29 SkASSERT(x >= 0 && y >= 0);
30 ERRORF(reporter, "%s %s %s - mismatch at %d, %d (%f, %f, %f %f)",
31 label0, label1, label2, x, y,
32 diffs[0], diffs[1], diffs[2], diffs[3]);
33 });
34
35 CheckSolidPixels(expected, actual, tols, error);
36}
37
Robert Phillips07f0e412020-01-17 15:20:00 -050038// Create an SkImage to wrap 'backendTex'
39sk_sp<SkImage> create_image(GrContext* context, const GrBackendTexture& backendTex) {
Greg Daniel01f278c2020-06-12 16:58:17 -040040 SkImage::CompressionType compression =
41 GrBackendFormatToCompressionType(backendTex.getBackendFormat());
Robert Phillips3e5e2f22019-12-19 11:19:16 -050042
Robert Phillips99dead92020-01-27 16:11:57 -050043 SkAlphaType at = SkCompressionTypeIsOpaque(compression) ? kOpaque_SkAlphaType
Robert Phillipsb0855272020-01-15 12:56:52 -050044 : kPremul_SkAlphaType;
Robert Phillips3e5e2f22019-12-19 11:19:16 -050045
Robert Phillips07f0e412020-01-17 15:20:00 -050046 return SkImage::MakeFromCompressedTexture(context,
47 backendTex,
48 kTopLeft_GrSurfaceOrigin,
49 at,
50 nullptr);
51}
52
53// Draw the compressed backend texture (wrapped in an SkImage) into an RGBA surface, attempting
54// to access all the mipMap levels.
Robert Phillipsc8ae4942020-07-20 10:56:01 -040055static void check_compressed_mipmaps(GrRecordingContext* rContext, sk_sp<SkImage> img,
Robert Phillips07f0e412020-01-17 15:20:00 -050056 SkImage::CompressionType compressionType,
57 const SkColor4f expectedColors[6],
Brian Salomon7e67dca2020-07-21 09:27:25 -040058 GrMipmapped mipMapped,
Robert Phillips07f0e412020-01-17 15:20:00 -050059 skiatest::Reporter* reporter, const char* label) {
Robert Phillips3e5e2f22019-12-19 11:19:16 -050060
61 SkImageInfo readbackSurfaceII = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType,
62 kPremul_SkAlphaType);
63
Robert Phillipsc8ae4942020-07-20 10:56:01 -040064 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(rContext,
Robert Phillips3e5e2f22019-12-19 11:19:16 -050065 SkBudgeted::kNo,
66 readbackSurfaceII, 1,
67 kTopLeft_GrSurfaceOrigin,
68 nullptr);
69 if (!surf) {
70 return;
71 }
72
73 SkCanvas* canvas = surf->getCanvas();
74
75 SkPaint p;
Robert Phillipsb0855272020-01-15 12:56:52 -050076 p.setFilterQuality(kHigh_SkFilterQuality); // to force mipMapping
77 p.setBlendMode(SkBlendMode::kSrc);
Robert Phillips3e5e2f22019-12-19 11:19:16 -050078
79 int numMipLevels = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -040080 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -040081 numMipLevels = SkMipmap::ComputeLevelCount(32, 32)+1;
Robert Phillips3e5e2f22019-12-19 11:19:16 -050082 }
83
84 for (int i = 0, rectSize = 32; i < numMipLevels; ++i, rectSize /= 2) {
85 SkASSERT(rectSize >= 1);
86
87 canvas->clear(SK_ColorTRANSPARENT);
88
89 SkRect r = SkRect::MakeWH(rectSize, rectSize);
90 canvas->drawImageRect(img, r, &p);
91
92 SkImageInfo readbackII = SkImageInfo::Make(rectSize, rectSize,
93 kRGBA_8888_SkColorType,
94 kUnpremul_SkAlphaType);
95 SkAutoPixmapStorage actual2;
96 SkAssertResult(actual2.tryAlloc(readbackII));
97 actual2.erase(SkColors::kTransparent);
98
99 bool result = surf->readPixels(actual2, 0, 0);
100 REPORTER_ASSERT(reporter, result);
101
102 SkString str;
103 str.appendf("mip-level %d", i);
104
105 check_solid_pixmap(reporter, expectedColors[i], actual2,
Robert Phillips07f0e412020-01-17 15:20:00 -0500106 GrCompressionTypeToStr(compressionType), label, str.c_str());
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500107 }
108}
109
Robert Phillips07f0e412020-01-17 15:20:00 -0500110// Verify that we can readback from a compressed texture
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400111static void check_readback(GrDirectContext* dContext, sk_sp<SkImage> img,
Robert Phillips07f0e412020-01-17 15:20:00 -0500112 SkImage::CompressionType compressionType,
113 const SkColor4f& expectedColor,
114 skiatest::Reporter* reporter, const char* label) {
Robert Phillips314524e2020-01-30 08:38:40 -0500115#ifdef SK_BUILD_FOR_IOS
116 // reading back ETC2 is broken on Metal/iOS (skbug.com/9839)
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400117 if (dContext->backend() == GrBackendApi::kMetal) {
Robert Phillips314524e2020-01-30 08:38:40 -0500118 return;
119 }
120#endif
121
Robert Phillips07f0e412020-01-17 15:20:00 -0500122 SkAutoPixmapStorage actual;
123
124 SkImageInfo readBackII = SkImageInfo::Make(img->width(), img->height(),
125 kRGBA_8888_SkColorType,
126 kUnpremul_SkAlphaType);
127
128 SkAssertResult(actual.tryAlloc(readBackII));
129 actual.erase(SkColors::kTransparent);
130
131 bool result = img->readPixels(actual, 0, 0);
132 REPORTER_ASSERT(reporter, result);
133
134 check_solid_pixmap(reporter, expectedColor, actual,
135 GrCompressionTypeToStr(compressionType), label, "");
136}
137
138// Test initialization of compressed GrBackendTextures to a specific color
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400139static void test_compressed_color_init(GrDirectContext* dContext,
Robert Phillips07f0e412020-01-17 15:20:00 -0500140 skiatest::Reporter* reporter,
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400141 std::function<GrBackendTexture (GrDirectContext*,
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500142 const SkColor4f&,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400143 GrMipmapped)> create,
Robert Phillips07f0e412020-01-17 15:20:00 -0500144 const SkColor4f& color,
145 SkImage::CompressionType compression,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400146 GrMipmapped mipMapped) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400147 GrBackendTexture backendTex = create(dContext, color, mipMapped);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500148 if (!backendTex.isValid()) {
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500149 return;
150 }
151
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400152 sk_sp<SkImage> img = create_image(dContext, backendTex);
Robert Phillips07f0e412020-01-17 15:20:00 -0500153 if (!img) {
154 return;
155 }
156
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500157 SkColor4f expectedColors[6] = { color, color, color, color, color, color };
158
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400159 check_compressed_mipmaps(dContext, img, compression, expectedColors, mipMapped,
Robert Phillips07f0e412020-01-17 15:20:00 -0500160 reporter, "colorinit");
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400161 check_readback(dContext, std::move(img), compression, color, reporter,
Greg Danielceebe422020-07-14 15:05:42 +0000162 "solid readback");
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500163
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400164 dContext->deleteBackendTexture(backendTex);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500165}
166
Robert Phillips07f0e412020-01-17 15:20:00 -0500167// Create compressed data pulling the color for each mipmap level from 'levelColors'.
Robert Phillipsca0f8372019-12-20 09:57:41 -0500168static std::unique_ptr<const char[]> make_compressed_data(SkImage::CompressionType compression,
169 SkColor4f levelColors[6],
Brian Salomon7e67dca2020-07-21 09:27:25 -0400170 GrMipmapped mipMapped) {
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500171 SkISize dimensions { 32, 32 };
172
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500173 int numMipLevels = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400174 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400175 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500176 }
177
Robert Phillipsca0f8372019-12-20 09:57:41 -0500178 SkTArray<size_t> mipMapOffsets(numMipLevels);
179
Robert Phillips99dead92020-01-27 16:11:57 -0500180 size_t dataSize = SkCompressedDataSize(compression, dimensions, &mipMapOffsets,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400181 mipMapped == GrMipmapped::kYes);
Robert Phillipsca0f8372019-12-20 09:57:41 -0500182 char* data = new char[dataSize];
183
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500184 for (int level = 0; level < numMipLevels; ++level) {
Robert Phillipsca0f8372019-12-20 09:57:41 -0500185 // We have to do this a level at a time bc we might have a different color for
186 // each level
187 GrFillInCompressedData(compression, dimensions,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400188 GrMipmapped::kNo, &data[mipMapOffsets[level]], levelColors[level]);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500189
Brian Osman788b9162020-02-07 10:36:46 -0500190 dimensions = {std::max(1, dimensions.width() /2), std::max(1, dimensions.height()/2)};
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500191 }
192
193 return std::unique_ptr<const char[]>(data);
194}
195
Robert Phillips07f0e412020-01-17 15:20:00 -0500196// Verify that we can initialize a compressed backend texture with data (esp.
197// the mipmap levels).
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400198static void test_compressed_data_init(GrDirectContext* dContext,
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500199 skiatest::Reporter* reporter,
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400200 std::function<GrBackendTexture (GrDirectContext*,
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500201 const char* data,
202 size_t dataSize,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400203 GrMipmapped)> create,
Robert Phillipsca0f8372019-12-20 09:57:41 -0500204 SkImage::CompressionType compression,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400205 GrMipmapped mipMapped) {
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500206
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500207 SkColor4f expectedColors[6] = {
208 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
209 { 0.0f, 1.0f, 0.0f, 1.0f }, // G
210 { 0.0f, 0.0f, 1.0f, 1.0f }, // B
211 { 0.0f, 1.0f, 1.0f, 1.0f }, // C
212 { 1.0f, 0.0f, 1.0f, 1.0f }, // M
213 { 1.0f, 1.0f, 0.0f, 1.0f }, // Y
214 };
215
Robert Phillipsca0f8372019-12-20 09:57:41 -0500216 std::unique_ptr<const char[]> data(make_compressed_data(compression, expectedColors,
217 mipMapped));
Robert Phillips99dead92020-01-27 16:11:57 -0500218 size_t dataSize = SkCompressedDataSize(compression, { 32, 32 }, nullptr,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400219 mipMapped == GrMipmapped::kYes);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500220
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400221 GrBackendTexture backendTex = create(dContext, data.get(), dataSize, mipMapped);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500222 if (!backendTex.isValid()) {
223 return;
224 }
225
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400226 sk_sp<SkImage> img = create_image(dContext, backendTex);
Robert Phillips07f0e412020-01-17 15:20:00 -0500227 if (!img) {
228 return;
229 }
230
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400231 check_compressed_mipmaps(dContext, img, compression, expectedColors,
Robert Phillips07f0e412020-01-17 15:20:00 -0500232 mipMapped, reporter, "pixmap");
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400233 check_readback(dContext, std::move(img), compression, expectedColors[0], reporter,
Robert Phillips07f0e412020-01-17 15:20:00 -0500234 "data readback");
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500235
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400236 dContext->deleteBackendTexture(backendTex);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500237}
238
239DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CompressedBackendAllocationTest, reporter, ctxInfo) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400240 auto dContext = ctxInfo.directContext();
241 const GrCaps* caps = dContext->priv().caps();
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500242
243 struct {
244 SkImage::CompressionType fCompression;
245 SkColor4f fColor;
246 } combinations[] = {
Robert Phillipsc558f722020-01-13 13:02:26 -0500247 { SkImage::CompressionType::kETC2_RGB8_UNORM, SkColors::kRed },
Robert Phillips07f0e412020-01-17 15:20:00 -0500248 { SkImage::CompressionType::kBC1_RGB8_UNORM, SkColors::kBlue },
Robert Phillipsb0855272020-01-15 12:56:52 -0500249 { SkImage::CompressionType::kBC1_RGBA8_UNORM, SkColors::kTransparent },
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500250 };
251
252 for (auto combo : combinations) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400253 GrBackendFormat format = dContext->compressedBackendFormat(combo.fCompression);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500254 if (!format.isValid()) {
255 continue;
256 }
257
258 if (!caps->isFormatTexturable(format)) {
259 continue;
260 }
261
Brian Salomon7e67dca2020-07-21 09:27:25 -0400262 for (auto mipMapped : { GrMipmapped::kNo, GrMipmapped::kYes }) {
263 if (GrMipmapped::kYes == mipMapped && !caps->mipMapSupport()) {
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500264 continue;
265 }
266
267 // color initialized
268 {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400269 auto createWithColorMtd = [format](GrDirectContext* dContext,
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500270 const SkColor4f& color,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400271 GrMipmapped mipMapped) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400272 return dContext->createCompressedBackendTexture(32, 32, format, color,
273 mipMapped, GrProtected::kNo);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500274 };
275
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400276 test_compressed_color_init(dContext, reporter, createWithColorMtd,
Robert Phillips07f0e412020-01-17 15:20:00 -0500277 combo.fColor, combo.fCompression, mipMapped);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500278 }
279
280 // data initialized
281 {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400282 auto createWithDataMtd = [format](GrDirectContext* dContext,
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500283 const char* data, size_t dataSize,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400284 GrMipmapped mipMapped) {
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400285 return dContext->createCompressedBackendTexture(32, 32, format, data, dataSize,
286 mipMapped, GrProtected::kNo);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500287 };
288
Robert Phillipsc8ae4942020-07-20 10:56:01 -0400289 test_compressed_data_init(dContext, reporter, createWithDataMtd,
Robert Phillipsca0f8372019-12-20 09:57:41 -0500290 combo.fCompression, mipMapped);
Robert Phillips3e5e2f22019-12-19 11:19:16 -0500291 }
292
293 }
294 }
295}