blob: aad1e685d5ee7e8ae6402694dc73e25e57e0657e [file] [log] [blame]
bsalomone179a912016-01-20 06:18:10 -08001/*
2 * Copyright 2016 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
Brian Salomonf4ba4ec2020-03-19 15:54:28 -04008// This test only works with the GL backend.
bsalomone179a912016-01-20 06:18:10 -08009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "gm/gm.h"
Brian Salomonf4ba4ec2020-03-19 15:54:28 -040011
12#ifdef SK_GL
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkBitmap.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkCanvas.h"
15#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkImage.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040017#include "include/core/SkImageInfo.h"
18#include "include/core/SkPaint.h"
19#include "include/core/SkPoint.h"
20#include "include/core/SkRect.h"
21#include "include/core/SkRefCnt.h"
22#include "include/core/SkScalar.h"
23#include "include/core/SkShader.h"
24#include "include/core/SkSize.h"
25#include "include/core/SkString.h"
26#include "include/core/SkTileMode.h"
Robert Phillips08ba0852019-05-22 20:23:43 +000027#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "include/effects/SkGradientShader.h"
29#include "include/gpu/GrBackendSurface.h"
Robert Phillipsb87b39b2020-07-01 14:45:24 -040030#include "include/gpu/GrDirectContext.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040031#include "include/gpu/GrTypes.h"
Kevin Lubick77472bf2023-03-24 07:11:17 -040032#include "include/gpu/ganesh/SkImageGanesh.h"
Kevin Lubick19983e82023-08-02 13:10:28 -040033#include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
Brian Salomon0f396992020-06-19 19:51:21 -040034#include "src/core/SkAutoPixmapStorage.h"
Greg Daniel719239c2022-04-07 11:20:24 -040035#include "src/gpu/ganesh/GrDirectContextPriv.h"
36#include "src/gpu/ganesh/GrGpu.h"
37#include "src/gpu/ganesh/gl/GrGLCaps.h"
Kevin Lubicka78c1f12023-05-30 15:50:37 -040038#include "src/gpu/ganesh/gl/GrGLDefines.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040039
40#include <algorithm>
41#include <cstdint>
42#include <memory>
43
bsalomone179a912016-01-20 06:18:10 -080044namespace skiagm {
Robert Phillipsedcd4312021-06-03 10:14:16 -040045class RectangleTexture : public GM {
bsalomone179a912016-01-20 06:18:10 -080046public:
47 RectangleTexture() {
48 this->setBGColor(0xFFFFFFFF);
49 }
50
Brian Salomon3fcf83a2020-02-23 21:29:01 -050051private:
52 enum class ImageType {
53 kGradientCircle,
54 k2x2
55 };
56
Leandro Lovisolo24fa2112023-08-15 19:05:17 +000057 SkString getName() const override { return SkString("rectangle_texture"); }
bsalomone179a912016-01-20 06:18:10 -080058
Leandro Lovisolo8f023882023-08-15 21:13:52 +000059 SkISize getISize() override { return SkISize::Make(1180, 710); }
bsalomone179a912016-01-20 06:18:10 -080060
Brian Salomon3fcf83a2020-02-23 21:29:01 -050061 SkBitmap makeImagePixels(int size, ImageType type) {
62 auto ii = SkImageInfo::Make(size, size, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
63 switch (type) {
64 case ImageType::kGradientCircle: {
65 SkBitmap bmp;
66 bmp.allocPixels(ii);
67 SkPaint paint;
68 SkCanvas canvas(bmp);
69 SkPoint pts[] = {{0, 0}, {0, SkIntToScalar(size)}};
70 SkColor colors0[] = {0xFF1060B0, 0xFF102030};
71 paint.setShader(
72 SkGradientShader::MakeLinear(pts, colors0, nullptr, 2, SkTileMode::kClamp));
73 canvas.drawPaint(paint);
74 SkColor colors1[] = {0xFFA07010, 0xFFA02080};
75 paint.setAntiAlias(true);
76 paint.setShader(
77 SkGradientShader::MakeLinear(pts, colors1, nullptr, 2, SkTileMode::kClamp));
78 canvas.drawCircle(size/2.f, size/2.f, 2.f*size/5, paint);
79 return bmp;
80 }
81 case ImageType::k2x2: {
82 SkBitmap bmp;
83 bmp.allocPixels(ii);
84 *bmp.getAddr32(0, 0) = 0xFF0000FF;
85 *bmp.getAddr32(1, 0) = 0xFF00FF00;
86 *bmp.getAddr32(0, 1) = 0xFFFF0000;
87 *bmp.getAddr32(1, 1) = 0xFFFFFFFF;
88 return bmp;
89 }
90 }
91 SkUNREACHABLE;
bsalomone179a912016-01-20 06:18:10 -080092 }
93
Adlai Hollere34b2822020-07-29 12:50:56 -040094 sk_sp<SkImage> createRectangleTextureImg(GrDirectContext* dContext, GrSurfaceOrigin origin,
Brian Salomon3fcf83a2020-02-23 21:29:01 -050095 const SkBitmap content) {
96 SkASSERT(content.colorType() == kRGBA_8888_SkColorType);
Kevin Lubick19983e82023-08-02 13:10:28 -040097 auto format = GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_RECTANGLE);
Aditya Kushwah8acbc3c2022-08-24 09:31:11 -070098 auto bet = dContext->createBackendTexture(content.width(),
99 content.height(),
100 format,
Kevin Lubickdf73d162023-09-11 11:56:53 -0400101 skgpu::Mipmapped::kNo,
Aditya Kushwah8acbc3c2022-08-24 09:31:11 -0700102 GrRenderable::kNo,
103 GrProtected::kNo,
104 /*label=*/"CreateRectangleTextureImage");
Brian Salomon0f396992020-06-19 19:51:21 -0400105 if (!bet.isValid()) {
Mike Klein16b1efb2019-04-02 10:01:11 -0400106 return nullptr;
107 }
Brian Salomonb5f880a2020-12-07 11:30:16 -0500108 if (!dContext->updateBackendTexture(bet, content.pixmap(), origin, nullptr, nullptr)) {
Adlai Hollere34b2822020-07-29 12:50:56 -0400109 dContext->deleteBackendTexture(bet);
bsalomone179a912016-01-20 06:18:10 -0800110 }
Kevin Lubick77472bf2023-03-24 07:11:17 -0400111 return SkImages::AdoptTextureFrom(dContext, bet, origin, kRGBA_8888_SkColorType);
bsalomone179a912016-01-20 06:18:10 -0800112 }
113
Brian Salomonc759bbf2023-12-05 11:11:27 -0500114 DrawResult onGpuSetup(SkCanvas* canvas, SkString* errorMsg, GraphiteTestContext*) override {
Jim Van Vertha8624432023-02-13 16:48:09 -0500115 auto context = GrAsDirectContext(canvas->recordingContext());
Robert Phillipse3939012020-06-26 08:08:22 -0400116 if (!context || context->abandoned()) {
117 return DrawResult::kSkip;
118 }
119
Brian Salomon0f396992020-06-19 19:51:21 -0400120 if (context->backend() != GrBackendApi::kOpenGL_GrBackend ||
121 !static_cast<const GrGLCaps*>(context->priv().caps())->rectangleTextureSupport()) {
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500122 *errorMsg = "This GM requires an OpenGL context that supports texture rectangles.";
Mike Klein16b1efb2019-04-02 10:01:11 -0400123 return DrawResult::kSkip;
124 }
125
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500126 auto gradCircle = this->makeImagePixels(50, ImageType::kGradientCircle);
bsalomone179a912016-01-20 06:18:10 -0800127
Robert Phillipse3939012020-06-26 08:08:22 -0400128 fGradImgs[0] = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin,
129 gradCircle);
130 fGradImgs[1] = this->createRectangleTextureImg(context, kBottomLeft_GrSurfaceOrigin,
131 gradCircle);
132 SkASSERT(SkToBool(fGradImgs[0]) == SkToBool(fGradImgs[1]));
133 if (!fGradImgs[0]) {
134 *errorMsg = "Could not create gradient rectangle texture images.";
Chris Dalton50e24d72019-02-07 16:20:09 -0700135 return DrawResult::kFail;
bsalomone179a912016-01-20 06:18:10 -0800136 }
137
Robert Phillipse3939012020-06-26 08:08:22 -0400138 fSmallImg = this->createRectangleTextureImg(context, kTopLeft_GrSurfaceOrigin,
139 this->makeImagePixels(2, ImageType::k2x2));
140 if (!fSmallImg) {
141 *errorMsg = "Could not create 2x2 rectangle texture image.";
142 return DrawResult::kFail;
143 }
144
145 return DrawResult::kOk;
146 }
147
148 void onGpuTeardown() override {
149 fGradImgs[0] = fGradImgs[1] = nullptr;
150 fSmallImg = nullptr;
151 }
152
Robert Phillipsedcd4312021-06-03 10:14:16 -0400153 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
Robert Phillipse3939012020-06-26 08:08:22 -0400154 SkASSERT(fGradImgs[0] && fGradImgs[1] && fSmallImg);
155
156 static constexpr SkScalar kPad = 5.f;
157
Mike Reed039f1362021-01-27 21:21:08 -0500158 const SkSamplingOptions kSamplings[] = {
159 SkSamplingOptions(SkFilterMode::kNearest),
160 SkSamplingOptions(SkFilterMode::kLinear),
161 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
Mike Reedf3ac2af2021-02-05 12:55:38 -0500162 SkSamplingOptions(SkCubicResampler::Mitchell()),
bsalomone179a912016-01-20 06:18:10 -0800163 };
164
Brian Salomon246bc3d2018-12-06 15:33:02 -0500165 constexpr SkScalar kScales[] = {1.0f, 1.2f, 0.75f};
bsalomone179a912016-01-20 06:18:10 -0800166
167 canvas->translate(kPad, kPad);
Robert Phillipse3939012020-06-26 08:08:22 -0400168 for (size_t i = 0; i < kNumGradImages; ++i) {
169 auto img = fGradImgs[i];
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500170 int w = img->width();
171 int h = img->height();
John Stilesacf71642021-08-12 22:33:57 -0400172 for (auto scale : kScales) {
Brian Salomon246bc3d2018-12-06 15:33:02 -0500173 canvas->save();
John Stilesacf71642021-08-12 22:33:57 -0400174 canvas->scale(scale, scale);
Mike Reed039f1362021-01-27 21:21:08 -0500175 for (auto s : kSamplings) {
Brian Salomon246bc3d2018-12-06 15:33:02 -0500176 // drawImage
Mike Reed039f1362021-01-27 21:21:08 -0500177 canvas->drawImage(img, 0, 0, s);
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500178 canvas->translate(w + kPad, 0);
bsalomone179a912016-01-20 06:18:10 -0800179
Brian Salomon246bc3d2018-12-06 15:33:02 -0500180 // clamp/clamp shader
181 SkPaint clampPaint;
Mike Reed039f1362021-01-27 21:21:08 -0500182 clampPaint.setShader(fGradImgs[i]->makeShader(s));
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500183 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), clampPaint);
184 canvas->translate(1.5f*w + kPad, 0);
bsalomone179a912016-01-20 06:18:10 -0800185
Brian Salomon246bc3d2018-12-06 15:33:02 -0500186 // repeat/mirror shader
187 SkPaint repeatPaint;
Robert Phillipse3939012020-06-26 08:08:22 -0400188 repeatPaint.setShader(fGradImgs[i]->makeShader(SkTileMode::kRepeat,
Mike Reedb86cd3d2020-12-10 14:55:43 -0500189 SkTileMode::kMirror,
Mike Reed039f1362021-01-27 21:21:08 -0500190 s));
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500191 canvas->drawRect(SkRect::MakeWH(1.5f*w, 1.5f*h), repeatPaint);
192 canvas->translate(1.5f*w + kPad, 0);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500193
194 // drawImageRect with kStrict
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500195 auto srcRect = SkRect::MakeXYWH(.25f*w, .25f*h, .50f*w, .50f*h);
196 auto dstRect = SkRect::MakeXYWH( 0, 0, .50f*w, .50f*h);
Mike Reed039f1362021-01-27 21:21:08 -0500197 canvas->drawImageRect(fGradImgs[i], srcRect, dstRect, s, nullptr,
Brian Salomon246bc3d2018-12-06 15:33:02 -0500198 SkCanvas::kStrict_SrcRectConstraint);
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500199 canvas->translate(.5f*w + kPad, 0);
Brian Salomon246bc3d2018-12-06 15:33:02 -0500200 }
201 canvas->restore();
John Stilesacf71642021-08-12 22:33:57 -0400202 canvas->translate(0, kPad + 1.5f*h*scale);
bsalomone179a912016-01-20 06:18:10 -0800203 }
bsalomone179a912016-01-20 06:18:10 -0800204 }
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500205
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500206 static constexpr SkScalar kOutset = 25.f;
207 canvas->translate(kOutset, kOutset);
Robert Phillipse3939012020-06-26 08:08:22 -0400208 auto dstRect = SkRect::Make(fSmallImg->dimensions()).makeOutset(kOutset, kOutset);
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500209
Mike Reed2bdf6ed2021-07-15 21:34:48 -0400210 const SkSamplingOptions gSamplings[] = {
211 SkSamplingOptions(SkFilterMode::kNearest),
212 SkSamplingOptions(SkFilterMode::kLinear),
213 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
214 SkSamplingOptions(SkCubicResampler::Mitchell()),
215 };
216
217 for (const auto& sampling : gSamplings) {
218 if (!sampling.useCubic && sampling.mipmap != SkMipmapMode::kNone) {
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500219 // Medium is the same as Low for upscaling.
220 continue;
221 }
222 canvas->save();
223 for (int ty = 0; ty < kSkTileModeCount; ++ty) {
224 canvas->save();
225 for (int tx = 0; tx < kSkTileModeCount; ++tx) {
226 SkMatrix lm;
227 lm.setRotate(45.f, 1, 1);
228 lm.postScale(6.5f, 6.5f);
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500229 SkPaint paint;
Mike Reedb86cd3d2020-12-10 14:55:43 -0500230 paint.setShader(fSmallImg->makeShader(static_cast<SkTileMode>(tx),
231 static_cast<SkTileMode>(ty),
Mike Reed2bdf6ed2021-07-15 21:34:48 -0400232 sampling,
Mike Reedb86cd3d2020-12-10 14:55:43 -0500233 lm));
Brian Salomon3fcf83a2020-02-23 21:29:01 -0500234 canvas->drawRect(dstRect, paint);
235 canvas->translate(dstRect.width() + kPad, 0);
236 }
237 canvas->restore();
238 canvas->translate(0, dstRect.height() + kPad);
239 }
240 canvas->restore();
241 canvas->translate((dstRect.width() + kPad)*kSkTileModeCount, 0);
242 }
243
Chris Dalton50e24d72019-02-07 16:20:09 -0700244 return DrawResult::kOk;
bsalomone179a912016-01-20 06:18:10 -0800245 }
246
247private:
Robert Phillipse3939012020-06-26 08:08:22 -0400248 static const int kNumGradImages = 2;
249
250 sk_sp<SkImage> fGradImgs[kNumGradImages];
251 sk_sp<SkImage> fSmallImg;
252
John Stiles7571f9e2020-09-02 22:42:33 -0400253 using INHERITED = GM;
bsalomone179a912016-01-20 06:18:10 -0800254};
255
256DEF_GM(return new RectangleTexture;)
John Stilesa6841be2020-08-06 14:11:56 -0400257} // namespace skiagm
Brian Salomonf4ba4ec2020-03-19 15:54:28 -0400258#endif