Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / tests / CompressedBackendAllocationTest.cpp
1 /*
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
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkColorSpace.h"
10 #include "include/gpu/GrDirectContext.h"
11 #include "include/gpu/GrRecordingContext.h"
12 #include "src/core/SkAutoPixmapStorage.h"
13 #include "src/core/SkCompressedDataUtils.h"
14 #include "src/core/SkMipmap.h"
15 #include "src/core/SkPaintPriv.h"
16 #include "src/gpu/ganesh/GrBackendUtils.h"
17 #include "src/gpu/ganesh/GrDirectContextPriv.h"
18 #include "src/image/SkImage_Base.h"
19 #include "tests/Test.h"
20 #include "tests/TestUtils.h"
21 #include "tools/ToolUtils.h"
22
23 // Just verify that 'actual' is entirely 'expected'
24 static void check_solid_pixmap(skiatest::Reporter* reporter,
25                                const SkColor4f& expected, const SkPixmap& actual,
26                                const char* label0, const char* label1, const char* label2) {
27     const float tols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
28
29     auto error = std::function<ComparePixmapsErrorReporter>(
30         [reporter, label0, label1, label2](int x, int y, const float diffs[4]) {
31             SkASSERT(x >= 0 && y >= 0);
32             ERRORF(reporter, "%s %s %s - mismatch at %d, %d (%f, %f, %f %f)",
33                    label0, label1, label2, x, y,
34                    diffs[0], diffs[1], diffs[2], diffs[3]);
35         });
36
37     CheckSolidPixels(expected, actual, tols, error);
38 }
39
40 // Create an SkImage to wrap 'backendTex'
41 sk_sp<SkImage> create_image(GrDirectContext* dContext, const GrBackendTexture& backendTex) {
42     SkImage::CompressionType compression =
43             GrBackendFormatToCompressionType(backendTex.getBackendFormat());
44
45     SkAlphaType at = SkCompressionTypeIsOpaque(compression) ? kOpaque_SkAlphaType
46                                                             : kPremul_SkAlphaType;
47
48     return SkImage::MakeFromCompressedTexture(dContext,
49                                               backendTex,
50                                               kTopLeft_GrSurfaceOrigin,
51                                               at,
52                                               nullptr);
53 }
54
55 // Draw the compressed backend texture (wrapped in an SkImage) into an RGBA surface, attempting
56 // to access all the mipMap levels.
57 static void check_compressed_mipmaps(GrRecordingContext* rContext, sk_sp<SkImage> img,
58                                      SkImage::CompressionType compressionType,
59                                      const SkColor4f expectedColors[6],
60                                      GrMipmapped mipmapped,
61                                      skiatest::Reporter* reporter, const char* label) {
62
63     SkImageInfo readbackSurfaceII = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType,
64                                                       kPremul_SkAlphaType);
65
66     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(rContext,
67                                                         SkBudgeted::kNo,
68                                                         readbackSurfaceII, 1,
69                                                         kTopLeft_GrSurfaceOrigin,
70                                                         nullptr);
71     if (!surf) {
72         return;
73     }
74
75     SkCanvas* canvas = surf->getCanvas();
76
77     // Given that we bias LOD selection with MIP maps, hitting a level exactly using
78     // SkMipmap::kLinear is difficult so we use kNearest.
79     const SkSamplingOptions sampling(SkFilterMode::kLinear,
80                                      SkMipmapMode::kNearest);
81     SkPaint p;
82     p.setBlendMode(SkBlendMode::kSrc);
83
84     int numMipLevels = 1;
85     if (mipmapped == GrMipmapped::kYes) {
86         numMipLevels = SkMipmap::ComputeLevelCount(32, 32)+1;
87     }
88
89     for (int i = 0, rectSize = 32; i < numMipLevels; ++i, rectSize /= 2) {
90         SkASSERT(rectSize >= 1);
91
92         canvas->clear(SK_ColorTRANSPARENT);
93
94         SkRect r = SkRect::MakeWH(rectSize, rectSize);
95         canvas->drawImageRect(img, r, sampling, &p);
96
97         SkImageInfo readbackII = SkImageInfo::Make(rectSize, rectSize,
98                                                    kRGBA_8888_SkColorType,
99                                                    kUnpremul_SkAlphaType);
100         SkAutoPixmapStorage actual2;
101         SkAssertResult(actual2.tryAlloc(readbackII));
102         actual2.erase(SkColors::kTransparent);
103
104         bool result = surf->readPixels(actual2, 0, 0);
105         REPORTER_ASSERT(reporter, result);
106
107         SkString str;
108         str.appendf("mip-level %d", i);
109
110         check_solid_pixmap(reporter, expectedColors[i], actual2,
111                            GrCompressionTypeToStr(compressionType), label, str.c_str());
112     }
113 }
114
115 // Verify that we can readback from a compressed texture
116 static void check_readback(GrDirectContext* dContext, sk_sp<SkImage> img,
117                            SkImage::CompressionType compressionType,
118                            const SkColor4f& expectedColor,
119                            skiatest::Reporter* reporter, const char* label) {
120 #ifdef SK_BUILD_FOR_IOS
121     // reading back ETC2 is broken on Metal/iOS (skbug.com/9839)
122     if (dContext->backend() == GrBackendApi::kMetal) {
123       return;
124     }
125 #endif
126
127     SkAutoPixmapStorage actual;
128
129     SkImageInfo readBackII = SkImageInfo::Make(img->width(), img->height(),
130                                                kRGBA_8888_SkColorType,
131                                                kUnpremul_SkAlphaType);
132
133     SkAssertResult(actual.tryAlloc(readBackII));
134     actual.erase(SkColors::kTransparent);
135
136     bool result = img->readPixels(dContext, actual, 0, 0);
137     REPORTER_ASSERT(reporter, result);
138
139     check_solid_pixmap(reporter, expectedColor, actual,
140                        GrCompressionTypeToStr(compressionType), label, "");
141 }
142
143 // Test initialization of compressed GrBackendTextures to a specific color
144 static void test_compressed_color_init(GrDirectContext* dContext,
145                                        skiatest::Reporter* reporter,
146                                        std::function<GrBackendTexture (GrDirectContext*,
147                                                                        const SkColor4f&,
148                                                                        GrMipmapped)> create,
149                                        const SkColor4f& color,
150                                        SkImage::CompressionType compression,
151                                        GrMipmapped mipmapped) {
152     GrBackendTexture backendTex = create(dContext, color, mipmapped);
153     if (!backendTex.isValid()) {
154         return;
155     }
156
157     sk_sp<SkImage> img = create_image(dContext, backendTex);
158     if (!img) {
159         return;
160     }
161
162     SkColor4f expectedColors[6] = { color, color, color, color, color, color };
163
164     check_compressed_mipmaps(dContext, img, compression, expectedColors, mipmapped,
165                              reporter, "colorinit");
166     check_readback(dContext, img, compression, color, reporter, "solid readback");
167
168     SkColor4f newColor;
169     newColor.fR = color.fB;
170     newColor.fG = color.fR;
171     newColor.fB = color.fG;
172     newColor.fA = color.fA;
173
174     bool result = dContext->updateCompressedBackendTexture(backendTex, newColor, nullptr, nullptr);
175     // Since we were able to create the compressed texture we should be able to update it.
176     REPORTER_ASSERT(reporter, result);
177
178     SkColor4f expectedNewColors[6] = {newColor, newColor, newColor, newColor, newColor, newColor};
179
180     check_compressed_mipmaps(dContext, img, compression, expectedNewColors, mipmapped, reporter,
181                              "colorinit");
182     check_readback(dContext, std::move(img), compression, newColor, reporter, "solid readback");
183
184     dContext->deleteBackendTexture(backendTex);
185 }
186
187 // Create compressed data pulling the color for each mipmap level from 'levelColors'.
188 static std::unique_ptr<const char[]> make_compressed_data(SkImage::CompressionType compression,
189                                                           SkColor4f levelColors[6],
190                                                           GrMipmapped mipmapped) {
191     SkISize dimensions { 32, 32 };
192
193     int numMipLevels = 1;
194     if (mipmapped == GrMipmapped::kYes) {
195         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
196     }
197
198     SkTArray<size_t> mipMapOffsets(numMipLevels);
199
200     size_t dataSize = SkCompressedDataSize(compression, dimensions, &mipMapOffsets,
201                                            mipmapped == GrMipmapped::kYes);
202     char* data = new char[dataSize];
203
204     for (int level = 0; level < numMipLevels; ++level) {
205         // We have to do this a level at a time bc we might have a different color for
206         // each level
207         GrFillInCompressedData(compression, dimensions,
208                                GrMipmapped::kNo, &data[mipMapOffsets[level]], levelColors[level]);
209
210         dimensions = {std::max(1, dimensions.width() /2), std::max(1, dimensions.height()/2)};
211     }
212
213     return std::unique_ptr<const char[]>(data);
214 }
215
216 // Verify that we can initialize a compressed backend texture with data (esp.
217 // the mipmap levels).
218 static void test_compressed_data_init(GrDirectContext* dContext,
219                                       skiatest::Reporter* reporter,
220                                       std::function<GrBackendTexture (GrDirectContext*,
221                                                                       const char* data,
222                                                                       size_t dataSize,
223                                                                       GrMipmapped)> create,
224                                       SkImage::CompressionType compression,
225                                       GrMipmapped mipmapped) {
226
227     SkColor4f expectedColors[6] = {
228         { 1.0f, 0.0f, 0.0f, 1.0f }, // R
229         { 0.0f, 1.0f, 0.0f, 1.0f }, // G
230         { 0.0f, 0.0f, 1.0f, 1.0f }, // B
231         { 0.0f, 1.0f, 1.0f, 1.0f }, // C
232         { 1.0f, 0.0f, 1.0f, 1.0f }, // M
233         { 1.0f, 1.0f, 0.0f, 1.0f }, // Y
234     };
235
236     std::unique_ptr<const char[]> data(make_compressed_data(compression, expectedColors,
237                                                             mipmapped));
238     size_t dataSize = SkCompressedDataSize(compression, { 32, 32 }, nullptr,
239                                            mipmapped == GrMipmapped::kYes);
240
241     GrBackendTexture backendTex = create(dContext, data.get(), dataSize, mipmapped);
242     if (!backendTex.isValid()) {
243         return;
244     }
245
246     sk_sp<SkImage> img = create_image(dContext, backendTex);
247     if (!img) {
248         return;
249     }
250
251     check_compressed_mipmaps(dContext, img, compression, expectedColors,
252                              mipmapped, reporter, "pixmap");
253     check_readback(dContext, img, compression, expectedColors[0], reporter, "data readback");
254
255     SkColor4f expectedColorsNew[6] = {
256         {1.0f, 1.0f, 0.0f, 1.0f},  // Y
257         {1.0f, 0.0f, 0.0f, 1.0f},  // R
258         {0.0f, 1.0f, 0.0f, 1.0f},  // G
259         {0.0f, 0.0f, 1.0f, 1.0f},  // B
260         {0.0f, 1.0f, 1.0f, 1.0f},  // C
261         {1.0f, 0.0f, 1.0f, 1.0f},  // M
262     };
263
264     std::unique_ptr<const char[]> dataNew(
265             make_compressed_data(compression, expectedColorsNew, mipmapped));
266     size_t dataNewSize =
267             SkCompressedDataSize(compression, {32, 32}, nullptr, mipmapped == GrMipmapped::kYes);
268
269     bool result = dContext->updateCompressedBackendTexture(backendTex, dataNew.get(), dataNewSize,
270                                                            nullptr, nullptr);
271     // Since we were able to create the compressed texture we should be able to update it.
272     REPORTER_ASSERT(reporter, result);
273
274     check_compressed_mipmaps(dContext, img, compression, expectedColorsNew, mipmapped, reporter,
275                              "pixmap");
276     check_readback(dContext, std::move(img), compression, expectedColorsNew[0], reporter,
277                    "data readback");
278
279     dContext->deleteBackendTexture(backendTex);
280 }
281
282 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CompressedBackendAllocationTest, reporter, ctxInfo) {
283     auto dContext = ctxInfo.directContext();
284     const GrCaps* caps = dContext->priv().caps();
285
286     struct {
287         SkImage::CompressionType fCompression;
288         SkColor4f                fColor;
289     } combinations[] = {
290         { SkImage::CompressionType::kETC2_RGB8_UNORM, SkColors::kRed },
291         { SkImage::CompressionType::kBC1_RGB8_UNORM,  SkColors::kBlue },
292         { SkImage::CompressionType::kBC1_RGBA8_UNORM, SkColors::kTransparent },
293     };
294
295     for (auto combo : combinations) {
296         GrBackendFormat format = dContext->compressedBackendFormat(combo.fCompression);
297         if (!format.isValid()) {
298             continue;
299         }
300
301         if (!caps->isFormatTexturable(format, GrTextureType::k2D)) {
302             continue;
303         }
304
305         for (auto mipmapped : { GrMipmapped::kNo, GrMipmapped::kYes }) {
306             if (GrMipmapped::kYes == mipmapped && !caps->mipmapSupport()) {
307                 continue;
308             }
309
310             // color initialized
311             {
312                 auto createWithColorMtd = [format](GrDirectContext* dContext,
313                                                    const SkColor4f& color,
314                                                    GrMipmapped mipmapped) {
315                     return dContext->createCompressedBackendTexture(32, 32, format, color,
316                                                                     mipmapped, GrProtected::kNo);
317                 };
318
319                 test_compressed_color_init(dContext, reporter, createWithColorMtd,
320                                            combo.fColor, combo.fCompression, mipmapped);
321             }
322
323             // data initialized
324             {
325                 auto createWithDataMtd = [format](GrDirectContext* dContext,
326                                                   const char* data, size_t dataSize,
327                                                   GrMipmapped mipmapped) {
328                     return dContext->createCompressedBackendTexture(32, 32, format, data, dataSize,
329                                                                     mipmapped, GrProtected::kNo);
330                 };
331
332                 test_compressed_data_init(dContext, reporter, createWithDataMtd,
333                                           combo.fCompression, mipmapped);
334             }
335
336         }
337     }
338 }