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