Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
surface.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2014 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"
13#include "include/core/SkFont.h"
18#include "include/core/SkRect.h"
22#include "include/core/SkSize.h"
34#include "tools/ToolUtils.h"
37
38#define W 800
39#define H 100
40
42 int a = 0x99;
43 int b = 0xBB;
44 SkPoint pts[] = { { 0, 0 }, { W, H } };
45 SkColor colors[] = { SkColorSetRGB(a, a, a), SkColorSetRGB(b, b, b) };
46 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
47}
48
50 const SkImageInfo& info,
52 SkScalar contrast,
53 SkScalar gamma) {
54 SkSurfaceProps props(0, geo, contrast, gamma);
55 if (ctx) {
56 return SkSurfaces::RenderTarget(ctx, skgpu::Budgeted::kNo, info, 0, &props);
57 } else {
58 return SkSurfaces::Raster(info, &props);
59 }
60}
61
62static void test_draw(SkCanvas* canvas, const char label[]) {
64
65 paint.setAntiAlias(true);
66 paint.setDither(true);
67
68 paint.setShader(make_shader());
69 canvas->drawRect(SkRect::MakeWH(W, H), paint);
70 paint.setShader(nullptr);
71
72 paint.setColor(SK_ColorWHITE);
75 SkTextUtils::DrawString(canvas, label, W / 2, H * 3 / 4, font, paint,
77}
78
79class SurfacePropsGM : public skiagm::GM {
80public:
82 recs = {
84 "Unknown geometry, default contrast/gamma",
88 "RGB_H, default contrast/gamma",
92 "BGR_H, default contrast/gamma",
96 "RGB_V, default contrast/gamma",
100 "BGR_V, default contrast/gamma",
103 {kRGB_H_SkPixelGeometry, "RGB_H contrast : 0 gamma: 0", 0, 0},
104 {kRGB_H_SkPixelGeometry, "RGB_H contrast : 1 gamma: 0", 1, 0},
105 {kRGB_H_SkPixelGeometry, "RGB_H contrast : 0 gamma: 3.9", 0, 3.9f},
106 {kRGB_H_SkPixelGeometry, "RGB_H contrast : 1 gamma: 3.9", 1, 3.9f},
107 };
108 }
109
110protected:
111 SkString getName() const override { return SkString("surfaceprops"); }
112
113 SkISize getISize() override { return SkISize::Make(W, H * recs.size()); }
114
115 void onDraw(SkCanvas* canvas) override {
116 auto ctx = canvas->recordingContext();
117
118 // must be opaque to have a hope of testing LCD text
120
121 SkScalar x = 0;
122 SkScalar y = 0;
123 for (const auto& rec : recs) {
124 auto surface(make_surface(ctx, info, rec.fGeo, rec.fContrast, rec.fGamma));
125 if (!surface) {
126 SkDebugf("failed to create surface! label: %s", rec.fLabel);
127 continue;
128 }
129 test_draw(surface->getCanvas(), rec.fLabel);
130 surface->draw(canvas, x, y);
131 y += H;
132 }
133 }
134
135private:
136 struct SurfacePropsInput {
137 SkPixelGeometry fGeo;
138 const char* fLabel;
139 SkScalar fContrast;
141 };
142 std::vector<SurfacePropsInput> recs;
143
144 using INHERITED = GM;
145};
146DEF_GM( return new SurfacePropsGM )
147
148#ifdef SK_DEBUG
149static bool equal(const SkSurfaceProps& a, const SkSurfaceProps& b) {
150 return a == b;
151}
152#endif
153
154class NewSurfaceGM : public skiagm::GM {
155public:
157
158protected:
159 SkString getName() const override { return SkString("surfacenew"); }
160
161 SkISize getISize() override { return SkISize::Make(300, 140); }
162
163 static void drawInto(SkCanvas* canvas) {
164 canvas->drawColor(SK_ColorRED);
165 }
166
167 void onDraw(SkCanvas* canvas) override {
169
170 auto surf(ToolUtils::makeSurface(canvas, info, nullptr));
171 drawInto(surf->getCanvas());
172
173 sk_sp<SkImage> image(surf->makeImageSnapshot());
174 canvas->drawImage(image, 10, 10);
175
176 auto surf2(surf->makeSurface(info));
177 drawInto(surf2->getCanvas());
178
179 // Assert that the props were communicated transitively through the first image
180 SkASSERT(equal(surf->props(), surf2->props()));
181
182 sk_sp<SkImage> image2(surf2->makeImageSnapshot());
183 canvas->drawImage(image2.get(), 10 + SkIntToScalar(image->width()) + 10, 10);
184 }
185
186private:
187 using INHERITED = GM;
188};
189DEF_GM( return new NewSurfaceGM )
190
191///////////////////////////////////////////////////////////////////////////////////////////////////
192
193// The GPU backend may behave differently when images are snapped from wrapped textures and
194// render targets compared.
195namespace {
196enum SurfaceType {
197 kManaged,
200};
201}
202
205 switch (type) {
206 case kManaged:
207 return ToolUtils::makeSurface(canvas, ii);
208 case kBackendTexture:
209 if (!direct) {
210 return nullptr;
211 }
215 ii,
217 1);
218 }
219 return nullptr;
220}
221
222using MakeSurfaceFn = std::function<sk_sp<SkSurface>(const SkImageInfo&)>;
223
224#define DEF_BASIC_SURFACE_TEST(name, canvas, main, W, H) \
225 DEF_SIMPLE_GM(name, canvas, W, H) { \
226 auto make = [canvas](const SkImageInfo& ii) { \
227 return make_surface(ii, canvas, SurfaceType::kManaged); \
228 }; \
229 main(canvas, MakeSurfaceFn(make)); \
230 }
231
232#define DEF_BACKEND_SURFACE_TEST(name, canvas, main, type, W, H) \
233 DEF_SIMPLE_GM_CAN_FAIL(name, canvas, err_msg, W, H) { \
234 GrDirectContext* direct = GrAsDirectContext(canvas->recordingContext()); \
235 if (!direct || direct->abandoned()) { \
236 *err_msg = "Requires non-abandoned GrDirectContext"; \
237 return skiagm::DrawResult::kSkip; \
238 } \
239 auto make = [canvas](const SkImageInfo& ii) { return make_surface(ii, canvas, type); }; \
240 main(canvas, MakeSurfaceFn(make)); \
241 return skiagm::DrawResult::kOk; \
242 }
243
244#define DEF_BET_SURFACE_TEST(name, canvas, main, W, H) \
245 DEF_BACKEND_SURFACE_TEST(SK_MACRO_CONCAT(name, _bet), canvas, main, \
246 SurfaceType::kBackendTexture, W, H)
247
248#define DEF_BERT_SURFACE_TEST(name, canvas, main, W, H) \
249 DEF_BACKEND_SURFACE_TEST(SK_MACRO_CONCAT(name, _bert), canvas, main, \
250 SurfaceType::kBackendRenderTarget, W, H)
251
252// This makes 3 GMs from the same code, normal, wrapped backend texture, and wrapped backend
253// render target.
254#define DEF_SURFACE_TESTS(name, canvas, W, H) \
255 static void SK_MACRO_CONCAT(name, _main)(SkCanvas*, const MakeSurfaceFn&); \
256 DEF_BASIC_SURFACE_TEST(name, canvas, SK_MACRO_CONCAT(name, _main), W, H) \
257 DEF_BET_SURFACE_TEST (name, canvas, SK_MACRO_CONCAT(name, _main), W, H) \
258 DEF_BERT_SURFACE_TEST (name, canvas, SK_MACRO_CONCAT(name, _main), W, H) \
259 static void SK_MACRO_CONCAT(name, _main)(SkCanvas * canvas, const MakeSurfaceFn& make)
260
261DEF_SURFACE_TESTS(copy_on_write_retain, canvas, 256, 256) {
263 sk_sp<SkSurface> surf = make(info);
264
265 surf->getCanvas()->clear(SK_ColorRED);
266 // its important that image survives longer than the next draw, so the surface will see
267 // an outstanding image, and have to decide if it should retain or discard those pixels
268 sk_sp<SkImage> image = surf->makeImageSnapshot();
269
270 // normally a clear+opaque should trigger the discard optimization, but since we have a clip
271 // it should not (we need the previous red pixels).
272 surf->getCanvas()->clipRect(SkRect::MakeWH(128, 256));
273 surf->getCanvas()->clear(SK_ColorBLUE);
274
275 // expect to see two rects: blue | red
276 canvas->drawImage(surf->makeImageSnapshot(), 0, 0);
277}
278
279// Like copy_on_write_retain but draws the snapped image back to the surface it was snapped from.
280DEF_SURFACE_TESTS(copy_on_write_retain2, canvas, 256, 256) {
282 sk_sp<SkSurface> surf = make(info);
283
284 surf->getCanvas()->clear(SK_ColorBLUE);
285 // its important that image survives longer than the next draw, so the surface will see
286 // an outstanding image, and have to decide if it should retain or discard those pixels
287 sk_sp<SkImage> image = surf->makeImageSnapshot();
288
289 surf->getCanvas()->clear(SK_ColorRED);
290 // normally a clear+opaque should trigger the discard optimization, but since we have a clip
291 // it should not (we need the previous red pixels).
292 surf->getCanvas()->clipRect(SkRect::MakeWH(128, 256));
293 surf->getCanvas()->drawImage(image, 0, 0);
294
295 // expect to see two rects: blue | red
296 canvas->drawImage(surf->makeImageSnapshot(), 0, 0);
297}
298
299DEF_SURFACE_TESTS(simple_snap_image, canvas, 256, 256) {
301 sk_sp<SkSurface> surf = make(info);
302
303 surf->getCanvas()->clear(SK_ColorRED);
304 sk_sp<SkImage> image = surf->makeImageSnapshot();
305 // expect to see just red
306 canvas->drawImage(std::move(image), 0, 0);
307}
308
309// Like simple_snap_image but the surface dies before the image.
310DEF_SURFACE_TESTS(simple_snap_image2, canvas, 256, 256) {
312 sk_sp<SkSurface> surf = make(info);
313
314 surf->getCanvas()->clear(SK_ColorRED);
315 sk_sp<SkImage> image = surf->makeImageSnapshot();
316 surf.reset();
317 // expect to see just red
318 canvas->drawImage(std::move(image), 0, 0);
319}
320
321DEF_SIMPLE_GM(snap_with_mips, canvas, 80, 75) {
322 auto ct = canvas->imageInfo().colorType() == kUnknown_SkColorType
324 : canvas->imageInfo().colorType();
325 auto ii = SkImageInfo::Make({32, 32},
326 ct,
328 canvas->imageInfo().refColorSpace());
329 auto surface = SkSurfaces::Raster(ii);
330
331 auto nextImage = [&](SkColor color) {
332 surface->getCanvas()->clear(color);
334 paint.setColor(~color | 0xFF000000);
335 surface->getCanvas()->drawRect(SkRect::MakeLTRB(surface->width() *2/5.f,
336 surface->height()*2/5.f,
337 surface->width() *3/5.f,
338 surface->height()*3/5.f),
339 paint);
340 return surface->makeImageSnapshot()->withDefaultMipmaps();
341 };
342
343 static constexpr int kPad = 8;
345
346 canvas->save();
347 for (int y = 0; y < 3; ++y) {
348 canvas->save();
349 SkColor kColors[] = {0xFFF0F0F0, SK_ColorBLUE};
350 for (int x = 0; x < 2; ++x) {
351 auto image = nextImage(kColors[x]);
352 canvas->drawImage(image, 0, 0, kSampling);
353 canvas->translate(ii.width() + kPad, 0);
354 }
355 canvas->restore();
356 canvas->translate(0, ii.width() + kPad);
357 canvas->scale(.4f, .4f);
358 }
359 canvas->restore();
360}
361
362DEF_SURFACE_TESTS(copy_on_write_savelayer, canvas, 256, 256) {
364 sk_sp<SkSurface> surf = make(info);
365 surf->getCanvas()->clear(SK_ColorRED);
366 // its important that image survives longer than the next draw, so the surface will see
367 // an outstanding image, and have to decide if it should retain or discard those pixels
368 sk_sp<SkImage> image = surf->makeImageSnapshot();
369
370 // now draw into a full-screen layer. This should (a) trigger a copy-on-write, but it should
371 // not trigger discard, even tho its alpha (SK_ColorBLUE) is opaque, since it is in a layer
372 // with a non-opaque paint.
374 paint.setAlphaf(0.25f);
375 surf->getCanvas()->saveLayer({0, 0, 256, 256}, &paint);
376 surf->getCanvas()->clear(SK_ColorBLUE);
377 surf->getCanvas()->restore();
378
379 // expect to see two rects: blue blended on red
380 canvas->drawImage(surf->makeImageSnapshot(), 0, 0);
381}
382
383DEF_SURFACE_TESTS(surface_underdraw, canvas, 256, 256) {
384 SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256, nullptr);
385 auto surf = make(info);
386
387 const SkIRect subset = SkIRect::MakeLTRB(180, 0, 256, 256);
388
389 // noisy background
390 {
391 SkPoint pts[] = {{0, 0}, {40, 50}};
392 SkColor colors[] = {SK_ColorRED, SK_ColorBLUE};
393 auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kRepeat);
395 paint.setShader(sh);
396 surf->getCanvas()->drawPaint(paint);
397 }
398
399 // save away the right-hand strip, then clear it
400 sk_sp<SkImage> saveImg = surf->makeImageSnapshot(subset);
401 {
403 paint.setBlendMode(SkBlendMode::kClear);
404 surf->getCanvas()->drawRect(SkRect::Make(subset), paint);
405 }
406
407 // draw the "foreground"
408 {
410 paint.setColor(SK_ColorGREEN);
411 SkRect r = { 0, 10, 256, 35 };
412 while (r.fBottom < 256) {
413 surf->getCanvas()->drawRect(r, paint);
414 r.offset(0, r.height() * 2);
415 }
416 }
417
418 // apply the "fade"
419 {
420 SkPoint pts[] = {{SkIntToScalar(subset.left()), 0}, {SkIntToScalar(subset.right()), 0}};
421 SkColor colors[] = {0xFF000000, 0};
422 auto sh = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp);
424 paint.setShader(sh);
425 paint.setBlendMode(SkBlendMode::kDstIn);
426 surf->getCanvas()->drawRect(SkRect::Make(subset), paint);
427 }
428
429 // restore the original strip, drawing it "under" the current foreground
430 {
432 paint.setBlendMode(SkBlendMode::kDstOver);
433 surf->getCanvas()->drawImage(saveImg,
434 SkIntToScalar(subset.left()), SkIntToScalar(subset.top()),
436 }
437
438 // show it on screen
439 surf->draw(canvas, 0, 0);
440}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
@ kBackendRenderTarget
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
SkColor4f color
static bool equal(const SkBitmap &a, const SkBitmap &b)
ScalarValue fGamma
@ 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
@ kDstIn
r = d * sa
@ kDstOver
r = d + (1-da)*s
@ kClear
r = 0
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
uint32_t SkColor
Definition SkColor.h:37
#define SkColorSetRGB(r, g, b)
Definition SkColor.h:57
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkIntToScalar(x)
Definition SkScalar.h:57
SkPixelGeometry
@ kUnknown_SkPixelGeometry
@ kRGB_V_SkPixelGeometry
@ kBGR_H_SkPixelGeometry
@ kRGB_H_SkPixelGeometry
@ kBGR_V_SkPixelGeometry
#define SK_GAMMA_CONTRAST
Definition SkTypes.h:94
#define SK_GAMMA_EXPONENT
Definition SkTypes.h:86
constexpr int kPad
SkISize getISize() override
Definition surface.cpp:161
SkString getName() const override
Definition surface.cpp:159
void onDraw(SkCanvas *canvas) override
Definition surface.cpp:167
static void drawInto(SkCanvas *canvas)
Definition surface.cpp:163
void drawRect(const SkRect &rect, const SkPaint &paint)
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition SkCanvas.h:1182
virtual GrRecordingContext * recordingContext() const
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
@ kSubpixelAntiAlias
glyph positioned in pixel using transparency
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
int width() const
Definition SkImage.h:285
static void DrawString(SkCanvas *canvas, const char text[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint, Align align=kLeft_Align)
Definition SkTextUtils.h:34
SkISize getISize() override
Definition surface.cpp:113
SkString getName() const override
Definition surface.cpp:111
void onDraw(SkCanvas *canvas) override
Definition surface.cpp:115
T * get() const
Definition SkRefCnt.h:303
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition gm.cpp:81
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
#define DEF_GM(CODE)
Definition gm.h:40
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
static sk_sp< SkImage > make(sk_sp< SkColorSpace > cs)
Definition mipmap.cpp:65
double y
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
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)
sk_sp< SkTypeface > DefaultPortableTypeface()
sk_sp< SkSurface > makeSurface(SkCanvas *canvas, const SkImageInfo &info, const SkSurfaceProps *props)
sk_sp< SkSurface > MakeBackendRenderTargetSurface(GrDirectContext *dContext, const SkImageInfo &ii, GrSurfaceOrigin origin, int sampleCnt, GrProtected isProtected, const SkSurfaceProps *props)
sk_sp< SkSurface > MakeBackendTextureSurface(GrDirectContext *dContext, const SkImageInfo &ii, GrSurfaceOrigin origin, int sampleCnt, skgpu::Mipmapped mipmapped, GrProtected isProtected, const SkSurfaceProps *props)
Definition SkMD5.cpp:130
constexpr int32_t top() const
Definition SkRect.h:120
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition SkRect.h:91
constexpr int32_t right() const
Definition SkRect.h:127
constexpr int32_t left() const
Definition SkRect.h:113
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeN32(int width, int height, SkAlphaType at)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
void offset(float dx, float dy)
Definition SkRect.h:1016
constexpr float height() const
Definition SkRect.h:769
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
std::function< sk_sp< SkSurface >(const SkImageInfo &)> MakeSurfaceFn
Definition surface.cpp:222
#define W
Definition surface.cpp:38
#define DEF_SURFACE_TESTS(name, canvas, W, H)
Definition surface.cpp:254
static void test_draw(SkCanvas *canvas, const char label[])
Definition surface.cpp:62
static sk_sp< SkShader > make_shader()
Definition surface.cpp:41
#define H
Definition surface.cpp:39
static sk_sp< SkSurface > make_surface(GrRecordingContext *ctx, const SkImageInfo &info, SkPixelGeometry geo, SkScalar contrast, SkScalar gamma)
Definition surface.cpp:49