1 /*
2 * Copyright 2013 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 "src/gpu/ganesh/effects/GrBitmapTextGeoProc.h"
9
10 #include "include/core/SkSamplingOptions.h"
11 #include "include/private/base/SkAssert.h"
12 #include "include/private/base/SkMath.h"
13 #include "include/private/gpu/ganesh/GrTypesPriv.h"
14 #include "src/base/SkRandom.h"
15 #include "src/core/SkSLTypeShared.h"
16 #include "src/gpu/AtlasTypes.h"
17 #include "src/gpu/KeyBuilder.h"
18 #include "src/gpu/ganesh/GrCaps.h"
19 #include "src/gpu/ganesh/GrColor.h"
20 #include "src/gpu/ganesh/GrShaderCaps.h"
21 #include "src/gpu/ganesh/GrShaderVar.h"
22 #include "src/gpu/ganesh/GrSurfaceProxy.h"
23 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
24 #include "src/gpu/ganesh/GrTestUtils.h"
25 #include "src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h"
26 #include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
27 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
28 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
29 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
30 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
31
32 #include <algorithm>
33
34 class GrGLSLVertexBuilder;
35
36 using MaskFormat = skgpu::MaskFormat;
37
38 class GrBitmapTextGeoProc::Impl : public ProgramImpl {
39 public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)40 void setData(const GrGLSLProgramDataManager& pdman,
41 const GrShaderCaps& shaderCaps,
42 const GrGeometryProcessor& geomProc) override {
43 const GrBitmapTextGeoProc& btgp = geomProc.cast<GrBitmapTextGeoProc>();
44 if (btgp.fColor != fColor && !btgp.hasVertexColor()) {
45 pdman.set4fv(fColorUniform, 1, btgp.fColor.vec());
46 fColor = btgp.fColor;
47 }
48
49 const SkISize& atlasDimensions = btgp.fAtlasDimensions;
50 SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight));
51
52 if (fAtlasDimensions != atlasDimensions) {
53 pdman.set2f(fAtlasDimensionsInvUniform,
54 1.0f / atlasDimensions.fWidth,
55 1.0f / atlasDimensions.fHeight);
56 fAtlasDimensions = atlasDimensions;
57 }
58
59 SetTransform(pdman, shaderCaps, fLocalMatrixUniform, btgp.fLocalMatrix, &fLocalMatrix);
60 fColorSpaceXformHelper.setData(pdman, btgp.fColorSpaceXform.get());
61 }
62
63 private:
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)64 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
65 const GrBitmapTextGeoProc& btgp = args.fGeomProc.cast<GrBitmapTextGeoProc>();
66
67 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
68 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
69 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
70
71 fColorSpaceXformHelper.emitCode(uniformHandler,
72 btgp.fColorSpaceXform.get());
73
74 // emit attributes
75 varyingHandler->emitAttributes(btgp);
76
77 const char* atlasDimensionsInvName;
78 fAtlasDimensionsInvUniform = uniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
79 SkSLType::kFloat2, "AtlasSizeInv", &atlasDimensionsInvName);
80
81 GrGLSLVarying uv, texIdx;
82 append_index_uv_varyings(args,
83 btgp.numTextureSamplers(),
84 btgp.fInTextureCoords.name(),
85 atlasDimensionsInvName,
86 &uv,
87 &texIdx,
88 nullptr);
89
90 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
91 // Setup pass through color
92 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
93 if (btgp.hasVertexColor()) {
94 varyingHandler->addPassThroughAttribute(btgp.fInColor.asShaderVar(), args.fOutputColor);
95 } else {
96 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
97 &fColorUniform);
98 }
99
100 // Setup position
101 gpArgs->fPositionVar = btgp.fInPosition.asShaderVar();
102 WriteLocalCoord(vertBuilder,
103 uniformHandler,
104 *args.fShaderCaps,
105 gpArgs,
106 btgp.fInPosition.asShaderVar(),
107 btgp.fLocalMatrix,
108 &fLocalMatrixUniform);
109
110 fragBuilder->codeAppend("half4 texColor;");
111 append_multitexture_lookup(args, btgp.numTextureSamplers(),
112 texIdx, uv.fsIn(), "texColor");
113 if (!fColorSpaceXformHelper.isNoop()) {
114 fragBuilder->codeAppend("texColor = ");
115 fragBuilder->appendColorGamutXform("texColor", &fColorSpaceXformHelper);
116 fragBuilder->codeAppend(";");
117 }
118
119 if (btgp.fMaskFormat == MaskFormat::kARGB) {
120 // modulate by color
121 fragBuilder->codeAppendf("%s = %s * texColor;", args.fOutputColor, args.fOutputColor);
122 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
123 } else {
124 fragBuilder->codeAppendf("half4 %s = texColor;", args.fOutputCoverage);
125 }
126 }
127
128 private:
129 SkPMColor4f fColor = SK_PMColor4fILLEGAL;
130 SkISize fAtlasDimensions = {-1, -1};
131 SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
132
133 UniformHandle fColorUniform;
134 UniformHandle fAtlasDimensionsInvUniform;
135 UniformHandle fLocalMatrixUniform;
136
137 GrGLSLColorSpaceXformHelper fColorSpaceXformHelper;
138 };
139
140 ///////////////////////////////////////////////////////////////////////////////
141
GrBitmapTextGeoProc(const GrShaderCaps & caps,const SkPMColor4f & color,bool wideColor,sk_sp<GrColorSpaceXform> colorSpaceXform,const GrSurfaceProxyView * views,int numActiveViews,GrSamplerState params,MaskFormat format,const SkMatrix & localMatrix,bool usesW)142 GrBitmapTextGeoProc::GrBitmapTextGeoProc(const GrShaderCaps& caps,
143 const SkPMColor4f& color,
144 bool wideColor,
145 sk_sp<GrColorSpaceXform> colorSpaceXform,
146 const GrSurfaceProxyView* views,
147 int numActiveViews,
148 GrSamplerState params,
149 MaskFormat format,
150 const SkMatrix& localMatrix,
151 bool usesW)
152 : INHERITED(kGrBitmapTextGeoProc_ClassID)
153 , fColor(color)
154 , fColorSpaceXform(std::move(colorSpaceXform))
155 , fLocalMatrix(localMatrix)
156 , fUsesW(usesW)
157 , fMaskFormat(format) {
158 SkASSERT(numActiveViews <= kMaxTextures);
159
160 if (usesW) {
161 fInPosition = {"inPosition", kFloat3_GrVertexAttribType, SkSLType::kFloat3};
162 } else {
163 fInPosition = {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
164 }
165
166 bool hasVertexColor = MaskFormat::kA8 == fMaskFormat || MaskFormat::kA565 == fMaskFormat;
167 if (hasVertexColor) {
168 fInColor = MakeColorAttribute("inColor", wideColor);
169 }
170
171 fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
172 caps.fIntegerSupport ? SkSLType::kUShort2 : SkSLType::kFloat2};
173 this->setVertexAttributesWithImplicitOffsets(&fInPosition, 3);
174
175 if (numActiveViews) {
176 fAtlasDimensions = views[0].proxy()->dimensions();
177 }
178 for (int i = 0; i < numActiveViews; ++i) {
179 const GrSurfaceProxy* proxy = views[i].proxy();
180 SkASSERT(proxy);
181 SkASSERT(proxy->dimensions() == fAtlasDimensions);
182 fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle());
183 }
184 this->setTextureSamplerCnt(numActiveViews);
185 }
186
addNewViews(const GrSurfaceProxyView * views,int numActiveViews,GrSamplerState params)187 void GrBitmapTextGeoProc::addNewViews(const GrSurfaceProxyView* views,
188 int numActiveViews,
189 GrSamplerState params) {
190 SkASSERT(numActiveViews <= kMaxTextures);
191 // Just to make sure we don't try to add too many proxies
192 numActiveViews = std::min(numActiveViews, kMaxTextures);
193
194 if (!fTextureSamplers[0].isInitialized()) {
195 fAtlasDimensions = views[0].proxy()->dimensions();
196 }
197
198 for (int i = 0; i < numActiveViews; ++i) {
199 const GrSurfaceProxy* proxy = views[i].proxy();
200 SkASSERT(proxy);
201 SkASSERT(proxy->dimensions() == fAtlasDimensions);
202
203 if (!fTextureSamplers[i].isInitialized()) {
204 fTextureSamplers[i].reset(params, proxy->backendFormat(), views[i].swizzle());
205 }
206 }
207 this->setTextureSamplerCnt(numActiveViews);
208 }
209
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const210 void GrBitmapTextGeoProc::addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
211 b->addBool(fUsesW, "usesW");
212 static_assert(static_cast<int>(MaskFormat::kLast) < (1u << 2));
213 b->addBits(2, static_cast<int>(fMaskFormat), "maskFormat");
214 b->addBits(ProgramImpl::kMatrixKeyBits,
215 ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix),
216 "localMatrixType");
217 b->add32(this->numTextureSamplers(), "numTextures");
218 b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()), "colorSpaceXform");
219 }
220
makeProgramImpl(const GrShaderCaps & caps) const221 std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrBitmapTextGeoProc::makeProgramImpl(
222 const GrShaderCaps& caps) const {
223 return std::make_unique<Impl>();
224 }
225
226 ///////////////////////////////////////////////////////////////////////////////
227
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc)228 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc)
229
230 #if defined(GPU_TEST_UTILS)
231
232 GrGeometryProcessor* GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) {
233 auto [view, ct, at] = d->randomView();
234
235 GrSamplerState::WrapMode wrapModes[2];
236 GrTest::TestWrapModes(d->fRandom, wrapModes);
237 GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
238 ? GrSamplerState::Filter::kLinear
239 : GrSamplerState::Filter::kNearest);
240
241 MaskFormat format;
242 switch (ct) {
243 case GrColorType::kAlpha_8:
244 format = MaskFormat::kA8;
245 break;
246 case GrColorType::kBGR_565:
247 format = MaskFormat::kA565;
248 break;
249 case GrColorType::kRGBA_8888:
250 default: // It doesn't really matter that color type and mask format agree.
251 format = MaskFormat::kARGB;
252 break;
253 }
254
255 GrColor color = GrTest::RandomColor(d->fRandom);
256 bool wideColor = d->fRandom->nextBool();
257 SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
258 bool usesW = d->fRandom->nextBool();
259 return GrBitmapTextGeoProc::Make(d->allocator(), *d->caps()->shaderCaps(),
260 SkPMColor4f::FromBytes_RGBA(color),
261 wideColor, /*colorSpaceXform=*/nullptr,
262 &view, 1, samplerState, format,
263 localMatrix, usesW);
264 }
265 #endif
266