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 "GrBitmapTextGeoProc.h"
9
10#include "GrAtlasedShaderHelpers.h"
11#include "GrTexture.h"
12#include "glsl/GrGLSLFragmentShaderBuilder.h"
13#include "glsl/GrGLSLGeometryProcessor.h"
14#include "glsl/GrGLSLProgramDataManager.h"
15#include "glsl/GrGLSLUniformHandler.h"
16#include "glsl/GrGLSLVarying.h"
17#include "glsl/GrGLSLVertexGeoBuilder.h"
18
19class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor {
20public:
21    GrGLBitmapTextGeoProc() : fColor(GrColor_ILLEGAL), fAtlasSize({0,0}) {}
22
23    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
24        const GrBitmapTextGeoProc& btgp = args.fGP.cast<GrBitmapTextGeoProc>();
25
26        GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
27        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
28        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
29
30        // emit attributes
31        varyingHandler->emitAttributes(btgp);
32
33        const char* atlasSizeInvName;
34        fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
35                                                          kFloat2_GrSLType,
36                                                          kHigh_GrSLPrecision,
37                                                          "AtlasSizeInv",
38                                                          &atlasSizeInvName);
39
40        GrGLSLVarying uv(kFloat2_GrSLType);
41        GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
42        GrGLSLVarying texIdx(texIdxType);
43        append_index_uv_varyings(args, btgp.inTextureCoords()->fName, atlasSizeInvName,
44                                 &uv, &texIdx, nullptr);
45
46        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
47        // Setup pass through color
48        if (btgp.hasVertexColor()) {
49            varyingHandler->addPassThroughAttribute(btgp.inColor(), args.fOutputColor);
50        } else {
51            this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
52                                    &fColorUniform);
53        }
54
55        // Setup position
56        this->writeOutputPosition(vertBuilder, gpArgs, btgp.inPosition()->fName);
57
58        // emit transforms
59        this->emitTransforms(vertBuilder,
60                             varyingHandler,
61                             uniformHandler,
62                             btgp.inPosition()->asShaderVar(),
63                             btgp.localMatrix(),
64                             args.fFPCoordTransformHandler);
65
66        fragBuilder->codeAppend("half4 texColor;");
67        append_multitexture_lookup(args, btgp.numTextureSamplers(),
68                                   texIdx, uv.fsIn(), "texColor");
69
70        if (btgp.maskFormat() == kARGB_GrMaskFormat) {
71            // modulate by color
72            fragBuilder->codeAppendf("%s = %s * texColor;", args.fOutputColor, args.fOutputColor);
73            fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
74        } else {
75            fragBuilder->codeAppendf("%s = texColor;", args.fOutputCoverage);
76        }
77    }
78
79    void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp,
80                 FPCoordTransformIter&& transformIter) override {
81        const GrBitmapTextGeoProc& btgp = gp.cast<GrBitmapTextGeoProc>();
82        if (btgp.color() != fColor && !btgp.hasVertexColor()) {
83            float c[4];
84            GrColorToRGBAFloat(btgp.color(), c);
85            pdman.set4fv(fColorUniform, 1, c);
86            fColor = btgp.color();
87        }
88
89        SkASSERT(btgp.numTextureSamplers() >= 1);
90        GrTexture* atlas = btgp.textureSampler(0).peekTexture();
91        SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
92
93        if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
94            pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
95            fAtlasSize.set(atlas->width(), atlas->height());
96        }
97        this->setTransformDataHelper(btgp.localMatrix(), pdman, &transformIter);
98    }
99
100    static inline void GenKey(const GrGeometryProcessor& proc,
101                              const GrShaderCaps&,
102                              GrProcessorKeyBuilder* b) {
103        const GrBitmapTextGeoProc& btgp = proc.cast<GrBitmapTextGeoProc>();
104        uint32_t key = 0;
105        key |= (btgp.usesLocalCoords() && btgp.localMatrix().hasPerspective()) ? 0x1 : 0x0;
106        key |= btgp.maskFormat() << 1;
107        b->add32(key);
108        b->add32(btgp.numTextureSamplers());
109    }
110
111private:
112    GrColor       fColor;
113    UniformHandle fColorUniform;
114
115    SkISize       fAtlasSize;
116    UniformHandle fAtlasSizeInvUniform;
117
118    typedef GrGLSLGeometryProcessor INHERITED;
119};
120
121///////////////////////////////////////////////////////////////////////////////
122
123GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color,
124                                         const sk_sp<GrTextureProxy>* proxies,
125                                         int numProxies,
126                                         const GrSamplerState& params, GrMaskFormat format,
127                                         const SkMatrix& localMatrix, bool usesLocalCoords)
128        : INHERITED(kGrBitmapTextGeoProc_ClassID)
129        , fColor(color)
130        , fLocalMatrix(localMatrix)
131        , fUsesLocalCoords(usesLocalCoords)
132        , fInColor(nullptr)
133        , fMaskFormat(format) {
134    SkASSERT(numProxies <= kMaxTextures);
135
136    fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
137
138    bool hasVertexColor = kA8_GrMaskFormat == fMaskFormat ||
139                          kA565_GrMaskFormat == fMaskFormat;
140    if (hasVertexColor) {
141        fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
142    }
143
144    fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kUShort2_GrVertexAttribType);
145    for (int i = 0; i < numProxies; ++i) {
146        SkASSERT(proxies[i]);
147
148        fTextureSamplers[i].reset(std::move(proxies[i]), params);
149        this->addTextureSampler(&fTextureSamplers[i]);
150    }
151}
152
153void GrBitmapTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
154                                        int numProxies,
155                                        const GrSamplerState& params) {
156    SkASSERT(numProxies <= kMaxTextures);
157
158    for (int i = 0; i < numProxies; ++i) {
159        SkASSERT(proxies[i]);
160
161        if (!fTextureSamplers[i].isInitialized()) {
162            fTextureSamplers[i].reset(std::move(proxies[i]), params);
163            this->addTextureSampler(&fTextureSamplers[i]);
164        }
165    }
166}
167
168void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
169                                              GrProcessorKeyBuilder* b) const {
170    GrGLBitmapTextGeoProc::GenKey(*this, caps, b);
171}
172
173GrGLSLPrimitiveProcessor* GrBitmapTextGeoProc::createGLSLInstance(const GrShaderCaps& caps) const {
174    return new GrGLBitmapTextGeoProc();
175}
176
177///////////////////////////////////////////////////////////////////////////////
178
179GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
180
181#if GR_TEST_UTILS
182
183sk_sp<GrGeometryProcessor> GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) {
184    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
185                                        : GrProcessorUnitTest::kAlphaTextureIdx;
186    sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
187        d->textureProxy(texIdx),
188        nullptr,
189        nullptr,
190        nullptr
191    };
192
193    GrSamplerState::WrapMode wrapModes[2];
194    GrTest::TestWrapModes(d->fRandom, wrapModes);
195    GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
196                                                   ? GrSamplerState::Filter::kBilerp
197                                                   : GrSamplerState::Filter::kNearest);
198
199    GrMaskFormat format = kARGB_GrMaskFormat; // init to avoid warning
200    switch (d->fRandom->nextULessThan(3)) {
201        case 0:
202            format = kA8_GrMaskFormat;
203            break;
204        case 1:
205            format = kA565_GrMaskFormat;
206            break;
207        case 2:
208            format = kARGB_GrMaskFormat;
209            break;
210    }
211
212    return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), proxies, 1, samplerState,
213                                     format, GrTest::TestMatrix(d->fRandom),
214                                     d->fRandom->nextBool());
215}
216#endif
217