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#include "GrFontAtlasSizes.h"
10#include "GrInvariantOutput.h"
11#include "GrTexture.h"
12#include "gl/GrGLProcessor.h"
13#include "gl/GrGLSL.h"
14#include "gl/GrGLTexture.h"
15#include "gl/GrGLGeometryProcessor.h"
16#include "gl/builders/GrGLProgramBuilder.h"
17
18struct BitmapTextBatchTracker {
19    GrGPInput fInputColorType;
20    GrColor fColor;
21    bool fUsesLocalCoords;
22};
23
24class GrGLBitmapTextGeoProc : public GrGLGeometryProcessor {
25public:
26    GrGLBitmapTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&)
27        : fColor(GrColor_ILLEGAL) {}
28
29    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
30        const GrBitmapTextGeoProc& cte = args.fGP.cast<GrBitmapTextGeoProc>();
31        const BitmapTextBatchTracker& local = args.fBT.cast<BitmapTextBatchTracker>();
32
33        GrGLGPBuilder* pb = args.fPB;
34        GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder();
35
36        // emit attributes
37        vsBuilder->emitAttributes(cte);
38
39        GrGLVertToFrag v(kVec2f_GrSLType);
40        pb->addVarying("TextureCoords", &v);
41        // this is only used with text, so our texture bounds always match the glyph atlas
42        if (cte.maskFormat() == kA8_GrMaskFormat) {
43            vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
44                                   GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", v.vsOut(),
45                                   cte.inTextureCoords()->fName);
46        } else {
47            vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_RECIP_WIDTH ", "
48                                   GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", v.vsOut(),
49                                   cte.inTextureCoords()->fName);
50        }
51
52        // Setup pass through color
53        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, cte.inColor(),
54                                    &fColorUniform);
55
56        // Setup position
57        this->setupPosition(pb, gpArgs, cte.inPosition()->fName);
58
59        // emit transforms
60        this->emitTransforms(args.fPB, gpArgs->fPositionVar, cte.inPosition()->fName,
61                             cte.localMatrix(), args.fTransformsIn, args.fTransformsOut);
62
63        GrGLFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
64        if (cte.maskFormat() == kARGB_GrMaskFormat) {
65            fsBuilder->codeAppendf("%s = ", args.fOutputColor);
66            fsBuilder->appendTextureLookupAndModulate(args.fOutputColor,
67                                                      args.fSamplers[0],
68                                                      v.fsIn(),
69                                                      kVec2f_GrSLType);
70            fsBuilder->codeAppend(";");
71            fsBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
72        } else {
73            fsBuilder->codeAppendf("%s = ", args.fOutputCoverage);
74            fsBuilder->appendTextureLookup(args.fSamplers[0], v.fsIn(), kVec2f_GrSLType);
75            fsBuilder->codeAppend(";");
76        }
77    }
78
79    virtual void setData(const GrGLProgramDataManager& pdman,
80                         const GrPrimitiveProcessor& gp,
81                         const GrBatchTracker& bt) override {
82        const BitmapTextBatchTracker& local = bt.cast<BitmapTextBatchTracker>();
83        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
84            GrGLfloat c[4];
85            GrColorToRGBAFloat(local.fColor, c);
86            pdman.set4fv(fColorUniform, 1, c);
87            fColor = local.fColor;
88        }
89    }
90
91    void setTransformData(const GrPrimitiveProcessor& primProc,
92                          const GrGLProgramDataManager& pdman,
93                          int index,
94                          const SkTArray<const GrCoordTransform*, true>& transforms) override {
95        this->setTransformDataHelper<GrBitmapTextGeoProc>(primProc, pdman, index, transforms);
96    }
97
98    static inline void GenKey(const GrGeometryProcessor& proc,
99                              const GrBatchTracker& bt,
100                              const GrGLSLCaps&,
101                              GrProcessorKeyBuilder* b) {
102        const BitmapTextBatchTracker& local = bt.cast<BitmapTextBatchTracker>();
103        // We have to put the optional vertex attribute as part of the key.  See the comment
104        // on addVertexAttrib.
105        // TODO When we have deferred geometry we can fix this
106        const GrBitmapTextGeoProc& gp = proc.cast<GrBitmapTextGeoProc>();
107        uint32_t key = 0;
108        key |= SkToBool(gp.inColor()) ? 0x1 : 0x0;
109        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x2 : 0x0;
110        key |= gp.maskFormat() == kARGB_GrMaskFormat ? 0x4 : 0x0;
111        b->add32(local.fInputColorType << 16 | key);
112    }
113
114private:
115    GrColor fColor;
116    UniformHandle fColorUniform;
117
118    typedef GrGLGeometryProcessor INHERITED;
119};
120
121///////////////////////////////////////////////////////////////////////////////
122
123GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture,
124                                         const GrTextureParams& params, GrMaskFormat format,
125                                         const SkMatrix& localMatrix)
126    : fColor(color)
127    , fLocalMatrix(localMatrix)
128    , fTextureAccess(texture, params)
129    , fInColor(NULL)
130    , fMaskFormat(format) {
131    this->initClassID<GrBitmapTextGeoProc>();
132    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
133
134    bool hasVertexColor = kA8_GrMaskFormat == fMaskFormat;
135    if (hasVertexColor) {
136        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
137    }
138    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
139                                                        kVec2s_GrVertexAttribType));
140    this->addTextureAccess(&fTextureAccess);
141}
142
143void GrBitmapTextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
144                                            const GrGLSLCaps& caps,
145                                            GrProcessorKeyBuilder* b) const {
146    GrGLBitmapTextGeoProc::GenKey(*this, bt, caps, b);
147}
148
149GrGLPrimitiveProcessor*
150GrBitmapTextGeoProc::createGLInstance(const GrBatchTracker& bt,
151                                      const GrGLSLCaps& caps) const {
152    return SkNEW_ARGS(GrGLBitmapTextGeoProc, (*this, bt));
153}
154
155void GrBitmapTextGeoProc::initBatchTracker(GrBatchTracker* bt, const GrPipelineInfo& init) const {
156    BitmapTextBatchTracker* local = bt->cast<BitmapTextBatchTracker>();
157    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
158                                               SkToBool(fInColor));
159    local->fUsesLocalCoords = init.fUsesLocalCoords;
160}
161
162///////////////////////////////////////////////////////////////////////////////
163
164GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
165
166GrGeometryProcessor* GrBitmapTextGeoProc::TestCreate(SkRandom* random,
167                                                     GrContext*,
168                                                     const GrDrawTargetCaps&,
169                                                     GrTexture* textures[]) {
170    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
171                                      GrProcessorUnitTest::kAlphaTextureIdx;
172    static const SkShader::TileMode kTileModes[] = {
173        SkShader::kClamp_TileMode,
174        SkShader::kRepeat_TileMode,
175        SkShader::kMirror_TileMode,
176    };
177    SkShader::TileMode tileModes[] = {
178        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
179        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
180    };
181    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
182                                                           GrTextureParams::kNone_FilterMode);
183
184    GrMaskFormat format;
185    switch (random->nextULessThan(3)) {
186        default:
187            SkFAIL("Incomplete enum\n");
188        case 0:
189            format = kA8_GrMaskFormat;
190            break;
191        case 1:
192            format = kA565_GrMaskFormat;
193            break;
194        case 2:
195            format = kARGB_GrMaskFormat;
196            break;
197    }
198
199    return GrBitmapTextGeoProc::Create(GrRandomColor(random), textures[texIdx], params,
200                                       format, GrTest::TestMatrix(random));
201}
202