• 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