Flutter Engine
The Flutter Engine
CompressedBackendAllocationTest.cpp
Go to the documentation of this file.
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
17#include "include/core/SkRect.h"
20#include "include/core/SkSize.h"
28#include "include/gpu/GrTypes.h"
35#include "src/core/SkMipmap.h"
36#include "src/gpu/DataUtils.h"
43#include "tests/Test.h"
44#include "tests/TestUtils.h"
45
46#include <algorithm>
47#include <cstddef>
48#include <functional>
49#include <initializer_list>
50#include <memory>
51#include <utility>
52
53using namespace skia_private;
54
56class SkPixmap;
57struct GrContextOptions;
58
59// Just verify that 'actual' is entirely 'expected'
61 const SkColor4f& expected, const SkPixmap& actual,
62 const char* label0, const char* label1, const char* label2) {
63 const float tols[4] = { 0.01f, 0.01f, 0.01f, 0.01f };
64
65 auto error = std::function<ComparePixmapsErrorReporter>(
66 [reporter, label0, label1, label2](int x, int y, const float diffs[4]) {
67 SkASSERT(x >= 0 && y >= 0);
68 ERRORF(reporter, "%s %s %s - mismatch at %d, %d (%f, %f, %f %f)",
69 label0, label1, label2, x, y,
70 diffs[0], diffs[1], diffs[2], diffs[3]);
71 });
72
73 CheckSolidPixels(expected, actual, tols, error);
74}
75
76// Create an SkImage to wrap 'backendTex'
78 SkTextureCompressionType compression =
80
83
85 dContext, backendTex, kTopLeft_GrSurfaceOrigin, at, nullptr);
86}
87
88// Draw the compressed backend texture (wrapped in an SkImage) into an RGBA surface, attempting
89// to access all the mipMap levels.
92 SkTextureCompressionType compressionType,
93 const SkColor4f expectedColors[6],
94 skgpu::Mipmapped mipmapped,
96 const char* label) {
97 SkImageInfo readbackSurfaceII = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType,
99
102 readbackSurfaceII,
103 1,
105 nullptr);
106 if (!surf) {
107 return;
108 }
109
110 SkCanvas* canvas = surf->getCanvas();
111
112 // Given that we bias LOD selection with MIP maps, hitting a level exactly using
113 // SkMipmap::kLinear is difficult so we use kNearest.
116 SkPaint p;
117 p.setBlendMode(SkBlendMode::kSrc);
118
119 int numMipLevels = 1;
120 if (mipmapped == skgpu::Mipmapped::kYes) {
121 numMipLevels = SkMipmap::ComputeLevelCount(32, 32)+1;
122 }
123
124 for (int i = 0, rectSize = 32; i < numMipLevels; ++i, rectSize /= 2) {
125 SkASSERT(rectSize >= 1);
126
127 canvas->clear(SK_ColorTRANSPARENT);
128
129 SkRect r = SkRect::MakeWH(rectSize, rectSize);
130 canvas->drawImageRect(img, r, sampling, &p);
131
132 SkImageInfo readbackII = SkImageInfo::Make(rectSize, rectSize,
135 SkAutoPixmapStorage actual2;
136 SkAssertResult(actual2.tryAlloc(readbackII));
138
139 bool result = surf->readPixels(actual2, 0, 0);
141
142 SkString str;
143 str.appendf("mip-level %d", i);
144
145 check_solid_pixmap(reporter, expectedColors[i], actual2,
146 skgpu::CompressionTypeToStr(compressionType), label, str.c_str());
147 }
148}
149
150// Verify that we can readback from a compressed texture
152 SkTextureCompressionType compressionType,
153 const SkColor4f& expectedColor,
154 skiatest::Reporter* reporter, const char* label) {
155#ifdef SK_BUILD_FOR_IOS
156 // reading back ETC2 is broken on Metal/iOS (skbug.com/9839)
157 if (dContext->backend() == GrBackendApi::kMetal) {
158 return;
159 }
160#endif
161
162 SkAutoPixmapStorage actual;
163
164 SkImageInfo readBackII = SkImageInfo::Make(img->width(), img->height(),
167
168 SkAssertResult(actual.tryAlloc(readBackII));
170
171 bool result = img->readPixels(dContext, actual, 0, 0);
173
174 check_solid_pixmap(reporter, expectedColor, actual,
175 skgpu::CompressionTypeToStr(compressionType), label, "");
176}
177
178// Test initialization of compressed GrBackendTextures to a specific color
180 GrDirectContext* dContext,
183 create,
184 const SkColor4f& color,
185 SkTextureCompressionType compression,
186 skgpu::Mipmapped mipmapped) {
187 GrBackendTexture backendTex = create(dContext, color, mipmapped);
188 if (!backendTex.isValid()) {
189 return;
190 }
191
192 sk_sp<SkImage> img = create_image(dContext, backendTex);
193 if (!img) {
194 return;
195 }
196
197 SkColor4f expectedColors[6] = { color, color, color, color, color, color };
198
199 check_compressed_mipmaps(dContext, img, compression, expectedColors, mipmapped,
200 reporter, "colorinit");
201 check_readback(dContext, img, compression, color, reporter, "solid readback");
202
203 SkColor4f newColor;
204 newColor.fR = color.fB;
205 newColor.fG = color.fR;
206 newColor.fB = color.fG;
207 newColor.fA = color.fA;
208
209 bool result = dContext->updateCompressedBackendTexture(backendTex, newColor, nullptr, nullptr);
210 // Since we were able to create the compressed texture we should be able to update it.
212
213 SkColor4f expectedNewColors[6] = {newColor, newColor, newColor, newColor, newColor, newColor};
214
215 check_compressed_mipmaps(dContext, img, compression, expectedNewColors, mipmapped, reporter,
216 "colorinit");
217 check_readback(dContext, std::move(img), compression, newColor, reporter, "solid readback");
218
219 dContext->deleteBackendTexture(backendTex);
220}
221
222// Create compressed data pulling the color for each mipmap level from 'levelColors'.
223static std::unique_ptr<const char[]> make_compressed_data(SkTextureCompressionType compression,
224 SkColor4f levelColors[6],
225 skgpu::Mipmapped mipmapped) {
226 SkISize dimensions { 32, 32 };
227
228 int numMipLevels = 1;
229 if (mipmapped == skgpu::Mipmapped::kYes) {
230 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
231 }
232
233 TArray<size_t> mipMapOffsets(numMipLevels);
234
235 size_t dataSize = SkCompressedDataSize(
236 compression, dimensions, &mipMapOffsets, mipmapped == skgpu::Mipmapped::kYes);
237 char* data = new char[dataSize];
238
239 for (int level = 0; level < numMipLevels; ++level) {
240 // We have to do this a level at a time bc we might have a different color for
241 // each level
242 skgpu::FillInCompressedData(compression,
243 dimensions,
245 &data[mipMapOffsets[level]],
246 levelColors[level]);
247
248 dimensions = {std::max(1, dimensions.width() /2), std::max(1, dimensions.height()/2)};
249 }
250
251 return std::unique_ptr<const char[]>(data);
252}
253
254// Verify that we can initialize a compressed backend texture with data (esp.
255// the mipmap levels).
257 GrDirectContext* dContext,
260 GrDirectContext*, const char* data, size_t dataSize, skgpu::Mipmapped)> create,
261 SkTextureCompressionType compression,
262 skgpu::Mipmapped mipmapped) {
263 SkColor4f expectedColors[6] = {
264 { 1.0f, 0.0f, 0.0f, 1.0f }, // R
265 { 0.0f, 1.0f, 0.0f, 1.0f }, // G
266 { 0.0f, 0.0f, 1.0f, 1.0f }, // B
267 { 0.0f, 1.0f, 1.0f, 1.0f }, // C
268 { 1.0f, 0.0f, 1.0f, 1.0f }, // M
269 { 1.0f, 1.0f, 0.0f, 1.0f }, // Y
270 };
271
272 std::unique_ptr<const char[]> data(make_compressed_data(compression, expectedColors,
273 mipmapped));
274 size_t dataSize = SkCompressedDataSize(
275 compression, {32, 32}, nullptr, mipmapped == skgpu::Mipmapped::kYes);
276
277 GrBackendTexture backendTex = create(dContext, data.get(), dataSize, mipmapped);
278 if (!backendTex.isValid()) {
279 return;
280 }
281
282 sk_sp<SkImage> img = create_image(dContext, backendTex);
283 if (!img) {
284 return;
285 }
286
287 check_compressed_mipmaps(dContext, img, compression, expectedColors,
288 mipmapped, reporter, "pixmap");
289 check_readback(dContext, img, compression, expectedColors[0], reporter, "data readback");
290
291 SkColor4f expectedColorsNew[6] = {
292 {1.0f, 1.0f, 0.0f, 1.0f}, // Y
293 {1.0f, 0.0f, 0.0f, 1.0f}, // R
294 {0.0f, 1.0f, 0.0f, 1.0f}, // G
295 {0.0f, 0.0f, 1.0f, 1.0f}, // B
296 {0.0f, 1.0f, 1.0f, 1.0f}, // C
297 {1.0f, 0.0f, 1.0f, 1.0f}, // M
298 };
299
300 std::unique_ptr<const char[]> dataNew(
301 make_compressed_data(compression, expectedColorsNew, mipmapped));
302 size_t dataNewSize = SkCompressedDataSize(
303 compression, {32, 32}, nullptr, mipmapped == skgpu::Mipmapped::kYes);
304
305 bool result = dContext->updateCompressedBackendTexture(backendTex, dataNew.get(), dataNewSize,
306 nullptr, nullptr);
307 // Since we were able to create the compressed texture we should be able to update it.
309
310 check_compressed_mipmaps(dContext, img, compression, expectedColorsNew, mipmapped, reporter,
311 "pixmap");
312 check_readback(dContext, std::move(img), compression, expectedColorsNew[0], reporter,
313 "data readback");
314
315 dContext->deleteBackendTexture(backendTex);
316}
317
318DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(CompressedBackendAllocationTest,
319 reporter,
320 ctxInfo,
322 auto dContext = ctxInfo.directContext();
323 const GrCaps* caps = dContext->priv().caps();
324
325 struct {
326 SkTextureCompressionType fCompression;
327 SkColor4f fColor;
328 } combinations[] = {
332 };
333
334 for (auto combo : combinations) {
335 GrBackendFormat format = dContext->compressedBackendFormat(combo.fCompression);
336 if (!format.isValid()) {
337 continue;
338 }
339
341 continue;
342 }
343
344 for (auto mipmapped : {skgpu::Mipmapped::kNo, skgpu::Mipmapped::kYes}) {
345 if (skgpu::Mipmapped::kYes == mipmapped && !caps->mipmapSupport()) {
346 continue;
347 }
348
349 // color initialized
350 {
351 auto createWithColorMtd = [format](GrDirectContext* dContext,
352 const SkColor4f& color,
353 skgpu::Mipmapped mipmapped) {
354 return dContext->createCompressedBackendTexture(32, 32, format, color,
355 mipmapped, GrProtected::kNo);
356 };
357
358 test_compressed_color_init(dContext, reporter, createWithColorMtd,
359 combo.fColor, combo.fCompression, mipmapped);
360 }
361
362 // data initialized
363 {
364 auto createWithDataMtd = [format](GrDirectContext* dContext,
365 const char* data,
366 size_t dataSize,
367 skgpu::Mipmapped mipmapped) {
368 return dContext->createCompressedBackendTexture(32, 32, format, data, dataSize,
369 mipmapped, GrProtected::kNo);
370 };
371
372 test_compressed_data_init(dContext, reporter, createWithDataMtd,
373 combo.fCompression, mipmapped);
374 }
375 }
376 }
377}
static std::unique_ptr< const char[]> make_compressed_data(SkTextureCompressionType compression, SkColor4f levelColors[6], skgpu::Mipmapped mipmapped)
static void check_readback(GrDirectContext *dContext, sk_sp< SkImage > img, SkTextureCompressionType compressionType, const SkColor4f &expectedColor, skiatest::Reporter *reporter, const char *label)
static void check_solid_pixmap(skiatest::Reporter *reporter, const SkColor4f &expected, const SkPixmap &actual, const char *label0, const char *label1, const char *label2)
static void check_compressed_mipmaps(GrRecordingContext *rContext, sk_sp< SkImage > img, SkTextureCompressionType compressionType, const SkColor4f expectedColors[6], skgpu::Mipmapped mipmapped, skiatest::Reporter *reporter, const char *label)
static void test_compressed_data_init(GrDirectContext *dContext, skiatest::Reporter *reporter, std::function< GrBackendTexture(GrDirectContext *, const char *data, size_t dataSize, skgpu::Mipmapped)> create, SkTextureCompressionType compression, skgpu::Mipmapped mipmapped)
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(CompressedBackendAllocationTest, reporter, ctxInfo, CtsEnforcement::kApiLevel_T)
sk_sp< SkImage > create_image(GrDirectContext *dContext, const GrBackendTexture &backendTex)
static void test_compressed_color_init(GrDirectContext *dContext, skiatest::Reporter *reporter, std::function< GrBackendTexture(GrDirectContext *, const SkColor4f &, skgpu::Mipmapped)> create, const SkColor4f &color, SkTextureCompressionType compression, skgpu::Mipmapped mipmapped)
reporter
Definition: FontMgrTest.cpp:39
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
SkTextureCompressionType GrBackendFormatToCompressionType(const GrBackendFormat &format)
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
size_t SkCompressedDataSize(SkTextureCompressionType type, SkISize dimensions, TArray< size_t > *individualMipOffsets, bool mipmapped)
static constexpr bool SkTextureCompressionTypeIsOpaque(SkTextureCompressionType compression)
SkTextureCompressionType
bool CheckSolidPixels(const SkColor4f &col, const SkPixmap &pixmap, const float tolRGBA[4], std::function< ComparePixmapsErrorReporter > &error)
Definition: TestUtils.cpp:191
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
GrBackendFormat getBackendFormat() const
bool isValid() const
const GrCaps * caps() const
Definition: GrCaps.h:57
bool mipmapSupport() const
Definition: GrCaps.h:72
virtual bool isFormatTexturable(const GrBackendFormat &, GrTextureType) const =0
SK_API GrBackendApi backend() const
SK_API GrBackendFormat compressedBackendFormat(SkTextureCompressionType) const
bool updateCompressedBackendTexture(const GrBackendTexture &, const SkColor4f &color, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext)
GrBackendTexture createCompressedBackendTexture(int width, int height, const GrBackendFormat &, const SkColor4f &color, skgpu::Mipmapped, GrProtected=GrProtected::kNo, GrGpuFinishedProc finishedProc=nullptr, GrGpuFinishedContext finishedContext=nullptr)
void deleteBackendTexture(const GrBackendTexture &)
GrDirectContextPriv priv()
bool tryAlloc(const SkImageInfo &)
void clear(SkColor color)
Definition: SkCanvas.h:1199
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2333
bool readPixels(GrDirectContext *context, const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY, CachingHint cachingHint=kAllow_CachingHint) const
Definition: SkImage.cpp:42
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
bool erase(SkColor color, const SkIRect &subset) const
Definition: SkPixmap.cpp:742
const char * c_str() const
Definition: SkString.h:133
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
bool readPixels(const SkPixmap &dst, int srcX, int srcY)
Definition: SkSurface.cpp:125
DlColor color
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
uint32_t uint32_t * format
Dart_NativeFunction function
Definition: fuchsia.cc:51
static float max(float r, float g, float b)
Definition: hsl.cpp:49
double y
double x
constexpr SkColor4f kRed
Definition: SkColor.h:440
constexpr SkColor4f kTransparent
Definition: SkColor.h:434
constexpr SkColor4f kBlue
Definition: SkColor.h:442
SK_API sk_sp< SkImage > TextureFromCompressedTexture(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SkSamplingOptions sampling
Definition: SkRecords.h:337
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Definition: create.py:1
void FillInCompressedData(SkTextureCompressionType type, SkISize dimensions, skgpu::Mipmapped mipmapped, char *dstPixels, const SkColor4f &colorf)
Definition: DataUtils.cpp:257
Mipmapped
Definition: GpuTypes.h:53
static constexpr const char * CompressionTypeToStr(SkTextureCompressionType compression)
Definition: GpuTypesPriv.h:41
Definition: SkSize.h:16
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
int_closure create