blob: 6c451f962fe77cc9a14491bb7ba942e571cd4abc [file] [log] [blame]
Brian Salomonf0334042020-01-31 16:16:39 -05001/*
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// This test only works with the GPU backend.
9
10#include "gm/gm.h"
11#include "include/core/SkBitmap.h"
12#include "include/core/SkCanvas.h"
13#include "include/core/SkColor.h"
14#include "include/core/SkMatrix.h"
15#include "include/core/SkPaint.h"
16#include "include/core/SkRect.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
19#include "include/effects/SkGradientShader.h"
20#include "include/private/GrTypesPriv.h"
21#include "include/private/SkTArray.h"
22#include "src/gpu/GrBitmapTextureMaker.h"
Adlai Hollera0693042020-10-14 11:23:11 -040023#include "src/gpu/GrDirectContextPriv.h"
Brian Salomonf0334042020-01-31 16:16:39 -050024#include "src/gpu/GrProxyProvider.h"
Brian Salomonf0334042020-01-31 16:16:39 -050025#include "src/gpu/GrSamplerState.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050026#include "src/gpu/GrSurfaceDrawContext.h"
Brian Salomonf0334042020-01-31 16:16:39 -050027#include "src/gpu/GrTextureProxy.h"
Brian Salomon16033c92020-02-13 11:25:11 -050028#include "src/gpu/effects/generated/GrConstColorProcessor.h"
Brian Salomonf0334042020-01-31 16:16:39 -050029#include "tools/Resources.h"
30#include "tools/gpu/TestOps.h"
31
32#include <memory>
33#include <utility>
34
Brian Salomone69b9ef2020-07-22 11:18:06 -040035using MipmapMode = GrSamplerState::MipmapMode;
36using Filter = GrSamplerState::Filter;
37using Wrap = GrSamplerState::WrapMode;
38
Brian Salomonf0334042020-01-31 16:16:39 -050039namespace skiagm {
40/**
41 * This GM directly exercises GrTextureEffect::MakeTexelSubset.
42 */
43class TexelSubset : public GpuGM {
44public:
Brian Salomone69b9ef2020-07-22 11:18:06 -040045 TexelSubset(Filter filter, MipmapMode mm, bool upscale)
46 : fFilter(filter), fMipmapMode(mm), fUpscale(upscale) {
Brian Salomonf0334042020-01-31 16:16:39 -050047 this->setBGColor(0xFFFFFFFF);
48 }
49
50protected:
51 SkString onShortName() override {
52 SkString name("texel_subset");
53 switch (fFilter) {
Brian Salomone69b9ef2020-07-22 11:18:06 -040054 case Filter::kNearest:
Brian Salomonf0334042020-01-31 16:16:39 -050055 name.append("_nearest");
56 break;
Brian Salomone69b9ef2020-07-22 11:18:06 -040057 case Filter::kLinear:
58 name.append("_linear");
Brian Salomonf0334042020-01-31 16:16:39 -050059 break;
60 }
Brian Salomonf7353512020-07-22 19:26:48 -040061 switch (fMipmapMode) {
62 case MipmapMode::kNone:
63 break;
64 case MipmapMode::kNearest:
65 name.append("_mipmap_nearest");
66 break;
67 case MipmapMode::kLinear:
68 name.append("_mipmap_linear");
69 break;
70 }
Brian Salomonf0334042020-01-31 16:16:39 -050071 name.append(fUpscale ? "_up" : "_down");
72 return name;
73 }
74
75 SkISize onISize() override {
Brian Salomon16033c92020-02-13 11:25:11 -050076 static constexpr int kN = GrSamplerState::kWrapModeCount;
Brian Salomonf46f19b2020-02-13 14:11:28 -050077 int w = kTestPad + 2*kN*(kImageSize.width() + 2*kDrawPad + kTestPad);
78 int h = kTestPad + 2*kN*(kImageSize.height() + 2*kDrawPad + kTestPad);
Brian Salomonf0334042020-01-31 16:16:39 -050079 return {w, h};
80 }
81
82 void onOnceBeforeDraw() override {
83 GetResourceAsBitmap("images/mandrill_128.png", &fBitmap);
84 // Make the bitmap non-square to detect any width/height confusion.
85 fBitmap.extractSubset(&fBitmap, SkIRect::MakeSize(fBitmap.dimensions()).makeInset(0, 20));
86 SkASSERT(fBitmap.dimensions() == kImageSize);
87 }
88
Brian Salomon1aa1f5f2020-12-11 17:25:17 -050089 DrawResult onDraw(GrRecordingContext* context, GrSurfaceDrawContext* surfaceDrawContext,
Brian Salomonf0334042020-01-31 16:16:39 -050090 SkCanvas* canvas, SkString* errorMsg) override {
Brian Salomone69b9ef2020-07-22 11:18:06 -040091 GrMipmapped mipmapped = (fMipmapMode != MipmapMode::kNone) ? GrMipmapped::kYes
92 : GrMipmapped::kNo;
93 if (mipmapped == GrMipmapped::kYes && !context->priv().caps()->mipmapSupport()) {
94 return DrawResult::kSkip;
95 }
Brian Salomonbc074a62020-03-18 10:06:13 -040096 GrBitmapTextureMaker maker(context, fBitmap, GrImageTexGenPolicy::kDraw);
Brian Salomone69b9ef2020-07-22 11:18:06 -040097 auto view = maker.view(mipmapped);
Brian Salomonecbb0fb2020-02-28 18:07:32 -050098 if (!view) {
Brian Salomonf0334042020-01-31 16:16:39 -050099 *errorMsg = "Failed to create proxy.";
100 return DrawResult::kFail;
101 }
102
103 SkIRect texelSubset;
104 // Use a smaller subset when upscaling so that wrap is hit on all sides of the rect we
105 // will draw.
106 if (fUpscale) {
107 texelSubset = SkIRect::MakeXYWH(fBitmap.width()/3 - 1, 2*fBitmap.height()/5 - 1,
108 fBitmap.width()/4 + 2, fBitmap.height()/5 + 2);
109 } else {
110 texelSubset = SkIRect::MakeXYWH( fBitmap.width()/8 - 1, fBitmap.height()/7 - 1,
111 3*fBitmap.width()/5 + 2, 4*fBitmap.height()/5 + 2);
112 }
113
114 SkTArray<SkMatrix> textureMatrices;
115
116 SkRect a = SkRect::Make(texelSubset);
Brian Salomon63a04a82020-02-03 10:47:05 -0500117 SkRect b = fUpscale ? a.makeInset (.31f * a.width(), .31f * a.height())
Brian Salomonf0334042020-01-31 16:16:39 -0500118 : a.makeOutset(.25f * a.width(), .25f * a.height());
Mike Reed2ac6ce82021-01-15 12:26:22 -0500119 textureMatrices.push_back() = SkMatrix::RectToRect(a, b);
Brian Salomonf0334042020-01-31 16:16:39 -0500120
121 b = fUpscale ? a.makeInset (.25f * a.width(), .35f * a.height())
122 : a.makeOutset(.20f * a.width(), .35f * a.height());
Mike Reed2ac6ce82021-01-15 12:26:22 -0500123 textureMatrices.push_back() = SkMatrix::RectToRect(a, b);
Brian Salomonf0334042020-01-31 16:16:39 -0500124 textureMatrices.back().preRotate(45.f, a.centerX(), a.centerY());
125 textureMatrices.back().postSkew(.05f, -.05f);
126
Brian Salomonf0334042020-01-31 16:16:39 -0500127 SkBitmap subsetBmp;
128 fBitmap.extractSubset(&subsetBmp, texelSubset);
129 subsetBmp.setImmutable();
Brian Salomonbc074a62020-03-18 10:06:13 -0400130 GrBitmapTextureMaker subsetMaker(context, subsetBmp, GrImageTexGenPolicy::kDraw);
Brian Salomone69b9ef2020-07-22 11:18:06 -0400131 auto subsetView = subsetMaker.view(mipmapped);
Brian Salomonf0334042020-01-31 16:16:39 -0500132
133 SkRect localRect = SkRect::Make(fBitmap.bounds()).makeOutset(kDrawPad, kDrawPad);
134
135 auto size = this->onISize();
136
137 SkScalar y = kDrawPad + kTestPad;
138 SkRect drawRect;
139 for (int tm = 0; tm < textureMatrices.count(); ++tm) {
Brian Salomon16033c92020-02-13 11:25:11 -0500140 for (int my = 0; my < GrSamplerState::kWrapModeCount; ++my) {
Brian Salomonf0334042020-01-31 16:16:39 -0500141 SkScalar x = kDrawPad + kTestPad;
Brian Salomone69b9ef2020-07-22 11:18:06 -0400142 auto wmy = static_cast<Wrap>(my);
Brian Salomon16033c92020-02-13 11:25:11 -0500143 for (int mx = 0; mx < GrSamplerState::kWrapModeCount; ++mx) {
Brian Salomone69b9ef2020-07-22 11:18:06 -0400144 auto wmx = static_cast<Wrap>(mx);
Brian Salomon16033c92020-02-13 11:25:11 -0500145
Brian Salomonf0334042020-01-31 16:16:39 -0500146 const auto& caps = *context->priv().caps();
Brian Salomon16033c92020-02-13 11:25:11 -0500147
Brian Salomone69b9ef2020-07-22 11:18:06 -0400148 GrSamplerState sampler(wmx, wmy, fFilter, fMipmapMode);
Brian Salomon16033c92020-02-13 11:25:11 -0500149
Brian Salomonf0334042020-01-31 16:16:39 -0500150 drawRect = localRect.makeOffset(x, y);
Brian Salomon16033c92020-02-13 11:25:11 -0500151
152 std::unique_ptr<GrFragmentProcessor> fp1;
Brian Salomonb3779f52020-02-14 11:22:52 -0500153 fp1 = GrTextureEffect::MakeSubset(view,
154 fBitmap.alphaType(),
155 textureMatrices[tm],
156 sampler,
157 SkRect::Make(texelSubset),
158 caps);
Brian Salomonf46f19b2020-02-13 14:11:28 -0500159 if (!fp1) {
160 continue;
Brian Salomon16033c92020-02-13 11:25:11 -0500161 }
Brian Salomonf46f19b2020-02-13 14:11:28 -0500162
Brian Salomonf0334042020-01-31 16:16:39 -0500163 // Throw a translate in the local matrix just to test having something other
164 // than identity. Compensate with an offset local rect.
165 static constexpr SkVector kT = {-100, 300};
166 if (auto op = sk_gpu_test::test_ops::MakeRect(context,
167 std::move(fp1),
168 drawRect,
169 localRect.makeOffset(kT),
Mike Reed1f607332020-05-21 12:11:27 -0400170 SkMatrix::Translate(-kT))) {
Brian Salomon1aa1f5f2020-12-11 17:25:17 -0500171 surfaceDrawContext->addDrawOp(std::move(op));
Brian Salomonf0334042020-01-31 16:16:39 -0500172 }
Brian Salomon16033c92020-02-13 11:25:11 -0500173
Brian Salomonf0334042020-01-31 16:16:39 -0500174 x += localRect.width() + kTestPad;
175
Brian Salomon16033c92020-02-13 11:25:11 -0500176 // Now draw with a subsetted proxy using fixed function texture sampling
177 // rather than a texture subset as a comparison.
178 drawRect = localRect.makeOffset(x, y);
Brian Salomonf0334042020-01-31 16:16:39 -0500179 SkMatrix subsetTextureMatrix = SkMatrix::Concat(
Mike Reed1f607332020-05-21 12:11:27 -0400180 SkMatrix::Translate(-texelSubset.topLeft()), textureMatrices[tm]);
Brian Salomonf0334042020-01-31 16:16:39 -0500181
Brian Salomone69b9ef2020-07-22 11:18:06 -0400182 auto fp2 = GrTextureEffect::Make(subsetView,
183 fBitmap.alphaType(),
Greg Danield2ccbb52020-02-05 10:45:39 -0500184 subsetTextureMatrix,
Brian Salomone69b9ef2020-07-22 11:18:06 -0400185 sampler,
186 caps);
Brian Salomonf0334042020-01-31 16:16:39 -0500187 if (auto op = sk_gpu_test::test_ops::MakeRect(context, std::move(fp2), drawRect,
188 localRect)) {
Brian Salomon1aa1f5f2020-12-11 17:25:17 -0500189 surfaceDrawContext->addDrawOp(std::move(op));
Brian Salomonf0334042020-01-31 16:16:39 -0500190 }
Brian Salomon16033c92020-02-13 11:25:11 -0500191
192 if (mx < GrSamplerState::kWrapModeCount - 1) {
Brian Salomonf1e316f2020-02-02 07:57:38 -0500193 SkScalar midX =
194 SkScalarFloorToScalar(drawRect.right() + kTestPad/2.f) + 0.5f;
195 canvas->drawLine({midX, -1}, {midX, (float)size.fHeight+1}, {});
Brian Salomonf0334042020-01-31 16:16:39 -0500196 }
197 x += localRect.width() + kTestPad;
198 }
Brian Salomon16033c92020-02-13 11:25:11 -0500199 if (my < GrSamplerState::kWrapModeCount - 1) {
Brian Salomonf1e316f2020-02-02 07:57:38 -0500200 SkScalar midY = SkScalarFloorToScalar(drawRect.bottom() + kTestPad/2.f) + 0.5f;
201 canvas->drawLine({-1, midY}, {(float)size.fWidth+1, midY}, {});
Brian Salomonf0334042020-01-31 16:16:39 -0500202 }
203 y += localRect.height() + kTestPad;
204 }
205 if (tm < textureMatrices.count() - 1) {
206 SkPaint paint;
207 paint.setColor(SK_ColorRED);
Brian Salomonf1e316f2020-02-02 07:57:38 -0500208 SkScalar midY = SkScalarFloorToScalar(drawRect.bottom() + kTestPad/2.f) + 0.5f;
209 canvas->drawLine({-1, midY}, {(float)size.fWidth + 1, midY}, paint);
Brian Salomonf0334042020-01-31 16:16:39 -0500210 }
211 }
212 return DrawResult::kOk;
213 }
214
215private:
216 static constexpr SkISize kImageSize = {128, 88};
217 static constexpr SkScalar kDrawPad = 10.f;
218 static constexpr SkScalar kTestPad = 10.f;
219 SkBitmap fBitmap;
Brian Salomone69b9ef2020-07-22 11:18:06 -0400220 Filter fFilter;
221 MipmapMode fMipmapMode;
Brian Salomonf0334042020-01-31 16:16:39 -0500222 bool fUpscale;
223
John Stiles7571f9e2020-09-02 22:42:33 -0400224 using INHERITED = GM;
Brian Salomonf0334042020-01-31 16:16:39 -0500225};
226
Brian Salomonf7353512020-07-22 19:26:48 -0400227DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kNone , false);)
228DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kNone , true );)
229DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kNone , false);)
230DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kNone , true );)
Brian Salomonf0334042020-01-31 16:16:39 -0500231// It doesn't make sense to have upscaling MIP map.
Brian Salomonf7353512020-07-22 19:26:48 -0400232DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kNearest, false);)
233DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kNearest, false);)
234DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kLinear , false);)
235DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kLinear , false);)
Brian Salomonf0334042020-01-31 16:16:39 -0500236
John Stilesa6841be2020-08-06 14:11:56 -0400237} // namespace skiagm