14a8126e7f81384526629b1e21bf89b632ea13cd9reed/*
24a8126e7f81384526629b1e21bf89b632ea13cd9reed * Copyright 2014 Google Inc.
34a8126e7f81384526629b1e21bf89b632ea13cd9reed *
44a8126e7f81384526629b1e21bf89b632ea13cd9reed * Use of this source code is governed by a BSD-style license that can be
54a8126e7f81384526629b1e21bf89b632ea13cd9reed * found in the LICENSE file.
64a8126e7f81384526629b1e21bf89b632ea13cd9reed */
74a8126e7f81384526629b1e21bf89b632ea13cd9reed
84a8126e7f81384526629b1e21bf89b632ea13cd9reed#include "gm.h"
933d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "sk_tool_utils.h"
104a8126e7f81384526629b1e21bf89b632ea13cd9reed#include "SkGradientShader.h"
114a8126e7f81384526629b1e21bf89b632ea13cd9reed#include "SkSurface.h"
124a8126e7f81384526629b1e21bf89b632ea13cd9reed#include "SkSurfaceProps.h"
134a8126e7f81384526629b1e21bf89b632ea13cd9reed
144a8126e7f81384526629b1e21bf89b632ea13cd9reed#define W 200
154a8126e7f81384526629b1e21bf89b632ea13cd9reed#define H 100
164a8126e7f81384526629b1e21bf89b632ea13cd9reed
171a9b9640843a64af8d9d90337ec3b3fea663196areedstatic sk_sp<SkShader> make_shader() {
184a8126e7f81384526629b1e21bf89b632ea13cd9reed    int a = 0x99;
194a8126e7f81384526629b1e21bf89b632ea13cd9reed    int b = 0xBB;
204a8126e7f81384526629b1e21bf89b632ea13cd9reed    SkPoint pts[] = { { 0, 0 }, { W, H } };
214a8126e7f81384526629b1e21bf89b632ea13cd9reed    SkColor colors[] = { SkColorSetRGB(a, a, a), SkColorSetRGB(b, b, b) };
221a9b9640843a64af8d9d90337ec3b3fea663196areed    return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
234a8126e7f81384526629b1e21bf89b632ea13cd9reed}
244a8126e7f81384526629b1e21bf89b632ea13cd9reed
257c1235457f7ef69d3bde48306e9be528718da7e6reedstatic sk_sp<SkSurface> make_surface(GrContext* ctx, const SkImageInfo& info, SkPixelGeometry geo) {
267c1235457f7ef69d3bde48306e9be528718da7e6reed    SkSurfaceProps props(0, geo);
274a8126e7f81384526629b1e21bf89b632ea13cd9reed    if (ctx) {
28e8f3062a36d3682f4019309a32b5b84dc9eddf8creed        return SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props);
294a8126e7f81384526629b1e21bf89b632ea13cd9reed    } else {
30e8f3062a36d3682f4019309a32b5b84dc9eddf8creed        return SkSurface::MakeRaster(info, &props);
314a8126e7f81384526629b1e21bf89b632ea13cd9reed    }
324a8126e7f81384526629b1e21bf89b632ea13cd9reed}
334a8126e7f81384526629b1e21bf89b632ea13cd9reed
344a8126e7f81384526629b1e21bf89b632ea13cd9reedstatic void test_draw(SkCanvas* canvas, const char label[]) {
354a8126e7f81384526629b1e21bf89b632ea13cd9reed    SkPaint paint;
364a8126e7f81384526629b1e21bf89b632ea13cd9reed
374a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setAntiAlias(true);
384a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setLCDRenderText(true);
394a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setDither(true);
404a8126e7f81384526629b1e21bf89b632ea13cd9reed
411a9b9640843a64af8d9d90337ec3b3fea663196areed    paint.setShader(make_shader());
424a8126e7f81384526629b1e21bf89b632ea13cd9reed    canvas->drawRect(SkRect::MakeWH(W, H), paint);
4396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    paint.setShader(nullptr);
444a8126e7f81384526629b1e21bf89b632ea13cd9reed
454a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setColor(SK_ColorWHITE);
464a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setTextSize(32);
474a8126e7f81384526629b1e21bf89b632ea13cd9reed    paint.setTextAlign(SkPaint::kCenter_Align);
48f597c42c50718d5c39769077040de1768c89bbd3caryclark    sk_tool_utils::set_portable_typeface(&paint);
492a475eae622adc1e8fa29206be1eaf862c23548eCary Clark    canvas->drawString(label, W / 2, H * 3 / 4, paint);
504a8126e7f81384526629b1e21bf89b632ea13cd9reed}
514a8126e7f81384526629b1e21bf89b632ea13cd9reed
524a8126e7f81384526629b1e21bf89b632ea13cd9reedclass SurfacePropsGM : public skiagm::GM {
534a8126e7f81384526629b1e21bf89b632ea13cd9reedpublic:
544a8126e7f81384526629b1e21bf89b632ea13cd9reed    SurfacePropsGM() {}
554a8126e7f81384526629b1e21bf89b632ea13cd9reed
564a8126e7f81384526629b1e21bf89b632ea13cd9reedprotected:
5736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override {
584a8126e7f81384526629b1e21bf89b632ea13cd9reed        return SkString("surfaceprops");
594a8126e7f81384526629b1e21bf89b632ea13cd9reed    }
604a8126e7f81384526629b1e21bf89b632ea13cd9reed
6136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override {
627c1235457f7ef69d3bde48306e9be528718da7e6reed        return SkISize::Make(W, H * 5);
634a8126e7f81384526629b1e21bf89b632ea13cd9reed    }
644a8126e7f81384526629b1e21bf89b632ea13cd9reed
6536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
664a8126e7f81384526629b1e21bf89b632ea13cd9reed        GrContext* ctx = canvas->getGrContext();
674a8126e7f81384526629b1e21bf89b632ea13cd9reed
684a8126e7f81384526629b1e21bf89b632ea13cd9reed        // must be opaque to have a hope of testing LCD text
690e22eb8e6efc7d7ab7a601ba555947916d139906brianosman        const SkImageInfo info = SkImageInfo::MakeN32(W, H, kOpaque_SkAlphaType);
704a8126e7f81384526629b1e21bf89b632ea13cd9reed
714a8126e7f81384526629b1e21bf89b632ea13cd9reed        const struct {
724a8126e7f81384526629b1e21bf89b632ea13cd9reed            SkPixelGeometry fGeo;
734a8126e7f81384526629b1e21bf89b632ea13cd9reed            const char*     fLabel;
74e6cad6b370d781c0e8345b5be74b83c2c328074cscroggo        } recs[] = {
754a8126e7f81384526629b1e21bf89b632ea13cd9reed            { kUnknown_SkPixelGeometry, "Unknown" },
764a8126e7f81384526629b1e21bf89b632ea13cd9reed            { kRGB_H_SkPixelGeometry,   "RGB_H" },
774a8126e7f81384526629b1e21bf89b632ea13cd9reed            { kBGR_H_SkPixelGeometry,   "BGR_H" },
784a8126e7f81384526629b1e21bf89b632ea13cd9reed            { kRGB_V_SkPixelGeometry,   "RGB_V" },
794a8126e7f81384526629b1e21bf89b632ea13cd9reed            { kBGR_V_SkPixelGeometry,   "BGR_V" },
804a8126e7f81384526629b1e21bf89b632ea13cd9reed        };
819d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary
824a8126e7f81384526629b1e21bf89b632ea13cd9reed        SkScalar x = 0;
837c1235457f7ef69d3bde48306e9be528718da7e6reed        SkScalar y = 0;
847c1235457f7ef69d3bde48306e9be528718da7e6reed        for (const auto& rec : recs) {
857c1235457f7ef69d3bde48306e9be528718da7e6reed            auto surface(make_surface(ctx, info, rec.fGeo));
867c1235457f7ef69d3bde48306e9be528718da7e6reed            if (!surface) {
877c1235457f7ef69d3bde48306e9be528718da7e6reed                SkDebugf("failed to create surface! label: %s", rec.fLabel);
887c1235457f7ef69d3bde48306e9be528718da7e6reed                continue;
894a8126e7f81384526629b1e21bf89b632ea13cd9reed            }
907c1235457f7ef69d3bde48306e9be528718da7e6reed            test_draw(surface->getCanvas(), rec.fLabel);
917c1235457f7ef69d3bde48306e9be528718da7e6reed            surface->draw(canvas, x, y, nullptr);
927c1235457f7ef69d3bde48306e9be528718da7e6reed            y += H;
934a8126e7f81384526629b1e21bf89b632ea13cd9reed        }
944a8126e7f81384526629b1e21bf89b632ea13cd9reed    }
954a8126e7f81384526629b1e21bf89b632ea13cd9reed
964a8126e7f81384526629b1e21bf89b632ea13cd9reedprivate:
974a8126e7f81384526629b1e21bf89b632ea13cd9reed    typedef GM INHERITED;
984a8126e7f81384526629b1e21bf89b632ea13cd9reed};
994a8126e7f81384526629b1e21bf89b632ea13cd9reedDEF_GM( return new SurfacePropsGM )
1004af267b11964d4a8acdb232ac46094c84d890e88reed
1014af267b11964d4a8acdb232ac46094c84d890e88reed#ifdef SK_DEBUG
1024af267b11964d4a8acdb232ac46094c84d890e88reedstatic bool equal(const SkSurfaceProps& a, const SkSurfaceProps& b) {
1034af267b11964d4a8acdb232ac46094c84d890e88reed    return a.flags() == b.flags() && a.pixelGeometry() == b.pixelGeometry();
1044af267b11964d4a8acdb232ac46094c84d890e88reed}
1054af267b11964d4a8acdb232ac46094c84d890e88reed#endif
1064af267b11964d4a8acdb232ac46094c84d890e88reed
1074af267b11964d4a8acdb232ac46094c84d890e88reedclass NewSurfaceGM : public skiagm::GM {
1084af267b11964d4a8acdb232ac46094c84d890e88reedpublic:
1094af267b11964d4a8acdb232ac46094c84d890e88reed    NewSurfaceGM() {}
1104af267b11964d4a8acdb232ac46094c84d890e88reed
1114af267b11964d4a8acdb232ac46094c84d890e88reedprotected:
11236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override {
1134af267b11964d4a8acdb232ac46094c84d890e88reed        return SkString("surfacenew");
1144af267b11964d4a8acdb232ac46094c84d890e88reed    }
1154af267b11964d4a8acdb232ac46094c84d890e88reed
11636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override {
1174af267b11964d4a8acdb232ac46094c84d890e88reed        return SkISize::Make(300, 140);
1184af267b11964d4a8acdb232ac46094c84d890e88reed    }
1194af267b11964d4a8acdb232ac46094c84d890e88reed
1204af267b11964d4a8acdb232ac46094c84d890e88reed    static void drawInto(SkCanvas* canvas) {
1214af267b11964d4a8acdb232ac46094c84d890e88reed        canvas->drawColor(SK_ColorRED);
1224af267b11964d4a8acdb232ac46094c84d890e88reed    }
1234af267b11964d4a8acdb232ac46094c84d890e88reed
12436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
1254af267b11964d4a8acdb232ac46094c84d890e88reed        SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
1264af267b11964d4a8acdb232ac46094c84d890e88reed
12746596ae50559e89a0a2462573ac9448cf309cf56Mike Reed        auto surf(sk_tool_utils::makeSurface(canvas, info, nullptr));
1284af267b11964d4a8acdb232ac46094c84d890e88reed        drawInto(surf->getCanvas());
1294af267b11964d4a8acdb232ac46094c84d890e88reed
1309ce9d6772df650ceb0511f275e1a83dffa78ff72reed        sk_sp<SkImage> image(surf->makeImageSnapshot());
13196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        canvas->drawImage(image, 10, 10, nullptr);
1324af267b11964d4a8acdb232ac46094c84d890e88reed
133e8f3062a36d3682f4019309a32b5b84dc9eddf8creed        auto surf2(surf->makeSurface(info));
1344af267b11964d4a8acdb232ac46094c84d890e88reed        drawInto(surf2->getCanvas());
1354af267b11964d4a8acdb232ac46094c84d890e88reed
1364af267b11964d4a8acdb232ac46094c84d890e88reed        // Assert that the props were communicated transitively through the first image
1374af267b11964d4a8acdb232ac46094c84d890e88reed        SkASSERT(equal(surf->props(), surf2->props()));
1384af267b11964d4a8acdb232ac46094c84d890e88reed
1399ce9d6772df650ceb0511f275e1a83dffa78ff72reed        sk_sp<SkImage> image2(surf2->makeImageSnapshot());
1409ce9d6772df650ceb0511f275e1a83dffa78ff72reed        canvas->drawImage(image2.get(), 10 + SkIntToScalar(image->width()) + 10, 10, nullptr);
1414af267b11964d4a8acdb232ac46094c84d890e88reed    }
1424af267b11964d4a8acdb232ac46094c84d890e88reed
1434af267b11964d4a8acdb232ac46094c84d890e88reedprivate:
1444af267b11964d4a8acdb232ac46094c84d890e88reed    typedef GM INHERITED;
1454af267b11964d4a8acdb232ac46094c84d890e88reed};
1464af267b11964d4a8acdb232ac46094c84d890e88reedDEF_GM( return new NewSurfaceGM )
147d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed
148d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed///////////////////////////////////////////////////////////////////////////////////////////////////
149d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed
150d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike ReedDEF_SIMPLE_GM(copy_on_write_retain, canvas, 256, 256) {
151d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
15246596ae50559e89a0a2462573ac9448cf309cf56Mike Reed    sk_sp<SkSurface> surf = sk_tool_utils::makeSurface(canvas, info);
153d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed
154d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    surf->getCanvas()->clear(SK_ColorRED);
155d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    // its important that image survives longer than the next draw, so the surface will see
156d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    // an outstanding image, and have to decide if it should retain or discard those pixels
157d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    sk_sp<SkImage> image = surf->makeImageSnapshot();
158d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed
159d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    // normally a clear+opaque should trigger the discard optimization, but since we have a clip
160d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    // it should not (we need the previous red pixels).
161d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    surf->getCanvas()->clipRect(SkRect::MakeWH(128, 256));
162d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    surf->getCanvas()->clear(SK_ColorBLUE);
163d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed
164d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    // expect to see two rects: blue | red
165d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed    canvas->drawImage(surf->makeImageSnapshot(), 0, 0, nullptr);
166d94abc5330a9332ca7bdb98f20d3d3b085bf623bMike Reed}
167a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed
168a1361364e64138adda3dc5f71d50d7503838bb6dMike ReedDEF_SIMPLE_GM(copy_on_write_savelayer, canvas, 256, 256) {
169a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
17046596ae50559e89a0a2462573ac9448cf309cf56Mike Reed    sk_sp<SkSurface> surf = sk_tool_utils::makeSurface(canvas, info);
171a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    surf->getCanvas()->clear(SK_ColorRED);
172a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // its important that image survives longer than the next draw, so the surface will see
173a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // an outstanding image, and have to decide if it should retain or discard those pixels
174a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    sk_sp<SkImage> image = surf->makeImageSnapshot();
175a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed
176a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // now draw into a full-screen layer. This should (a) trigger a copy-on-write, but it should
177a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // not trigger discard, even tho its alpha (SK_ColorBLUE) is opaque, since it is in a layer
178a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // with a non-opaque paint.
179a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    SkPaint paint;
180a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    paint.setAlpha(0x40);
181a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    surf->getCanvas()->saveLayer({0, 0, 256, 256}, &paint);
182a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    surf->getCanvas()->clear(SK_ColorBLUE);
183a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    surf->getCanvas()->restore();
184a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed
185a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    // expect to see two rects: blue blended on red
186a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed    canvas->drawImage(surf->makeImageSnapshot(), 0, 0, nullptr);
187a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed}
188