Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
compressed_textures.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
9
10#if !defined(SK_BUILD_FOR_GOOGLE3) // Google3 doesn't have etc1.h
11
12#include "gm/gm.h"
16#include "include/core/SkData.h"
19#include "include/core/SkPath.h"
20#include "include/core/SkRect.h"
22#include "include/core/SkSize.h"
29#include "src/core/SkMipmap.h"
38
39#if defined(SK_GRAPHITE)
46#endif
47
48static SkPoint gen_pt(float angle, const SkVector& scale) {
49 SkScalar s = SkScalarSin(angle);
50 SkScalar c = SkScalarCos(angle);
51
52 return { scale.fX * c, scale.fY * s };
53}
54
55// The resulting path will be centered at (0,0) and its size will match 'dimensions'
56static SkPath make_gear(SkISize dimensions, int numTeeth) {
57 SkVector outerRad{ dimensions.fWidth / 2.0f, dimensions.fHeight / 2.0f };
58 SkVector innerRad{ dimensions.fWidth / 2.5f, dimensions.fHeight / 2.5f };
59 const float kAnglePerTooth = 2.0f * SK_ScalarPI / (3 * numTeeth);
60
61 float angle = 0.0f;
62
63 SkPath tmp;
65
66 tmp.moveTo(gen_pt(angle, outerRad));
67
68 for (int i = 0; i < numTeeth; ++i, angle += 3*kAnglePerTooth) {
69 tmp.lineTo(gen_pt(angle+kAnglePerTooth, outerRad));
70 tmp.lineTo(gen_pt(angle+(1.5f*kAnglePerTooth), innerRad));
71 tmp.lineTo(gen_pt(angle+(2.5f*kAnglePerTooth), innerRad));
72 tmp.lineTo(gen_pt(angle+(3.0f*kAnglePerTooth), outerRad));
73 }
74
75 tmp.close();
76
77 float fInnerRad = 0.1f * std::min(dimensions.fWidth, dimensions.fHeight);
78 if (fInnerRad > 0.5f) {
79 tmp.addCircle(0.0f, 0.0f, fInnerRad, SkPathDirection::kCCW);
80 }
81
82 return tmp;
83}
84
85// Render one level of a mipmap
87 SkPath path = make_gear(dimensions, 9);
88
89 SkImageInfo ii = SkImageInfo::Make(dimensions.width(), dimensions.height(),
92 SkBitmap bm;
93 bm.allocPixels(ii);
94
96
97 SkCanvas c(bm);
98
100 paint.setColor(color | 0xFF000000);
101 paint.setAntiAlias(false);
102
103 c.translate(dimensions.width() / 2.0f, dimensions.height() / 2.0f);
104 c.drawPath(path, paint);
105
106 return bm;
107}
108
111#if defined(SK_GRAPHITE)
113#else
114 void* fGraphiteTexture = nullptr;
115#endif
116};
117
118// Create the compressed data blob needed to represent a mipmapped 2-color texture of the specified
119// compression format. In this case 2-color means either opaque black or transparent black plus
120// one other color.
121// Note that ETC1/ETC2_RGB8_UNORM only supports 565 opaque textures.
123 const SkISize dimensions,
125 bool opaque,
126 SkTextureCompressionType compression) {
127 size_t totalSize = SkCompressedDataSize(compression, dimensions, nullptr, true);
128
130 char* pixels = (char*) tmp->writable_data();
131
132 int numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
133
134 size_t offset = 0;
135
136 // Use a different color for each mipmap level so we can visually evaluate the draws
137 static const SkColor kColors[] = {
145 };
146
147 SkISize levelDims = dimensions;
148 for (int i = 0; i < numMipLevels; ++i) {
149 size_t levelSize = SkCompressedDataSize(compression, levelDims, nullptr, false);
150
151 SkBitmap bm = render_level(levelDims, kColors[i%7], colorType, opaque);
154 SkASSERT(opaque);
155
156 if (etc1_encode_image((unsigned char*)bm.getAddr16(0, 0),
157 bm.width(), bm.height(), 2, bm.rowBytes(),
158 (unsigned char*) &pixels[offset])) {
159 return {nullptr, nullptr};
160 }
161 } else {
162 GrTwoColorBC1Compress(bm.pixmap(), kColors[i%7], &pixels[offset]);
163 }
164
165 offset += levelSize;
166 levelDims = {std::max(1, levelDims.width()/2), std::max(1, levelDims.height()/2)};
167 }
168
170#if defined(SK_GRAPHITE)
171 skgpu::graphite::Recorder* recorder = canvas->recorder();
172 if (recorder) {
174 sk_gpu_test::ManagedGraphiteTexture::MakeFromCompressedData(recorder,
175 dimensions,
176 compression,
177 tmp,
179 if (texture) {
180 image = SkImages::WrapTexture(recorder,
181 texture->texture(),
184 /*colorSpace=*/nullptr);
185 if (image) {
186 return {image, texture};
187 }
188 }
189 }
190#endif
191 auto dContext = GrAsDirectContext(canvas->recordingContext());
192 if (dContext) {
194 std::move(tmp),
195 dimensions.width(),
196 dimensions.height(),
197 compression,
199 } else {
201 std::move(tmp), dimensions.width(), dimensions.height(), compression);
202 }
203 return {image, nullptr};
204}
205
206// Basic test of Ganesh's ETC1 and BC1 support
207// The layout is:
208// ETC2 BC1
209// --------------------------------------
210// RGB8 | kETC2_RGB8_UNORM | kBC1_RGB8_UNORM |
211// |--------------------------------------|
212// RGBA8 | | kBC1_RGBA8_UNORM |
213// --------------------------------------
214//
215// The nonPowerOfTwo and nonMultipleOfFour cases exercise some compression edge cases.
217public:
218 enum class Type {
219 kNormal,
220 kNonPowerOfTwo,
221 kNonMultipleOfFour
222 };
223
225 this->setBGColor(0xFFCCCCCC);
226
227 switch (fType) {
229 // These dimensions force the top two mip levels to be 1x3 and 1x1
230 fImgDimensions.set(20, 60);
231 break;
233 // These dimensions force the top three mip levels to be 1x7, 1x3 and 1x1
234 fImgDimensions.set(13, 61); // prime numbers - just bc
235 break;
236 default:
237 fImgDimensions.set(kBaseTexWidth, kBaseTexHeight);
238 break;
239 }
240
241 }
242
243protected:
244 SkString getName() const override {
245 SkString name("compressed_textures");
246
247 if (fType == Type::kNonPowerOfTwo) {
248 name.append("_npot");
249 } else if (fType == Type::kNonMultipleOfFour) {
250 name.append("_nmof");
251 }
252
253 return name;
254 }
255
256 SkISize getISize() override {
257 return SkISize::Make(2*kCellWidth + 3*kPad, 2*kBaseTexHeight + 3*kPad);
258 }
259
262 auto dContext = GrAsDirectContext(canvas->recordingContext());
263 if (dContext && dContext->abandoned()) {
264 // This isn't a GpuGM so a null 'context' is okay but an abandoned context
265 // if forbidden.
266 return DrawResult::kSkip;
267 }
268
269 if (dContext &&
270 dContext->backend() == GrBackendApi::kDirect3D && fType == Type::kNonMultipleOfFour) {
271 // skbug.com/10541 - Are non-multiple-of-four BC1 textures supported in D3D?
272 return DrawResult::kSkip;
273 }
274
275 fOpaqueETC2Image = make_compressed_image(canvas, fImgDimensions,
278
279 fOpaqueBC1Image = make_compressed_image(canvas, fImgDimensions,
282
283 fTransparentBC1Image = make_compressed_image(canvas, fImgDimensions,
286
287 if (!fOpaqueETC2Image.fImage || !fOpaqueBC1Image.fImage || !fTransparentBC1Image.fImage) {
288 *errorMsg = "Failed to create compressed images.";
289 return DrawResult::kFail;
290 }
291
292 return DrawResult::kOk;
293 }
294
295 void onGpuTeardown() override {
296 fOpaqueETC2Image.fImage = nullptr;
297 fOpaqueBC1Image.fImage = nullptr;
298 fTransparentBC1Image.fImage = nullptr;
299 fOpaqueETC2Image.fGraphiteTexture = nullptr;
300 fOpaqueBC1Image.fGraphiteTexture = nullptr;
301 fTransparentBC1Image.fGraphiteTexture = nullptr;
302 }
303
304 void onDraw(SkCanvas* canvas) override {
305 this->drawCell(canvas, fOpaqueETC2Image.fImage.get(), { kPad, kPad });
306
307 this->drawCell(canvas, fOpaqueBC1Image.fImage.get(), { 2*kPad + kCellWidth, kPad });
308
309 this->drawCell(canvas, fTransparentBC1Image.fImage.get(),
310 { 2*kPad + kCellWidth, 2*kPad + kBaseTexHeight });
311 }
312
313private:
314 void drawCell(SkCanvas* canvas, SkImage* image, SkIVector offset) {
315
316 SkISize levelDimensions = fImgDimensions;
317 int numMipLevels = SkMipmap::ComputeLevelCount(levelDimensions.width(),
318 levelDimensions.height()) + 1;
319
321
322 bool isCompressed = false;
323 if (image->isTextureBacked()) {
324 auto dContext = GrAsDirectContext(canvas->recordingContext());
325 if (dContext) {
326 const GrCaps* caps = as_IB(image)->context()->priv().caps();
328 image, canvas->recordingContext());
329 isCompressed = caps->isFormatCompressed(proxy->backendFormat());
330 } else {
331 // Graphite has no fallback to upload the compressed data to a non-compressed
332 // format. So if the image is texture backed and graphite then it will be a
333 // compressed format.
334 isCompressed = true;
335 }
336 }
337
338 SkPaint redStrokePaint;
339 redStrokePaint.setColor(SK_ColorRED);
340 redStrokePaint.setStyle(SkPaint::kStroke_Style);
341
342 for (int i = 0; i < numMipLevels; ++i) {
344 levelDimensions.width(), levelDimensions.height());
345
346 canvas->drawImageRect(image, r, sampling);
347 if (!isCompressed) {
348 // Make it obvious which drawImages used decompressed images
349 canvas->drawRect(r, redStrokePaint);
350 }
351
352 if (i == 0) {
353 offset.fX += levelDimensions.width()+1;
354 } else {
355 offset.fY += levelDimensions.height()+1;
356 }
357
358 levelDimensions = {std::max(1, levelDimensions.width()/2),
359 std::max(1, levelDimensions.height()/2)};
360 }
361 }
362
363 static const int kPad = 8;
364 static const int kBaseTexWidth = 64;
365 static const int kCellWidth = 1.5f * kBaseTexWidth;
366 static const int kBaseTexHeight = 64;
367
368 Type fType;
369 SkISize fImgDimensions;
370
371
372 CompressedImageObjects fOpaqueETC2Image;
373 CompressedImageObjects fOpaqueBC1Image;
374 CompressedImageObjects fTransparentBC1Image;
375
376 using INHERITED = GM;
377};
378
379//////////////////////////////////////////////////////////////////////////////
380
384
385#endif
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
@ 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
SkColorType
Definition: SkColorType.h:19
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
constexpr SkColor SK_ColorYELLOW
Definition: SkColor.h:139
constexpr SkColor SK_ColorMAGENTA
Definition: SkColor.h:147
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition: SkColor.h:143
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
size_t SkCompressedDataSize(SkTextureCompressionType type, SkISize dimensions, TArray< size_t > *individualMipOffsets, bool mipmapped)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static SkImage_Base * as_IB(SkImage *image)
Definition: SkImage_Base.h:201
#define SkScalarSin(radians)
Definition: SkScalar.h:45
#define SkScalarCos(radians)
Definition: SkScalar.h:46
#define SK_ScalarPI
Definition: SkScalar.h:21
SkTextureCompressionType
GLenum type
DrawResult onGpuSetup(SkCanvas *canvas, SkString *errorMsg, GraphiteTestContext *graphiteTestContext) override
SkString getName() const override
SkISize getISize() override
void onDraw(SkCanvas *canvas) override
const GrCaps * caps() const
Definition: GrCaps.h:57
bool isFormatCompressed(const GrBackendFormat &format) const
Definition: GrCaps.cpp:457
GrImageContextPriv priv()
const GrBackendFormat & backendFormat() const
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
int width() const
Definition: SkBitmap.h:149
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
size_t rowBytes() const
Definition: SkBitmap.h:238
SkColorType colorType() const
Definition: SkBitmap.h:160
int height() const
Definition: SkBitmap.h:158
uint16_t * getAddr16(int x, int y) const
Definition: SkBitmap.h:1265
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
virtual GrRecordingContext * recordingContext() const
Definition: SkCanvas.cpp:1637
virtual skgpu::graphite::Recorder * recorder() const
Definition: SkCanvas.cpp:1641
void drawImageRect(const SkImage *, const SkRect &src, const SkRect &dst, const SkSamplingOptions &, const SkPaint *, SrcRectConstraint)
Definition: SkCanvas.cpp:2333
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
void * writable_data()
Definition: SkData.h:52
virtual GrImageContext * context() const
Definition: SkImage_Base.h:112
virtual bool isTextureBacked() const =0
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setColor(SkColor color)
Definition: SkPaint.cpp:119
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
Definition: SkPath.h:59
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1213
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & lineTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:728
SkPath & close()
Definition: SkPath.cpp:823
T * get() const
Definition: SkRefCnt.h:303
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
GraphiteTestContext * graphiteTestContext() const
Definition: gm.h:228
void setBGColor(SkColor)
Definition: gm.cpp:159
const Paint & paint
Definition: color_source.cc:38
static SkPoint gen_pt(float angle, const SkVector &scale)
static SkPath make_gear(SkISize dimensions, int numTeeth)
SkBitmap render_level(SkISize dimensions, SkColor color, SkColorType colorType, bool opaque)
static CompressedImageObjects make_compressed_image(SkCanvas *canvas, const SkISize dimensions, SkColorType colorType, bool opaque, SkTextureCompressionType compression)
DlColor color
@ kNormal
Default priority level.
Definition: embedder.h:262
int etc1_encode_image(const etc1_byte *pIn, etc1_uint32 width, etc1_uint32 height, etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte *pOut)
Definition: etc1.cpp:517
float SkScalar
Definition: extension.cpp:12
struct MyStruct s
#define DEF_GM(CODE)
Definition: gm.h:40
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
FlTexture * texture
SK_API sk_sp< SkImage > WrapTexture(skgpu::graphite::Recorder *, const skgpu::graphite::BackendTexture &, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, skgpu::Origin origin, GenerateMipmapsFromBase generateMipmapsFromBase, TextureReleaseProc=nullptr, ReleaseContext=nullptr, std::string_view label={})
SK_API sk_sp< SkImage > TextureFromCompressedTextureData(GrDirectContext *direct, sk_sp< SkData > data, int width, int height, SkTextureCompressionType type, skgpu::Mipmapped mipmapped=skgpu::Mipmapped::kNo, GrProtected isProtected=GrProtected::kNo)
SK_API sk_sp< SkImage > RasterFromCompressedTextureData(sk_sp< SkData > data, int width, int height, SkTextureCompressionType type)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SkSamplingOptions sampling
Definition: SkRecords.h:337
const DlColor kColors[]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
GrTextureProxy * GetTextureImageProxy(SkImage *image, GrRecordingContext *rContext)
Definition: ProxyUtils.cpp:32
static constexpr SkColorType CompressionTypeToSkColorType(SkTextureCompressionType compression)
Definition: GpuTypesPriv.h:30
DrawResult
Definition: gm.h:104
const Scalar scale
SeparatedVector2 offset
static constexpr SkCubicResampler Mitchell()
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
void set(int32_t w, int32_t h)
Definition: SkSize.h:24
constexpr int32_t height() const
Definition: SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659