Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
bc1_transparency.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
8#include "gm/gm.h"
21
22constexpr int kImgWidth = 16;
23constexpr int kImgHeight = 8;
24constexpr int kPad = 4;
25
26struct BC1Block {
27 uint16_t fColor0;
28 uint16_t fColor1;
29 uint32_t fIndices;
30};
31
32static int num_4x4_blocks(int size) {
33 return ((size + 3) & ~3) >> 2;
34}
35
36static uint16_t to565(SkColor col) {
37 int r5 = SkMulDiv255Round(31, SkColorGetR(col));
38 int g6 = SkMulDiv255Round(63, SkColorGetG(col));
39 int b5 = SkMulDiv255Round(31, SkColorGetB(col));
40
41 return (r5 << 11) | (g6 << 5) | b5;
42}
43
44// BC1 has per-block transparency. If, taken as ints,
45// fColor0 < fColor1 -> the block has transparency (& it is in color3)
46// fColor1 > fColor0 -> the block is opaque
47//
48// This method can create two blocks to test out BC1's behavior. If BC1
49// behaves as expected (i.e., w/ per-block transparency) then, for RGBA textures,
50// the transparent block(s) should appear as:
51// opaque black, medium grey, transparent black, white.
52// and the opaque block(s) should appear as:
53// opaque black, dark grey, light grey, white
54//
55// For RGB textures, however, the transparent block(s) should appear as:
56// opaque black, medium grey, _opaque_ black, white
57// and the opaque block(s) should appear as:
58// opaque black, dark grey, light grey, white.
59static void create_BC1_block(BC1Block* block, bool transparent) {
60 unsigned int byte;
61
62 if (transparent) {
63 block->fColor0 = to565(SK_ColorBLACK);
64 block->fColor1 = to565(SK_ColorWHITE);
65 SkASSERT(block->fColor0 <= block->fColor1); // this signals a transparent block
66 // opaque black (col0), medium grey (col2), transparent black (col3), white (col1).
67 byte = (0x0 << 0) | (0x2 << 2) | (0x3 << 4) | (0x1 << 6);
68 } else {
69 block->fColor0 = to565(SK_ColorWHITE);
70 block->fColor1 = to565(SK_ColorBLACK);
71 SkASSERT(block->fColor0 > block->fColor1); // this signals an opaque block
72 // opaque black (col1), dark grey (col3), light grey (col2), white (col0)
73 byte = (0x1 << 0) | (0x3 << 2) | (0x2 << 4) | (0x0 << 6);
74 }
75
76 block->fIndices = (byte << 24) | (byte << 16) | (byte << 8) | byte;
77}
78
79// This makes a 16x8 BC1 texture which has the top 4 rows be officially transparent
80// and the bottom 4 rows be officially opaque.
83
85 nullptr, false);
86
88 BC1Block* dstBlocks = reinterpret_cast<BC1Block*>(tmp->writable_data());
89
90 BC1Block transBlock, opaqueBlock;
91 create_BC1_block(&transBlock, true);
92 create_BC1_block(&opaqueBlock, false);
93
94 int numXBlocks = num_4x4_blocks(kImgWidth);
95 int numYBlocks = num_4x4_blocks(kImgHeight);
96
97 for (int y = 0; y < numYBlocks; ++y) {
98 for (int x = 0; x < numXBlocks; ++x) {
99 dstBlocks[y*numXBlocks + x] = (y < numYBlocks/2) ? transBlock : opaqueBlock;
100 }
101 }
102
103 return tmp;
104}
105
107 SkTextureCompressionType compression) {
108 if (direct) {
110 direct, std::move(data), kImgWidth, kImgHeight, compression, skgpu::Mipmapped::kNo);
111 } else {
113 std::move(data), kImgWidth, kImgHeight, compression);
114 }
115}
116
117static void draw_image(SkCanvas* canvas, sk_sp<SkImage> image, int x, int y) {
118
119 bool isCompressed = false;
120 if (image && image->isTextureBacked()) {
121 const GrCaps* caps = as_IB(image)->context()->priv().caps();
123 canvas->recordingContext());
124 isCompressed = caps->isFormatCompressed(proxy->backendFormat());
125 }
126
127 canvas->drawImage(image, x, y);
128
129 if (!isCompressed) {
131 r.outset(1.0f, 1.0f);
132
133 SkPaint redStroke;
134 redStroke.setColor(SK_ColorRED);
136 redStroke.setStrokeWidth(2.0f);
137
138 canvas->drawRect(r, redStroke);
139 }
140}
141
142namespace skiagm {
143
144// This GM draws the BC1 compressed texture filled with "make_compressed_data"s data twice.
145//
146// It is drawn once (on the top) as a kBC1_RGB8_UNORM texture and then again (on the bottom)
147// as a kBC1_RGBA8_UNORM texture.
148//
149// If BC1 behaves as expected we should see:
150//
151// RGB8 Black MidGrey Black* White ...
152// Black DrkGrey LtGrey White ...
153//
154// RGBA8 Black MidGrey Green+ White ...
155// Black DrkGrey LtGrey White ...
156//
157// * We expect this to be black bc the transparent black will be forced to opaque. If BC1 were
158// treating it as an opaque block then it would be LtGrey - not black.
159// + This is just the background showing through the transparent black
160class BC1TransparencyGM : public GM {
161public:
165
166protected:
167 SkString getName() const override { return SkString("bc1_transparency"); }
168
169 SkISize getISize() override {
170 return SkISize::Make(kImgWidth + 2 * kPad, 2 * kImgHeight + 3 * kPad);
171 }
172
174 auto dContext = GrAsDirectContext(canvas->recordingContext());
175 if (dContext && dContext->abandoned()) {
176 // This isn't a GpuGM so a null 'context' is okay but an abandoned context
177 // if forbidden.
178 return DrawResult::kSkip;
179 }
180
182
183 fRGBImage = data_to_img(dContext, bc1Data, SkTextureCompressionType::kBC1_RGB8_UNORM);
184 fRGBAImage = data_to_img(dContext, std::move(bc1Data),
186 if (!fRGBImage || !fRGBAImage) {
187 *errorMsg = "Failed to create BC1 images.";
188 return DrawResult::kFail;
189 }
190
191 return DrawResult::kOk;
192 }
193
194 void onGpuTeardown() override {
195 fRGBImage = nullptr;
196 fRGBAImage = nullptr;
197 }
198
199 void onDraw(SkCanvas* canvas) override {
200 draw_image(canvas, fRGBImage, kPad, kPad);
201 draw_image(canvas, fRGBAImage, kPad, 2 * kPad + kImgHeight);
202 }
203
204private:
205 sk_sp<SkImage> fRGBImage;
206 sk_sp<SkImage> fRGBAImage;
207
208 using INHERITED = GM;
209};
210
211//////////////////////////////////////////////////////////////////////////////
212
213DEF_GM(return new BC1TransparencyGM;)
214} // namespace skiagm
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
static void draw_image(SkCanvas *canvas, SkImage *img)
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkColorGetR(color)
Definition SkColor.h:65
#define SkColorGetG(color)
Definition SkColor.h:69
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
#define SkColorGetB(color)
Definition SkColor.h:73
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
size_t SkCompressedDataSize(SkTextureCompressionType type, SkISize dimensions, TArray< size_t > *individualMipOffsets, bool mipmapped)
static SkImage_Base * as_IB(SkImage *image)
static U8CPU SkMulDiv255Round(U16CPU a, U16CPU b)
Definition SkMath.h:73
constexpr int kPad
static uint16_t to565(SkColor col)
static int num_4x4_blocks(int size)
constexpr int kImgWidth
static sk_sp< SkImage > data_to_img(GrDirectContext *direct, sk_sp< SkData > data, SkTextureCompressionType compression)
static sk_sp< SkData > make_compressed_data()
constexpr int kImgHeight
static void create_BC1_block(BC1Block *block, bool transparent)
static void draw_image(SkCanvas *canvas, sk_sp< SkImage > image, int x, int y)
const GrCaps * caps() const
bool isFormatCompressed(const GrBackendFormat &format) const
Definition GrCaps.cpp:457
GrImageContextPriv priv()
const GrBackendFormat & backendFormat() const
void drawRect(const SkRect &rect, const SkPaint &paint)
virtual GrRecordingContext * recordingContext() const
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
virtual GrImageContext * context() const
virtual bool isTextureBacked() const =0
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
void setStrokeWidth(SkScalar width)
Definition SkPaint.cpp:159
T * get() const
Definition SkRefCnt.h:303
SkString getName() const override
void onDraw(SkCanvas *canvas) override
DrawResult onGpuSetup(SkCanvas *canvas, SkString *errorMsg, GraphiteTestContext *) override
void setBGColor(SkColor)
Definition gm.cpp:159
sk_sp< SkImage > image
Definition examples.cpp:29
#define DEF_GM(CODE)
Definition gm.h:40
double y
double x
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)
GrTextureProxy * GetTextureImageProxy(SkImage *image, GrRecordingContext *rContext)
DrawResult
Definition gm.h:104
uint16_t fColor0
uint32_t fIndices
uint16_t fColor1
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
void outset(float dx, float dy)
Definition SkRect.h:1077
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659