blob: 852a941acd06f863a144700811e8a7eed78e2b4e [file] [log] [blame]
Robert Phillips94e67912021-01-21 13:39:08 -05001/*
2 * Copyright 2021 Google LLC
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"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkPaint.h"
11#include "include/core/SkRect.h"
12#include "include/core/SkSize.h"
13#include "include/core/SkString.h"
14#include "include/gpu/GrDirectContext.h"
15
16#include "src/core/SkConvertPixels.h"
17#include "src/gpu/GrDirectContextPriv.h"
18#include "src/gpu/GrPaint.h"
19#include "src/gpu/GrProxyProvider.h"
20#include "src/gpu/GrResourceProvider.h"
21#include "src/gpu/GrSurfaceDrawContext.h"
22#include "src/gpu/SkGr.h"
23#include "src/gpu/effects/GrTextureEffect.h"
24
25#include "tools/gpu/ProxyUtils.h"
26
27static GrSurfaceProxyView create_view(GrDirectContext* dContext,
28 const SkBitmap& src,
29 GrSurfaceOrigin origin) {
30 SkASSERT(src.colorType() == kRGBA_8888_SkColorType);
31
32#define USE_LAZY_PROXIES 1 // Toggle this to generate the reference images
33
34 if (USE_LAZY_PROXIES) {
35 auto format = dContext->priv().caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888,
36 GrRenderable::kNo);
37 if (!format.isValid()) {
38 return {};
39 }
40
41 sk_sp<GrTextureProxy> proxy = GrProxyProvider::MakeFullyLazyProxy(
42 [src](GrResourceProvider* rp,
43 const GrSurfaceProxy::LazySurfaceDesc& desc)
44 -> GrSurfaceProxy::LazyCallbackResult {
45 SkASSERT(desc.fMipmapped == GrMipmapped::kNo);
46 GrMipLevel mipLevel = { src.getPixels(), src.rowBytes() };
47 auto colorType = SkColorTypeToGrColorType(src.colorType());
48
49 return rp->createTexture(src.dimensions(), desc.fFormat, colorType,
50 desc.fRenderable, desc.fSampleCnt, desc.fBudgeted,
51 desc.fFit, desc.fProtected, mipLevel);
52 },
53 format, GrRenderable::kNo, 1, GrProtected::kNo, *dContext->priv().caps(),
54 GrSurfaceProxy::UseAllocator::kYes);
55
56 if (!proxy) {
57 return {};
58 }
59
60 auto swizzle = dContext->priv().caps()->getReadSwizzle(proxy->backendFormat(),
61 GrColorType::kRGBA_8888);
62 return GrSurfaceProxyView(std::move(proxy), origin, swizzle);
63 }
64
65 return sk_gpu_test::MakeTextureProxyViewFromData(dContext,
66 GrRenderable::kNo,
67 origin,
68 src.pixmap());
69}
70
71// Create an over large texture which is initialized to opaque black outside of the content
72// rect. The inside of the content rect consists of a grey coordinate frame lacking the -Y axis.
73// The -X and +X axes have a red and green dot at their ends (respectively). Finally, the content
74// rect has a 1-pixel wide blue border.
75static SkBitmap create_bitmap(SkIRect contentRect, SkISize fullSize, GrSurfaceOrigin origin) {
76
77 const int kContentSize = contentRect.width();
78 SkBitmap contentBM;
79
80 {
81 SkImageInfo contentInfo = SkImageInfo::Make(kContentSize, kContentSize,
82 kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
83 contentBM.allocPixels(contentInfo);
84
85 contentBM.eraseColor(SK_ColorWHITE);
86
87 const int halfM1 = kContentSize/2 - 1;
88
89 // The coordinate frame
90 contentBM.eraseArea(SkIRect::MakeXYWH(halfM1, 2,2, halfM1), SK_ColorGRAY);
91 contentBM.eraseArea(SkIRect::MakeXYWH(2, halfM1, kContentSize-4, 2), SK_ColorGRAY);
92
93 contentBM.eraseArea(SkIRect::MakeXYWH(2, halfM1, 2, 2), SK_ColorRED);
94 contentBM.eraseArea(SkIRect::MakeXYWH(kContentSize-4, halfM1, 2, 2), SK_ColorGREEN);
95
96 // The 1-pixel wide rim around the content rect
97 contentBM.eraseArea(SkIRect::MakeXYWH(0, 0, kContentSize, 1), SK_ColorBLUE);
98 contentBM.eraseArea(SkIRect::MakeXYWH(0, 0, 1, kContentSize), SK_ColorBLUE);
99 contentBM.eraseArea(SkIRect::MakeXYWH(kContentSize-1, 0, 1, kContentSize), SK_ColorBLUE);
100 contentBM.eraseArea(SkIRect::MakeXYWH(0, kContentSize-1, kContentSize, 1), SK_ColorBLUE);
101 }
102
103 SkBitmap bigBM;
104
105 {
106 const int kLeft = contentRect.fLeft;
107 const int kTop = contentRect.fTop;
108
109 SkImageInfo bigInfo = SkImageInfo::Make(fullSize.fWidth, fullSize.fHeight,
110 kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
111
112 bigBM.allocPixels(bigInfo);
113
114 bigBM.eraseColor(SK_ColorBLACK);
115
116 const char* src = static_cast<const char*>(contentBM.getPixels());
117 size_t srcRB = contentBM.rowBytes();
118 size_t dstRB = bigBM.rowBytes();
119
120 if (USE_LAZY_PROXIES && origin == kBottomLeft_GrSurfaceOrigin) {
121 char* dst = static_cast<char*>(bigBM.getAddr(kLeft, fullSize.height() - kTop - 1));
122 for (int y = 0; y < contentBM.height(); ++y) {
123 memcpy(dst, src, srcRB);
124 src = src + srcRB;
125 dst = dst - dstRB;
126 }
127 } else {
128 char* dst = static_cast<char*>(bigBM.getAddr(kLeft, kTop));
129 SkRectMemcpy(dst, dstRB, src, srcRB,
130 contentBM.rowBytes(), contentBM.height());
131 }
132
133 bigBM.setAlphaType(kOpaque_SkAlphaType);
134 bigBM.setImmutable();
135 }
136
137 return bigBM;
138}
139
140static void draw_texture(const GrCaps* caps,
141 GrSurfaceDrawContext* sdc,
142 const GrSurfaceProxyView& src,
143 const SkIRect& srcRect,
144 const SkIRect& drawRect,
145 const SkMatrix& mat,
146 GrSamplerState::WrapMode xTileMode,
147 GrSamplerState::WrapMode yTileMode) {
148 GrSamplerState sampler(xTileMode, yTileMode, SkFilterMode::kNearest);
149
150 auto fp = GrTextureEffect::MakeSubset(src, kOpaque_SkAlphaType, mat,
151 sampler, SkRect::Make(srcRect), *caps);
152 GrPaint paint;
153 paint.setColorFragmentProcessor(std::move(fp));
154
155 sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(drawRect));
156}
157
158namespace skiagm {
159
160// This GM exercises all the different tile modes for a texture that cannot be normalized
161// early (i.e., rectangle or fully-lazy).
162// TODO: should we also test w/ mipmapping?
163class LazyTilingGM : public GpuGM {
164public:
165 LazyTilingGM(GrSurfaceOrigin origin)
166 : fOrigin(origin)
167 , fContentRect(SkIRect::MakeXYWH(kLeftContentOffset, kTopContentOffset,
168 kContentSize, kContentSize)) {
169 this->setBGColor(0xFFCCCCCC);
170 }
171
172protected:
173
174 SkString onShortName() override {
175 return SkStringPrintf("lazytiling_%s", fOrigin == kTopLeft_GrSurfaceOrigin ? "tl" : "bl");
176 }
177
178 SkISize onISize() override {
179 return SkISize::Make(kTotalWidth, kTotalHeight);
180 }
181
182 DrawResult onGpuSetup(GrDirectContext* dContext, SkString* errorMsg) override {
183 if (!dContext || dContext->abandoned()) {
184 return DrawResult::kSkip;
185 }
186
187 auto bm = create_bitmap(fContentRect,
188 { kLeftContentOffset + kContentSize + kRightContentPadding,
189 kTopContentOffset + kContentSize + kBottomContentPadding },
190 fOrigin);
191
192 fView = create_view(dContext, bm, fOrigin);
193 if (!fView.proxy()) {
194 *errorMsg = "Failed to create proxy";
195 return DrawResult::kFail;
196 }
197
198 return DrawResult::kOk;
199 }
200
201 void onDraw(GrRecordingContext* rContext, GrSurfaceDrawContext* sdc,
202 SkCanvas* canvas) override {
203 SkSamplingOptions sampling(SkFilterMode::kNearest, SkMipmapMode::kNone);
204 SkPaint p;
205
206 int y = kPad;
207 for (auto yMode : { SkTileMode::kClamp, SkTileMode::kRepeat,
208 SkTileMode::kMirror, SkTileMode::kDecal }) {
209 int x = kPad;
210 for (auto xMode : { SkTileMode::kClamp, SkTileMode::kRepeat,
211 SkTileMode::kMirror, SkTileMode::kDecal }) {
212 SkIRect cellRect = SkIRect::MakeXYWH(x, y, 2*kContentSize, 2*kContentSize);
213 SkRect contentRect = SkRect::MakeXYWH(x+kContentSize/2, y+kContentSize/2,
214 kContentSize, kContentSize);
215
216 SkMatrix texMatrix = SkMatrix::RectToRect(contentRect, SkRect::Make(fContentRect));
217
218 draw_texture(rContext->priv().caps(),
219 sdc,
220 fView,
221 fContentRect,
222 cellRect,
223 texMatrix,
224 SkTileModeToWrapMode(xMode),
225 SkTileModeToWrapMode(yMode));
226
227 x += 2*kContentSize+kPad;
228 }
229
230 y += 2*kContentSize+kPad;
231 }
232
233 }
234
235private:
236 static constexpr int kLeftContentOffset = 8;
237 static constexpr int kTopContentOffset = 16;
238 static constexpr int kRightContentPadding = 24;
239 static constexpr int kBottomContentPadding = 80;
240
241 static constexpr int kPad = 4; // on-screen padding between cells
242
243 static constexpr int kContentSize = 32;
244
245 // Each cell in this GM's grid is a square - 2*kContentSize on a side
246 static constexpr int kTotalWidth = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
247 static constexpr int kTotalHeight = (2*kContentSize+kPad) * kSkTileModeCount + kPad;
248
249 GrSurfaceOrigin fOrigin;
250 SkIRect fContentRect;
251 GrSurfaceProxyView fView;
252
253 using INHERITED = GM;
254};
255
256//////////////////////////////////////////////////////////////////////////////
257
258DEF_GM(return new LazyTilingGM(kTopLeft_GrSurfaceOrigin);)
259DEF_GM(return new LazyTilingGM(kBottomLeft_GrSurfaceOrigin);)
260
261} // namespace skiagm