315 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright 2017 Google Inc.
 | |
|  *
 | |
|  * Use of this source code is governed by a BSD-style license that can be
 | |
|  * found in the LICENSE file.
 | |
|  */
 | |
| 
 | |
| #include "gm/gm.h"
 | |
| #include "include/core/SkBitmap.h"
 | |
| #include "include/core/SkCanvas.h"
 | |
| #include "include/core/SkColor.h"
 | |
| #include "include/core/SkFont.h"
 | |
| #include "include/core/SkFontTypes.h"
 | |
| #include "include/core/SkImage.h"
 | |
| #include "include/core/SkImageInfo.h"
 | |
| #include "include/core/SkMatrix.h"
 | |
| #include "include/core/SkPaint.h"
 | |
| #include "include/core/SkPoint.h"
 | |
| #include "include/core/SkRect.h"
 | |
| #include "include/core/SkRefCnt.h"
 | |
| #include "include/core/SkSize.h"
 | |
| #include "include/core/SkString.h"
 | |
| #include "include/core/SkSurface.h"
 | |
| #include "include/core/SkTypeface.h"
 | |
| #include "include/core/SkTypes.h"
 | |
| #include "include/gpu/GrDirectContext.h"
 | |
| #include "include/gpu/GrRecordingContext.h"
 | |
| #include "include/gpu/GrTypes.h"
 | |
| #include "include/private/SkTArray.h"
 | |
| #include "src/gpu/GrDirectContextPriv.h"
 | |
| #include "src/gpu/GrPixmap.h"
 | |
| #include "src/image/SkImage_Base.h"
 | |
| #include "src/image/SkImage_Gpu.h"
 | |
| #include "tools/ToolUtils.h"
 | |
| #include "tools/gpu/ProxyUtils.h"
 | |
| 
 | |
| #include <string.h>
 | |
| #include <utility>
 | |
| 
 | |
| static const int kNumMatrices = 6;
 | |
| static const int kImageSize = 128;
 | |
| static const int kLabelSize = 32;
 | |
| static const int kNumLabels = 4;
 | |
| static const int kInset = 16;
 | |
| 
 | |
| static const int kCellSize = kImageSize+2*kLabelSize;
 | |
| static const int kGMWidth  = kNumMatrices*kCellSize;
 | |
| static const int kGMHeight = 4*kCellSize;
 | |
| 
 | |
| static const SkPoint kPoints[kNumLabels] = {
 | |
|     {          0, kImageSize },     // LL
 | |
|     { kImageSize, kImageSize },     // LR
 | |
|     {          0,          0 },     // UL
 | |
|     { kImageSize,          0 },     // UR
 | |
| };
 | |
| 
 | |
| static const SkMatrix kUVMatrices[kNumMatrices] = {
 | |
|     SkMatrix::MakeAll( 0, -1, 1,
 | |
|                       -1,  0, 1,
 | |
|                        0,  0, 1),
 | |
|     SkMatrix::MakeAll( 1,  0, 0,
 | |
|                        0, -1, 1,
 | |
|                        0,  0, 1),
 | |
|     // flip x
 | |
|     SkMatrix::MakeAll(-1,  0, 1,
 | |
|                        0,  1, 0,
 | |
|                        0,  0, 1),
 | |
|     SkMatrix::MakeAll( 0,  1, 0,
 | |
|                       -1,  0, 1,
 | |
|                        0,  0, 1),
 | |
|     // flip both x & y == rotate 180
 | |
|     SkMatrix::MakeAll(-1,  0, 1,
 | |
|                        0, -1, 1,
 | |
|                        0,  0, 1),
 | |
|     // identity
 | |
|     SkMatrix::MakeAll(1,  0, 0,
 | |
|                       0,  1, 0,
 | |
|                       0,  0, 1)
 | |
| };
 | |
| 
 | |
| 
 | |
| // Create a fixed size text label like "LL" or "LR".
 | |
| static sk_sp<SkImage> make_text_image(GrDirectContext* dContext, const char* text, SkColor color) {
 | |
|     SkPaint paint;
 | |
|     paint.setAntiAlias(true);
 | |
|     paint.setColor(color);
 | |
| 
 | |
|     SkFont font;
 | |
|     font.setEdging(SkFont::Edging::kAntiAlias);
 | |
|     font.setTypeface(ToolUtils::create_portable_typeface());
 | |
|     font.setSize(32);
 | |
| 
 | |
|     SkRect bounds;
 | |
|     font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
 | |
|     const SkMatrix mat = SkMatrix::RectToRect(bounds, SkRect::MakeWH(kLabelSize, kLabelSize));
 | |
| 
 | |
|     const SkImageInfo ii = SkImageInfo::MakeN32Premul(kLabelSize, kLabelSize);
 | |
|     sk_sp<SkSurface> surf = SkSurface::MakeRaster(ii);
 | |
| 
 | |
|     SkCanvas* canvas = surf->getCanvas();
 | |
| 
 | |
|     canvas->clear(SK_ColorWHITE);
 | |
|     canvas->concat(mat);
 | |
|     canvas->drawSimpleText(text, strlen(text), SkTextEncoding::kUTF8, 0, 0, font, paint);
 | |
| 
 | |
|     sk_sp<SkImage> image = surf->makeImageSnapshot();
 | |
| 
 | |
|     return image->makeTextureImage(dContext);
 | |
| }
 | |
