• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright 2011 Google Inc.
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8          http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15  */
16 
17 #include "GrBinHashKey.h"
18 #include "GrGLProgram.h"
19 #include "GrGpuGLShaders.h"
20 #include "GrGpuVertex.h"
21 #include "GrMemory.h"
22 #include "GrNoncopyable.h"
23 #include "GrStringBuilder.h"
24 #include "GrRandom.h"
25 
26 #define SKIP_CACHE_CHECK    true
27 #define GR_UINT32_MAX   static_cast<uint32_t>(-1)
28 
29 #include "GrTHashCache.h"
30 
31 class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
32 private:
33     class Entry;
34 
35 #if GR_DEBUG
36     typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
37 #else
38     typedef GrBinHashKey<Entry, 64> ProgramHashKey;
39 #endif
40 
41     class Entry : public ::GrNoncopyable {
42     public:
Entry()43         Entry() {}
copyAndTakeOwnership(Entry & entry)44         void copyAndTakeOwnership(Entry& entry) {
45             fProgramData.copyAndTakeOwnership(entry.fProgramData);
46             fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
47             fLRUStamp = entry.fLRUStamp;
48         }
49 
50     public:
compare(const ProgramHashKey & key) const51         int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
52 
53     public:
54         GrGLProgram::CachedData fProgramData;
55         ProgramHashKey          fKey;
56         unsigned int            fLRUStamp;
57     };
58 
59     GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
60 
61     // We may have kMaxEntries+1 shaders in the GL context because
62     // we create a new shader before evicting from the cache.
63     enum {
64         kMaxEntries = 32
65     };
66     Entry        fEntries[kMaxEntries];
67     int          fCount;
68     unsigned int fCurrLRUStamp;
69 
70 public:
ProgramCache()71     ProgramCache()
72         : fCount(0)
73         , fCurrLRUStamp(0) {
74     }
75 
~ProgramCache()76     ~ProgramCache() {
77         for (int i = 0; i < fCount; ++i) {
78             GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
79         }
80     }
81 
abandon()82     void abandon() {
83         fCount = 0;
84     }
85 
invalidateViewMatrices()86     void invalidateViewMatrices() {
87         for (int i = 0; i < fCount; ++i) {
88             // set to illegal matrix
89             fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
90         }
91     }
92 
getProgramData(const GrGLProgram & desc)93     GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
94         Entry newEntry;
95         while (newEntry.fKey.doPass()) {
96             desc.buildKey(newEntry.fKey);
97         }
98         Entry* entry = fHashCache.find(newEntry.fKey);
99         if (NULL == entry) {
100             if (!desc.genProgram(&newEntry.fProgramData)) {
101                 return NULL;
102             }
103             if (fCount < kMaxEntries) {
104                 entry = fEntries + fCount;
105                 ++fCount;
106             } else {
107                 GrAssert(kMaxEntries == fCount);
108                 entry = fEntries;
109                 for (int i = 1; i < kMaxEntries; ++i) {
110                     if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
111                         entry = fEntries + i;
112                     }
113                 }
114                 fHashCache.remove(entry->fKey, entry);
115                 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
116             }
117             entry->copyAndTakeOwnership(newEntry);
118             fHashCache.insert(entry->fKey, entry);
119         }
120 
121         entry->fLRUStamp = fCurrLRUStamp;
122         if (GR_UINT32_MAX == fCurrLRUStamp) {
123             // wrap around! just trash our LRU, one time hit.
124             for (int i = 0; i < fCount; ++i) {
125                 fEntries[i].fLRUStamp = 0;
126             }
127         }
128         ++fCurrLRUStamp;
129         return &entry->fProgramData;
130     }
131 };
132 
abandonResources()133 void GrGpuGLShaders::abandonResources(){
134     INHERITED::abandonResources();
135     fProgramCache->abandon();
136 }
137 
DeleteProgram(GrGLProgram::CachedData * programData)138 void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
139     GR_GL(DeleteShader(programData->fVShaderID));
140     GR_GL(DeleteShader(programData->fFShaderID));
141     GR_GL(DeleteProgram(programData->fProgramID));
142     GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
143 }
144 
ProgramUnitTest()145 void GrGpuGLShaders::ProgramUnitTest() {
146 
147     static const int STAGE_OPTS[] = {
148         0,
149         GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
150         GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
151     };
152     static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
153         GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
154         GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
155     };
156     static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
157         GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
158         GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
159         GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
160         GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
161     };
162     static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
163         GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
164         GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
165     };
166     GrGLProgram program;
167     GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
168 
169     static const int NUM_TESTS = 512;
170 
171     // GrRandoms nextU() values have patterns in the low bits
172     // So using nextU() % array_count might never take some values.
173     GrRandom random;
174     for (int t = 0; t < NUM_TESTS; ++t) {
175 
176 #if 0
177         GrPrintf("\nTest Program %d\n-------------\n", t);
178         static const int stop = -1;
179         if (t == stop) {
180             int breakpointhere = 9;
181         }
182 #endif
183 
184         pdesc.fVertexLayout = 0;
185         pdesc.fEmitsPointSize = random.nextF() > .5f;
186         float colorType = random.nextF();
187         if (colorType < 1.f / 3.f) {
188             pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
189         } else if (colorType < 2.f / 3.f) {
190             pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
191         } else {
192             pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
193         }
194 
195         int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
196         pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
197 
198         idx = (int)(random.nextF() * (kNumStages+1));
199         pdesc.fFirstCoverageStage = idx;
200 
201         pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
202 
203         if (fDualSourceBlendingSupport) {
204             pdesc.fDualSrcOutput =
205                (GrGLProgram::ProgramDesc::DualSrcOutput)
206                (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
207         } else {
208             pdesc.fDualSrcOutput =
209                                 GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
210         }
211 
212         for (int s = 0; s < kNumStages; ++s) {
213             // enable the stage?
214             if (random.nextF() > .5f) {
215                 // use separate tex coords?
216                 if (random.nextF() > .5f) {
217                     int t = (int)(random.nextF() * kMaxTexCoords);
218                     pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
219                 } else {
220                     pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
221                 }
222             }
223             // use text-formatted verts?
224             if (random.nextF() > .5f) {
225                 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
226             }
227             idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
228             pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
229             idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
230             pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
231             idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
232             pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
233             idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
234             pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
235             pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
236         }
237         GrGLProgram::CachedData cachedData;
238         program.genProgram(&cachedData);
239         DeleteProgram(&cachedData);
240         bool again = false;
241         if (again) {
242             program.genProgram(&cachedData);
243             DeleteProgram(&cachedData);
244         }
245     }
246 }
247 
GrGpuGLShaders()248 GrGpuGLShaders::GrGpuGLShaders() {
249 
250     resetContext();
251     int major, minor;
252     gl_version(&major, &minor);
253 
254     f4X4DownsampleFilterSupport = true;
255     if (GR_GL_SUPPORT_DESKTOP) {
256         fDualSourceBlendingSupport =
257             major > 3 ||(3 == major && 3 <= minor) ||
258             has_gl_extension("GL_ARB_blend_func_extended");
259     } else {
260         fDualSourceBlendingSupport = false;
261     }
262 
263     fProgramData = NULL;
264     fProgramCache = new ProgramCache();
265 
266 #if 0
267     ProgramUnitTest();
268 #endif
269 }
270 
~GrGpuGLShaders()271 GrGpuGLShaders::~GrGpuGLShaders() {
272     delete fProgramCache;
273 }
274 
getHWSamplerMatrix(int stage)275 const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
276     GrAssert(fProgramData);
277 
278     if (GrGLProgram::kSetAsAttribute ==
279         fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
280         return fHWDrawState.fSamplerStates[stage].getMatrix();
281     } else {
282         return fProgramData->fTextureMatrices[stage];
283     }
284 }
285 
recordHWSamplerMatrix(int stage,const GrMatrix & matrix)286 void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
287     GrAssert(fProgramData);
288     if (GrGLProgram::kSetAsAttribute ==
289         fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
290         fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
291     } else {
292         fProgramData->fTextureMatrices[stage] = matrix;
293     }
294 }
295 
resetContext()296 void GrGpuGLShaders::resetContext() {
297     INHERITED::resetContext();
298 
299     fHWGeometryState.fVertexLayout = 0;
300     fHWGeometryState.fVertexOffset = ~0;
301     GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
302     for (int t = 0; t < kMaxTexCoords; ++t) {
303         GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
304     }
305     GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
306 
307     fHWProgramID = 0;
308 }
309 
flushViewMatrix()310 void GrGpuGLShaders::flushViewMatrix() {
311     GrAssert(NULL != fCurrDrawState.fRenderTarget);
312     GrMatrix m;
313     m.setAll(
314         GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
315         0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
316         0, 0, GrMatrix::I()[8]);
317     m.setConcat(m, fCurrDrawState.fViewMatrix);
318 
319     // ES doesn't allow you to pass true to the transpose param,
320     // so do our own transpose
321     GrGLfloat mt[]  = {
322         GrScalarToFloat(m[GrMatrix::kMScaleX]),
323         GrScalarToFloat(m[GrMatrix::kMSkewY]),
324         GrScalarToFloat(m[GrMatrix::kMPersp0]),
325         GrScalarToFloat(m[GrMatrix::kMSkewX]),
326         GrScalarToFloat(m[GrMatrix::kMScaleY]),
327         GrScalarToFloat(m[GrMatrix::kMPersp1]),
328         GrScalarToFloat(m[GrMatrix::kMTransX]),
329         GrScalarToFloat(m[GrMatrix::kMTransY]),
330         GrScalarToFloat(m[GrMatrix::kMPersp2])
331     };
332 
333     if (GrGLProgram::kSetAsAttribute ==
334         fProgramData->fUniLocations.fViewMatrixUni) {
335         int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
336         GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
337         GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
338         GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
339     } else {
340         GrAssert(GrGLProgram::kUnusedUniform !=
341                  fProgramData->fUniLocations.fViewMatrixUni);
342         GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
343                                1, false, mt));
344     }
345 }
346 
flushTextureDomain(int s)347 void GrGpuGLShaders::flushTextureDomain(int s) {
348     const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
349     if (GrGLProgram::kUnusedUniform != uni) {
350         const GrRect &texDom =
351             fCurrDrawState.fSamplerStates[s].getTextureDomain();
352 
353         if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
354             fProgramData->fTextureDomain[s] != texDom) {
355 
356             fProgramData->fTextureDomain[s] = texDom;
357 
358             float values[4] = {
359                 GrScalarToFloat(texDom.left()),
360                 GrScalarToFloat(texDom.top()),
361                 GrScalarToFloat(texDom.right()),
362                 GrScalarToFloat(texDom.bottom())
363             };
364 
365             GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
366             GrGLTexture::Orientation orientation = texture->orientation();
367 
368             // vertical flip if necessary
369             if (GrGLTexture::kBottomUp_Orientation == orientation) {
370                 values[1] = 1.0f - values[1];
371                 values[3] = 1.0f - values[3];
372                 // The top and bottom were just flipped, so correct the ordering
373                 // of elements so that values = (l, t, r, b).
374                 SkTSwap(values[1], values[3]);
375             }
376 
377             values[0] *= SkScalarToFloat(texture->contentScaleX());
378             values[2] *= SkScalarToFloat(texture->contentScaleX());
379             values[1] *= SkScalarToFloat(texture->contentScaleY());
380             values[3] *= SkScalarToFloat(texture->contentScaleY());
381 
382             GR_GL(Uniform4fv(uni, 1, values));
383         }
384     }
385 }
386 
flushTextureMatrix(int s)387 void GrGpuGLShaders::flushTextureMatrix(int s) {
388     const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
389     GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
390     if (NULL != texture) {
391         if (GrGLProgram::kUnusedUniform != uni &&
392             (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
393             getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
394 
395             GrAssert(NULL != fCurrDrawState.fTextures[s]);
396 
397             GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
398 
399             GrMatrix m = getSamplerMatrix(s);
400             GrSamplerState::SampleMode mode =
401                 fCurrDrawState.fSamplerStates[s].getSampleMode();
402             AdjustTextureMatrix(texture, mode, &m);
403 
404             // ES doesn't allow you to pass true to the transpose param,
405             // so do our own transpose
406             GrGLfloat mt[]  = {
407                 GrScalarToFloat(m[GrMatrix::kMScaleX]),
408                 GrScalarToFloat(m[GrMatrix::kMSkewY]),
409                 GrScalarToFloat(m[GrMatrix::kMPersp0]),
410                 GrScalarToFloat(m[GrMatrix::kMSkewX]),
411                 GrScalarToFloat(m[GrMatrix::kMScaleY]),
412                 GrScalarToFloat(m[GrMatrix::kMPersp1]),
413                 GrScalarToFloat(m[GrMatrix::kMTransX]),
414                 GrScalarToFloat(m[GrMatrix::kMTransY]),
415                 GrScalarToFloat(m[GrMatrix::kMPersp2])
416             };
417 
418             if (GrGLProgram::kSetAsAttribute ==
419                 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
420                 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
421                 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
422                 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
423                 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
424             } else {
425                 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
426             }
427             recordHWSamplerMatrix(s, getSamplerMatrix(s));
428         }
429     }
430 }
431 
flushRadial2(int s)432 void GrGpuGLShaders::flushRadial2(int s) {
433 
434     const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
435     const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
436     if (GrGLProgram::kUnusedUniform != uni &&
437         (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
438          fProgramData->fRadial2Radius0[s]  != sampler.getRadial2Radius0()  ||
439          fProgramData->fRadial2PosRoot[s]  != sampler.isRadial2PosRoot())) {
440 
441         GrScalar centerX1 = sampler.getRadial2CenterX1();
442         GrScalar radius0 = sampler.getRadial2Radius0();
443 
444         GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
445 
446         float values[6] = {
447             GrScalarToFloat(a),
448             1 / (2.f * values[0]),
449             GrScalarToFloat(centerX1),
450             GrScalarToFloat(radius0),
451             GrScalarToFloat(GrMul(radius0, radius0)),
452             sampler.isRadial2PosRoot() ? 1.f : -1.f
453         };
454         GR_GL(Uniform1fv(uni, 6, values));
455         fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
456         fProgramData->fRadial2Radius0[s]  = sampler.getRadial2Radius0();
457         fProgramData->fRadial2PosRoot[s]  = sampler.isRadial2PosRoot();
458     }
459 }
460 
flushTexelSize(int s)461 void GrGpuGLShaders::flushTexelSize(int s) {
462     const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
463     if (GrGLProgram::kUnusedUniform != uni) {
464         GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
465         if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
466             texture->allocHeight() != fProgramData->fTextureWidth[s]) {
467 
468             float texelSize[] = {1.f / texture->allocWidth(),
469                                  1.f / texture->allocHeight()};
470             GR_GL(Uniform2fv(uni, 1, texelSize));
471         }
472     }
473 }
474 
flushEdgeAAData()475 void GrGpuGLShaders::flushEdgeAAData() {
476     const int& uni = fProgramData->fUniLocations.fEdgesUni;
477     if (GrGLProgram::kUnusedUniform != uni) {
478         int count = fCurrDrawState.fEdgeAANumEdges;
479         Edge edges[kMaxEdges];
480         // Flip the edges in Y
481         float height = fCurrDrawState.fRenderTarget->height();
482         for (int i = 0; i < count; ++i) {
483             edges[i] = fCurrDrawState.fEdgeAAEdges[i];
484             float b = edges[i].fY;
485             edges[i].fY = -b;
486             edges[i].fZ += b * height;
487         }
488         GR_GL(Uniform3fv(uni, count, &edges[0].fX));
489     }
490 }
491 
492 static const float ONE_OVER_255 = 1.f / 255.f;
493 
494 #define GR_COLOR_TO_VEC4(color) {\
495     GrColorUnpackR(color) * ONE_OVER_255,\
496     GrColorUnpackG(color) * ONE_OVER_255,\
497     GrColorUnpackB(color) * ONE_OVER_255,\
498     GrColorUnpackA(color) * ONE_OVER_255 \
499 }
500 
flushColor()501 void GrGpuGLShaders::flushColor() {
502     const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
503     if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
504         // color will be specified per-vertex as an attribute
505         // invalidate the const vertex attrib color
506         fHWDrawState.fColor = GrColor_ILLEGAL;
507     } else {
508         switch (desc.fColorType) {
509             case GrGLProgram::ProgramDesc::kAttribute_ColorType:
510                 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
511                     // OpenGL ES only supports the float varities of glVertexAttrib
512                     float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
513                     GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
514                     fHWDrawState.fColor = fCurrDrawState.fColor;
515                 }
516                 break;
517             case GrGLProgram::ProgramDesc::kUniform_ColorType:
518                 if (fProgramData->fColor != fCurrDrawState.fColor) {
519                     // OpenGL ES only supports the float varities of glVertexAttrib
520                     float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
521                     GrAssert(GrGLProgram::kUnusedUniform !=
522                              fProgramData->fUniLocations.fColorUni);
523                     GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
524                     fProgramData->fColor = fCurrDrawState.fColor;
525                 }
526                 break;
527             case GrGLProgram::ProgramDesc::kNone_ColorType:
528                 GrAssert(0xffffffff == fCurrDrawState.fColor);
529                 break;
530             default:
531                 GrCrash("Unknown color type.");
532         }
533     }
534     if (fProgramData->fUniLocations.fColorFilterUni
535                 != GrGLProgram::kUnusedUniform
536             && fProgramData->fColorFilterColor
537                 != fCurrDrawState.fColorFilterColor) {
538         float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
539         GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
540         fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
541     }
542 }
543 
544 
flushGraphicsState(GrPrimitiveType type)545 bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
546     if (!flushGLStateCommon(type)) {
547         return false;
548     }
549 
550     if (fDirtyFlags.fRenderTargetChanged) {
551         // our coords are in pixel space and the GL matrices map to NDC
552         // so if the viewport changed, our matrix is now wrong.
553         fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
554         // we assume all shader matrices may be wrong after viewport changes
555         fProgramCache->invalidateViewMatrices();
556     }
557 
558     buildProgram(type);
559     fProgramData = fProgramCache->getProgramData(fCurrentProgram);
560     if (NULL == fProgramData) {
561         GrAssert(!"Failed to create program!");
562         return false;
563     }
564 
565     if (fHWProgramID != fProgramData->fProgramID) {
566         GR_GL(UseProgram(fProgramData->fProgramID));
567         fHWProgramID = fProgramData->fProgramID;
568     }
569     GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
570     GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
571 
572     fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
573     this->flushBlend(type, srcCoeff, dstCoeff);
574 
575     this->flushColor();
576 
577     GrMatrix* currViewMatrix;
578     if (GrGLProgram::kSetAsAttribute ==
579         fProgramData->fUniLocations.fViewMatrixUni) {
580         currViewMatrix = &fHWDrawState.fViewMatrix;
581     } else {
582         currViewMatrix = &fProgramData->fViewMatrix;
583     }
584 
585     if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
586         flushViewMatrix();
587         *currViewMatrix = fCurrDrawState.fViewMatrix;
588     }
589 
590     for (int s = 0; s < kNumStages; ++s) {
591         this->flushTextureMatrix(s);
592 
593         this->flushRadial2(s);
594 
595         this->flushTexelSize(s);
596 
597         this->flushTextureDomain(s);
598     }
599     this->flushEdgeAAData();
600     resetDirtyFlags();
601     return true;
602 }
603 
postDraw()604 void GrGpuGLShaders::postDraw() {
605 }
606 
setupGeometry(int * startVertex,int * startIndex,int vertexCount,int indexCount)607 void GrGpuGLShaders::setupGeometry(int* startVertex,
608                                     int* startIndex,
609                                     int vertexCount,
610                                     int indexCount) {
611 
612     int newColorOffset;
613     int newTexCoordOffsets[kMaxTexCoords];
614 
615     GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
616                                                   newTexCoordOffsets,
617                                                   &newColorOffset);
618     int oldColorOffset;
619     int oldTexCoordOffsets[kMaxTexCoords];
620     GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
621                                                   oldTexCoordOffsets,
622                                                   &oldColorOffset);
623     bool indexed = NULL != startIndex;
624 
625     int extraVertexOffset;
626     int extraIndexOffset;
627     setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
628 
629     GrGLenum scalarType;
630     bool texCoordNorm;
631     if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
632         scalarType = GrGLTextType;
633         texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
634     } else {
635         scalarType = GrGLType;
636         texCoordNorm = false;
637     }
638 
639     size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
640     *startVertex = 0;
641     if (indexed) {
642         *startIndex += extraIndexOffset;
643     }
644 
645     // all the Pointers must be set if any of these are true
646     bool allOffsetsChange =  fHWGeometryState.fArrayPtrsDirty ||
647                              vertexOffset != fHWGeometryState.fVertexOffset ||
648                              newStride != oldStride;
649 
650     // position and tex coord offsets change if above conditions are true
651     // or the type/normalization changed based on text vs nontext type coords.
652     bool posAndTexChange = allOffsetsChange ||
653                            (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
654                                 (kTextFormat_VertexLayoutBit &
655                                   (fHWGeometryState.fVertexLayout ^
656                                    fGeometrySrc.fVertexLayout)));
657 
658     if (posAndTexChange) {
659         int idx = GrGLProgram::PositionAttributeIdx();
660         GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
661                                   (GrGLvoid*)vertexOffset));
662         fHWGeometryState.fVertexOffset = vertexOffset;
663     }
664 
665     for (int t = 0; t < kMaxTexCoords; ++t) {
666         if (newTexCoordOffsets[t] > 0) {
667             GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
668             int idx = GrGLProgram::TexCoordAttributeIdx(t);
669             if (oldTexCoordOffsets[t] <= 0) {
670                 GR_GL(EnableVertexAttribArray(idx));
671                 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
672                                           newStride, texCoordOffset));
673             } else if (posAndTexChange ||
674                        newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
675                 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
676                                           newStride, texCoordOffset));
677             }
678         } else if (oldTexCoordOffsets[t] > 0) {
679             GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
680         }
681     }
682 
683     if (newColorOffset > 0) {
684         GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
685         int idx = GrGLProgram::ColorAttributeIdx();
686         if (oldColorOffset <= 0) {
687             GR_GL(EnableVertexAttribArray(idx));
688             GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
689                                       true, newStride, colorOffset));
690         } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
691             GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
692                                       true, newStride, colorOffset));
693         }
694     } else if (oldColorOffset > 0) {
695         GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
696     }
697 
698     fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
699     fHWGeometryState.fArrayPtrsDirty = false;
700 }
701 
buildProgram(GrPrimitiveType type)702 void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
703     GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
704 
705     // Must initialize all fields or cache will have false negatives!
706     desc.fVertexLayout = fGeometrySrc.fVertexLayout;
707 
708     desc.fEmitsPointSize = kPoints_PrimitiveType == type;
709 
710     bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
711     // fColorType records how colors are specified for the program. Strip
712     // the bit from the layout to avoid false negatives when searching for an
713     // existing program in the cache.
714     desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
715 
716     desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
717 
718 #if GR_AGGRESSIVE_SHADER_OPTS
719     if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
720         desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
721     } else
722 #endif
723 #if GR_GL_NO_CONSTANT_ATTRIBUTES
724     if (!requiresAttributeColors) {
725         desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
726     } else
727 #endif
728     {
729         if (requiresAttributeColors) {} // suppress unused var warning
730         desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
731     }
732 
733     desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
734 
735     int lastEnabledStage = -1;
736 
737     for (int s = 0; s < kNumStages; ++s) {
738         GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
739 
740         stage.fOptFlags = 0;
741         stage.setEnabled(this->isStageEnabled(s));
742 
743         if (stage.isEnabled()) {
744             lastEnabledStage = s;
745             GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
746             GrAssert(NULL != texture);
747             // we matrix to invert when orientation is TopDown, so make sure
748             // we aren't in that case before flagging as identity.
749             if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
750                 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
751             } else if (!getSamplerMatrix(s).hasPerspective()) {
752                 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
753             }
754             switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
755                 case GrSamplerState::kNormal_SampleMode:
756                     stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
757                     break;
758                 case GrSamplerState::kRadial_SampleMode:
759                     stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
760                     break;
761                 case GrSamplerState::kRadial2_SampleMode:
762                     stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
763                     break;
764                 case GrSamplerState::kSweep_SampleMode:
765                     stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
766                     break;
767                 default:
768                     GrCrash("Unexpected sample mode!");
769                     break;
770             }
771 
772             switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
773                 // these both can use a regular texture2D()
774                 case GrSamplerState::kNearest_Filter:
775                 case GrSamplerState::kBilinear_Filter:
776                     stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
777                     break;
778                 // performs 4 texture2D()s
779                 case GrSamplerState::k4x4Downsample_Filter:
780                     stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
781                     break;
782                 default:
783                     GrCrash("Unexpected filter!");
784                     break;
785             }
786 
787             if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
788                 GrAssert(GrSamplerState::kClamp_WrapMode ==
789                     fCurrDrawState.fSamplerStates[s].getWrapX() &&
790                     GrSamplerState::kClamp_WrapMode ==
791                     fCurrDrawState.fSamplerStates[s].getWrapY());
792                 stage.fOptFlags |=
793                     GrGLProgram::ProgramDesc::StageDesc::
794                     kCustomTextureDomain_OptFlagBit;
795             }
796 
797             if (GrPixelConfigIsAlphaOnly(texture->config())) {
798                 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
799             } else {
800                 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
801             }
802         } else {
803             stage.fOptFlags     = 0;
804             stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
805             stage.fModulation   = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
806         }
807     }
808 
809     desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
810     // use canonical value when coverage/color distinction won't affect
811     // generated code to prevent duplicate programs.
812     desc.fFirstCoverageStage = kNumStages;
813     if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
814         // color filter is applied between color/coverage computation
815         if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
816             desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
817         }
818 
819         // We could consider cases where the final color is solid (0xff alpha)
820         // and the dst coeff can correctly be set to a non-dualsrc gl value.
821         // (e.g. solid draw, and dst coeff is kZero. It's correct to make
822         // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
823         // kOne).
824         if (fDualSourceBlendingSupport) {
825             if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
826                 // write the coverage value to second color
827                 desc.fDualSrcOutput =
828                                 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
829                 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
830             } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
831                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
832                 // cover
833                 desc.fDualSrcOutput =
834                             GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
835                 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
836             } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
837                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
838                 // cover
839                 desc.fDualSrcOutput =
840                         GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
841                 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
842             }
843         }
844     }
845 }
846