Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2017 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.h"
      9 #include "sk_tool_utils.h"
     10 
     11 #include "SkSurface.h"
     12 
     13 #if SK_SUPPORT_GPU
     14 
     15 #include "GrContextPriv.h"
     16 #include "GrProxyProvider.h"
     17 #include "SkImage_Gpu.h"
     18 
     19 static const int kNumMatrices = 6;
     20 static const int kImageSize = 128;
     21 static const int kLabelSize = 32;
     22 static const int kNumLabels = 4;
     23 static const int kInset = 16;
     24 
     25 static const int kCellSize = kImageSize+2*kLabelSize;
     26 static const int kGMWidth  = kNumMatrices*kCellSize;
     27 static const int kGMHeight = 4*kCellSize;
     28 
     29 static const SkPoint kPoints[kNumLabels] = {
     30     {          0, kImageSize },     // LL
     31     { kImageSize, kImageSize },     // LR
     32     {          0,          0 },     // UL
     33     { kImageSize,          0 },     // UR
     34 };
     35 
     36 static const SkMatrix kUVMatrices[kNumMatrices] = {
     37     SkMatrix::MakeAll( 0, -1, 1,
     38                       -1,  0, 1,
     39                        0,  0, 1),
     40     SkMatrix::MakeAll( 1,  0, 0,
     41                        0, -1, 1,
     42                        0,  0, 1),
     43     // flip x
     44     SkMatrix::MakeAll(-1,  0, 1,
     45                        0,  1, 0,
     46                        0,  0, 1),
     47     SkMatrix::MakeAll( 0,  1, 0,
     48                       -1,  0, 1,
     49                        0,  0, 1),
     50     // flip both x & y == rotate 180
     51     SkMatrix::MakeAll(-1,  0, 1,
     52                        0, -1, 1,
     53                        0,  0, 1),
     54     // identity
     55     SkMatrix::MakeAll(1,  0, 0,
     56                       0,  1, 0,
     57                       0,  0, 1)
     58 };
     59 
     60 
     61 // Create a fixed size text label like "LL" or "LR".
     62 static sk_sp<SkImage> make_text_image(GrContext* context, const char* text, SkColor color) {
     63     SkPaint paint;
     64     sk_tool_utils::set_portable_typeface(&paint);
     65     paint.setAntiAlias(true);
     66     paint.setTextSize(32);
     67     paint.setColor(color);
     68 
     69     SkRect bounds;
     70     paint.measureText(text, strlen(text), &bounds);
     71     const SkMatrix mat = SkMatrix::MakeRectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize),
     72                                                   SkMatrix::kFill_ScaleToFit);
     73 
     74     const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
     75     sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
     76 
     77     SkCanvas* canvas = surf->getCanvas();
     78 
     79     canvas->clear(SK_ColorWHITE);
     80     canvas->concat(mat);
     81     canvas->drawText(text, strlen(text), 0, 0, paint);
     82 
     83     sk_sp<SkImage> image = surf->makeImageSnapshot();
     84 
     85     return image->makeTextureImage(context, nullptr);
     86 }
     87 
     88 static SkColor swap_red_and_blue(SkColor c) {
     89     return SkColorSetRGB(SkColorGetB(c), SkColorGetG(c), SkColorGetR(c));
     90 }
     91 
     92 // Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
     93 // or top-left.
     94 static sk_sp<SkImage> make_reference_image(GrContext* context,
     95                                            const SkTArray<sk_sp<SkImage>>& labels,
     96                                            bool bottomLeftOrigin) {
     97     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
     98     SkASSERT(kNumLabels == labels.count());
     99 
    100     SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
    101                                        kN32_SkColorType, kOpaque_SkAlphaType);
    102     SkBitmap bm;
    103     bm.allocPixels(ii);
    104     SkCanvas canvas(bm);
    105 
    106     canvas.clear(SK_ColorWHITE);
    107     for (int i = 0; i < kNumLabels; ++i) {
    108         canvas.drawImage(labels[i],
    109                          0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
    110                          0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
    111     }
    112 
    113     GrSurfaceDesc desc;
    114     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
    115     desc.fWidth = kImageSize;
    116     desc.fHeight = kImageSize;
    117     desc.fConfig = kRGBA_8888_GrPixelConfig;
    118 
    119     if (bottomLeftOrigin) {
    120         // Note that Ganesh will flip the data when it is uploaded
    121         desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    122     }
    123 
    124     if (kN32_SkColorType == kBGRA_8888_SkColorType) {
    125         // We're playing a game here and uploading N32 data into an RGB dest. We might have
    126         // to swap red & blue to compensate.
    127         for (int y = 0; y < bm.height(); ++y) {
    128             uint32_t *sl = bm.getAddr32(0, y);
    129             for (int x = 0; x < bm.width(); ++x) {
    130                 sl[x] = swap_red_and_blue(sl[x]);
    131             }
    132         }
    133     }
    134 
    135     sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
    136                                                                     bm.getPixels(), bm.rowBytes());
    137     if (!proxy) {
    138         return nullptr;
    139     }
    140 
    141     return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
    142                                    std::move(proxy), nullptr, SkBudgeted::kYes);
    143 }
    144 
    145 // Here we're converting from a matrix that is intended for UVs to a matrix that is intended
    146 // for rect geometry used for a drawImage call. They are, in some sense, inverses of each
    147 // other but we also need a scale to map from the [0..1] uv range to the actual size of
    148 // image.
    149 static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
    150 
    151     const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
    152 
    153     SkMatrix tmp = uvMat;
    154     tmp.preConcat(yFlip);
    155     tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
    156 
    157     tmp.postConcat(yFlip);
    158     tmp.postScale(kImageSize, kImageSize);
    159 
    160     return tmp.invert(geomMat);
    161 }
    162 
    163 // This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
    164 // rotates.
    165 class FlippityGM : public skiagm::GM {
    166 public:
    167     FlippityGM() {
    168         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
    169     }
    170 
    171 protected:
    172 
    173     SkString onShortName() override {
    174         return SkString("flippity");
    175     }
    176 
    177     SkISize onISize() override {
    178         return SkISize::Make(kGMWidth, kGMHeight);
    179     }
    180 
    181     // Draw the reference image and the four corner labels in the matrix's coordinate space
    182     void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
    183                                       bool drawSubset, bool drawScaled) {
    184         static const SkRect kSubsets[kNumMatrices] = {
    185             SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
    186             SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
    187             SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
    188             SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
    189             SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
    190             SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
    191         };
    192 
    193         SkMatrix imageGeomMat;
    194         SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
    195 
    196         canvas->save();
    197 
    198             // draw the reference image
    199             canvas->concat(imageGeomMat);
    200             if (drawSubset) {
    201                 canvas->drawImageRect(image, kSubsets[matIndex],
    202                                       drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
    203                                                  : kSubsets[matIndex],
    204                                       nullptr, SkCanvas::kFast_SrcRectConstraint);
    205             } else {
    206                 canvas->drawImage(image, 0, 0);
    207             }
    208 
    209             // draw the labels
    210             for (int i = 0; i < kNumLabels; ++i) {
    211                 canvas->drawImage(fLabels[i],
    212                                     0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
    213                                     0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
    214             }
    215         canvas->restore();
    216     }
    217 
    218     void drawRow(GrContext* context, SkCanvas* canvas,
    219                  bool bottomLeftImage, bool drawSubset, bool drawScaled) {
    220 
    221         sk_sp<SkImage> referenceImage = make_reference_image(context, fLabels, bottomLeftImage);
    222 
    223         canvas->save();
    224             canvas->translate(kLabelSize, kLabelSize);
    225 
    226             for (int i = 0; i < kNumMatrices; ++i) {
    227                 this->drawImageWithMatrixAndLabels(canvas, referenceImage.get(), i,
    228                                                    drawSubset, drawScaled);
    229                 canvas->translate(kCellSize, 0);
    230             }
    231         canvas->restore();
    232     }
    233 
    234     void makeLabels(GrContext* context) {
    235         static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
    236 
    237         static const SkColor kLabelColors[kNumLabels] = {
    238             SK_ColorRED,
    239             SK_ColorGREEN,
    240             SK_ColorBLUE,
    241             SK_ColorCYAN
    242         };
    243 
    244         SkASSERT(!fLabels.count());
    245         for (int i = 0; i < kNumLabels; ++i) {
    246             fLabels.push_back(make_text_image(context, kLabelText[i], kLabelColors[i]));
    247         }
    248         SkASSERT(kNumLabels == fLabels.count());
    249     }
    250 
    251     void onDraw(SkCanvas* canvas) override {
    252         GrContext* context = canvas->getGrContext();
    253         if (!context) {
    254             skiagm::GM::DrawGpuOnlyMessage(canvas);
    255             return;
    256         }
    257 
    258         this->makeLabels(context);
    259 
    260         canvas->save();
    261 
    262         // Top row gets TL image
    263         this->drawRow(context, canvas, false, false, false);
    264 
    265         canvas->translate(0, kCellSize);
    266 
    267         // Bottom row gets BL image
    268         this->drawRow(context, canvas, true, false, false);
    269 
    270         canvas->translate(0, kCellSize);
    271 
    272         // Third row gets subsets of BL images
    273         this->drawRow(context, canvas, true, true, false);
    274 
    275         canvas->translate(0, kCellSize);
    276 
    277         // Fourth row gets scaled subsets of BL images
    278         this->drawRow(context, canvas, true, true, true);
    279 
    280         canvas->restore();
    281 
    282         // separator grid
    283         for (int i = 0; i < 4; ++i) {
    284             canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
    285         }
    286         for (int i = 0; i < kNumMatrices; ++i) {
    287             canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
    288         }
    289     }
    290 
    291 private:
    292     SkTArray<sk_sp<SkImage>> fLabels;
    293 
    294     typedef GM INHERITED;
    295 };
    296 
    297 DEF_GM(return new FlippityGM;)
    298 
    299 #endif
    300