| 
 | |
| // Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
 | |
| // or top-left.
 | |
| static sk_sp<SkImage> make_reference_image(GrDirectContext* dContext,
 | |
|                                            const SkTArray<sk_sp<SkImage>>& labels,
 | |
|                                            bool bottomLeftOrigin) {
 | |
|     SkASSERT(kNumLabels == labels.count());
 | |
| 
 | |
|     SkImageInfo ii =
 | |
|             SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
 | |
|     SkBitmap bm;
 | |
|     bm.allocPixels(ii);
 | |
|     SkCanvas canvas(bm);
 | |
| 
 | |
|     canvas.clear(SK_ColorWHITE);
 | |
|     for (int i = 0; i < kNumLabels; ++i) {
 | |
|         canvas.drawImage(labels[i],
 | |
|                          0.0 != kPoints[i].fX ? kPoints[i].fX-kLabelSize-kInset : kInset,
 | |
|                          0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
 | |
|     }
 | |
| 
 | |
|     auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
 | |
| 
 | |
|     auto view = sk_gpu_test::MakeTextureProxyViewFromData(dContext, GrRenderable::kNo, origin,
 | |
|                                                           bm.pixmap());
 | |
|     if (!view) {
 | |
|         return nullptr;
 | |
|     }
 | |
| 
 | |
|     return sk_make_sp<SkImage_Gpu>(sk_ref_sp(dContext),
 | |
|                                    kNeedNewImageUniqueID,
 | |
|                                    std::move(view),
 | |
|                                    ii.colorInfo());
 | |
| }
 | |
| 
 | |
| // Here we're converting from a matrix that is intended for UVs to a matrix that is intended
 | |
| // for rect geometry used for a drawImage call. They are, in some sense, inverses of each
 | |
| // other but we also need a scale to map from the [0..1] uv range to the actual size of
 | |
| // image.
 | |
| static bool UVMatToGeomMatForImage(SkMatrix* geomMat, const SkMatrix& uvMat) {
 | |
| 
 | |
|     const SkMatrix yFlip = SkMatrix::MakeAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
 | |
| 
 | |
|     SkMatrix tmp = uvMat;
 | |
|     tmp.preConcat(yFlip);
 | |
|     tmp.preScale(1.0f/kImageSize, 1.0f/kImageSize);
 | |
| 
 | |
|     tmp.postConcat(yFlip);
 | |
|     tmp.postScale(kImageSize, kImageSize);
 | |
| 
 | |
|     return tmp.invert(geomMat);
 | |
| }
 | |
| 
 | |
| // This GM exercises drawImage with a set of matrices that use an unusual amount of flips and
 | |
| // rotates.
 | |
| class FlippityGM : public skiagm::GM {
 | |
| public:
 | |
|     FlippityGM() {
 | |
|         this->setBGColor(0xFFCCCCCC);
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     SkString onShortName() override {
 | |
|         return SkString("flippity");
 | |
|     }
 | |
| 
 | |
|     SkISize onISize() override {
 | |
|         return SkISize::Make(kGMWidth, kGMHeight);
 | |
|     }
 | |
| 
 | |
|     // Draw the reference image and the four corner labels in the matrix's coordinate space
 | |
|     void drawImageWithMatrixAndLabels(SkCanvas* canvas, SkImage* image, int matIndex,
 | |
|                                       bool drawSubset, bool drawScaled) {
 | |
|         static const SkRect kSubsets[kNumMatrices] = {
 | |
|             SkRect::MakeXYWH(kInset, 0, kImageSize-kInset, kImageSize),
 | |
|             SkRect::MakeXYWH(0, kInset, kImageSize, kImageSize-kInset),
 | |
|             SkRect::MakeXYWH(0, 0, kImageSize-kInset, kImageSize),
 | |
|             SkRect::MakeXYWH(0, 0, kImageSize, kImageSize-kInset),
 | |
|             SkRect::MakeXYWH(kInset/2, kInset/2, kImageSize-kInset, kImageSize-kInset),
 | |
|             SkRect::MakeXYWH(kInset, kInset, kImageSize-2*kInset, kImageSize-2*kInset),
 | |
|         };
 | |
| 
 | |
|         SkMatrix imageGeomMat;
 | |
|         SkAssertResult(UVMatToGeomMatForImage(&imageGeomMat, kUVMatrices[matIndex]));
 | |
| 
 | |
|         canvas->save();
 | |
| 
 | |
|             // draw the reference image
 | |
|             canvas->concat(imageGeomMat);
 | |
|             if (drawSubset) {
 | |
|                 canvas->drawImageRect(image, kSubsets[matIndex],
 | |
|                                       drawScaled ? SkRect::MakeWH(kImageSize, kImageSize)
 | |
|                                                  : kSubsets[matIndex],
 | |
|                                       SkSamplingOptions(), nullptr,
 | |
|                                       SkCanvas::kFast_SrcRectConstraint);
 | |
|             } else {
 | |
|                 canvas->drawImage(image, 0, 0);
 | |
|             }
 | |
| 
 | |
|             // draw the labels
 | |
|             for (int i = 0; i < kNumLabels; ++i) {
 | |
|                 canvas->drawImage(fLabels[i],
 | |
|                                     0.0f == kPoints[i].fX ? -kLabelSize : kPoints[i].fX,
 | |
|                                     0.0f == kPoints[i].fY ? -kLabelSize : kPoints[i].fY);
 | |
|             }
 | |
|         canvas->restore();
 | |
|     }
 | |
| 
 | |
|     void drawRow(SkCanvas* canvas, bool bottomLeftImage, bool drawSubset, bool drawScaled) {
 | |
| 
 | |
|         canvas->save();
 | |
|             canvas->translate(kLabelSize, kLabelSize);
 | |
| 
 | |
|             for (int i = 0; i < kNumMatrices; ++i) {
 | |
|                 this->drawImageWithMatrixAndLabels(canvas, fReferenceImages[bottomLeftImage].get(),
 | |
|                                                    i, drawSubset, drawScaled);
 | |
|                 canvas->translate(kCellSize, 0);
 | |
|             }
 | |
|         canvas->restore();
 | |
|     }
 | |
| 
 | |
|     void makeLabels(GrDirectContext* dContext) {
 | |
|         if (fLabels.count()) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         static const char* kLabelText[kNumLabels] = { "LL", "LR", "UL", "UR" };
 | |
| 
 | |
|         static const SkColor kLabelColors[kNumLabels] = {
 | |
|             SK_ColorRED,
 | |
|             SK_ColorGREEN,
 | |
|             SK_ColorBLUE,
 | |
|             SK_ColorCYAN
 | |
|         };
 | |
| 
 | |
|         for (int i = 0; i < kNumLabels; ++i) {
 | |
|             fLabels.push_back(make_text_image(dContext, kLabelText[i], kLabelColors[i]));
 | |
|         }
 | |
|         SkASSERT(kNumLabels == fLabels.count());
 | |
|     }
 | |
| 
 | |
|     DrawResult onGpuSetup(GrDirectContext* dContext, SkString* errorMsg) override {
 | |
|         if (!dContext || dContext->abandoned()) {
 | |
|             *errorMsg = "DirectContext required to create reference images";
 | |
|             return DrawResult::kSkip;
 | |
|         }
 | |
| 
 | |
|         this->makeLabels(dContext);
 | |
|         fReferenceImages[0] = make_reference_image(dContext, fLabels, false);
 | |
|         fReferenceImages[1] = make_reference_image(dContext, fLabels, true);
 | |
|         if (!fReferenceImages[0] || !fReferenceImages[1]) {
 | |
|             *errorMsg = "Failed to create reference images.";
 | |
|             return DrawResult::kFail;
 | |
|         }
 | |
| 
 | |
|         return DrawResult::kOk;
 | |
|     }
 | |
| 
 | |
|     void onGpuTeardown() override {
 | |
|         fLabels.reset();
 | |
|         fReferenceImages[0] = fReferenceImages[1] = nullptr;
 | |
|     }
 | |
| 
 | |
|     void onDraw(SkCanvas* canvas) override {
 | |
|         SkASSERT(fReferenceImages[0] && fReferenceImages[1]);
 | |
| 
 | |
|         canvas->save();
 | |
| 
 | |
|         // Top row gets TL image
 | |
|         this->drawRow(canvas, false, false, false);
 | |
| 
 | |
|         canvas->translate(0, kCellSize);
 | |
| 
 | |
|         // Bottom row gets BL image
 | |
|         this->drawRow(canvas, true, false, false);
 | |
| 
 | |
|         canvas->translate(0, kCellSize);
 | |
| 
 | |
|         // Third row gets subsets of BL images
 | |
|         this->drawRow(canvas, true, true, false);
 | |
| 
 | |
|         canvas->translate(0, kCellSize);
 | |
| 
 | |
|         // Fourth row gets scaled subsets of BL images
 | |
|         this->drawRow(canvas, true, true, true);
 | |
| 
 | |
|         canvas->restore();
 | |
| 
 | |
|         // separator grid
 | |
|         for (int i = 0; i < 4; ++i) {
 | |
|             canvas->drawLine(0, i * kCellSize, kGMWidth, i * kCellSize, SkPaint());
 | |
|         }
 | |
|         for (int i = 0; i < kNumMatrices; ++i) {
 | |
|             canvas->drawLine(i * kCellSize, 0, i * kCellSize, kGMHeight, SkPaint());
 | |
|         }
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     SkTArray<sk_sp<SkImage>> fLabels;
 | |
|     sk_sp<SkImage> fReferenceImages[2];
 | |
| 
 | |
|     using INHERITED = GM;
 | |
| };
 | |
| 
 | |
| DEF_GM(return new FlippityGM;)
 |