blob: b9142219462ff0abb38de49318e3d19e044f3e4c [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
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 "GrGLEffect.h"
19#include "GrGLProgram.h"
20#include "GrGpuGLShaders.h"
21#include "GrGpuVertex.h"
22#include "GrMemory.h"
23#include "GrNoncopyable.h"
24#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000025#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000026
junov@google.comf93e7172011-03-31 21:26:24 +000027#define SKIP_CACHE_CHECK true
28#define GR_UINT32_MAX static_cast<uint32_t>(-1)
29
bsalomon@google.com4be283f2011-04-19 21:15:09 +000030#if GR_GL_ATTRIBUTE_MATRICES
31 #define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
32 #define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
33 #define BOGUS_MATRIX_UNI_LOCATION 1000
junov@google.comf93e7172011-03-31 21:26:24 +000034#endif
35
36#include "GrTHashCache.h"
37
38class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
39private:
40 class Entry;
41
42#if GR_DEBUG
43 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
44#else
45 typedef GrBinHashKey<Entry, 32> ProgramHashKey;
46#endif
47
48 class Entry : public ::GrNoncopyable {
49 public:
50 Entry() {}
51 private:
52 void copyAndTakeOwnership(Entry& entry) {
53 fProgramData.copyAndTakeOwnership(entry.fProgramData);
54 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000055 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000056 }
57
58 public:
59 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
60
61 public:
62 GrGLProgram::CachedData fProgramData;
63 ProgramHashKey fKey;
64 unsigned int fLRUStamp;
65 };
66
67 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
68
69 enum {
70 kMaxEntries = 32
71 };
72 Entry fEntries[kMaxEntries];
73 int fCount;
74 unsigned int fCurrLRUStamp;
75
76public:
77 ProgramCache()
78 : fCount(0)
79 , fCurrLRUStamp(0) {
80 }
81
82 ~ProgramCache() {
83 for (int i = 0; i < fCount; ++i) {
84 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
85 }
86 }
87
88 void abandon() {
89 fCount = 0;
90 }
91
92 void invalidateViewMatrices() {
93 for (int i = 0; i < fCount; ++i) {
94 // set to illegal matrix
95 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
96 }
97 }
98
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000099 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
junov@google.comf93e7172011-03-31 21:26:24 +0000100 ProgramHashKey key;
101 while (key.doPass()) {
102 desc.buildKey(key);
103 }
104 Entry* entry = fHashCache.find(key);
105 if (NULL == entry) {
106 if (fCount < kMaxEntries) {
107 entry = fEntries + fCount;
108 ++fCount;
109 } else {
110 GrAssert(kMaxEntries == fCount);
111 entry = fEntries;
112 for (int i = 1; i < kMaxEntries; ++i) {
113 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
114 entry = fEntries + i;
115 }
116 }
117 fHashCache.remove(entry->fKey, entry);
118 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
119 }
120 entry->fKey.copyAndTakeOwnership(key);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000121 desc.genProgram(&entry->fProgramData);
junov@google.comf93e7172011-03-31 21:26:24 +0000122 fHashCache.insert(entry->fKey, entry);
123 }
124
125 entry->fLRUStamp = fCurrLRUStamp;
126 if (GR_UINT32_MAX == fCurrLRUStamp) {
127 // wrap around! just trash our LRU, one time hit.
128 for (int i = 0; i < fCount; ++i) {
129 fEntries[i].fLRUStamp = 0;
130 }
131 }
132 ++fCurrLRUStamp;
133 return &entry->fProgramData;
134 }
135};
136
137void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
138 GR_GL(DeleteShader(programData->fVShaderID));
139 GR_GL(DeleteShader(programData->fFShaderID));
140 GR_GL(DeleteProgram(programData->fProgramID));
141 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
142}
143
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000144void GrGpuGLShaders::ProgramUnitTest() {
145
146 static const int STAGE_OPTS[] = {
147 0,
148 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
149 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
150 };
151 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
152 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
153 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
154 };
155 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
156 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
157 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
158 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
159 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
160 };
161 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
162 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
163 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
164 };
165 GrGLProgram program;
166 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
167
168 static const int NUM_TESTS = 512;
169
170 // GrRandoms nextU() values have patterns in the low bits
171 // So using nextU() % array_count might never take some values.
172 GrRandom random;
173 for (int t = 0; t < NUM_TESTS; ++t) {
174
175 pdesc.fVertexLayout = 0;
176 pdesc.fEmitsPointSize = random.nextF() > .5f;
177 float colorType = random.nextF();
178 if (colorType < 1.f / 3.f) {
179 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
180 } else if (colorType < 2.f / 3.f) {
181 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
182 } else {
183 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
184 }
185 for (int s = 0; s < kNumStages; ++s) {
186 // enable the stage?
187 if (random.nextF() > .5f) {
188 // use separate tex coords?
189 if (random.nextF() > .5f) {
190 int t = (int)(random.nextF() * kMaxTexCoords);
191 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
192 } else {
193 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
194 }
195 }
196 // use text-formatted verts?
197 if (random.nextF() > .5f) {
198 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
199 }
200 }
201
202 for (int s = 0; s < kNumStages; ++s) {
203 int x;
204 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
205 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
206 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
207 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
208 pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
209 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
210 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
211 x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
212 pdesc.fStages[s].fFetchMode = FETCH_MODES[x];
213 }
214 GrGLProgram::CachedData cachedData;
215 program.genProgram(&cachedData);
216 DeleteProgram(&cachedData);
217 bool again = false;
218 if (again) {
219 program.genProgram(&cachedData);
220 DeleteProgram(&cachedData);
221 }
222 }
223}
224
junov@google.comf93e7172011-03-31 21:26:24 +0000225
226GrGpuGLShaders::GrGpuGLShaders() {
227
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000228 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000229 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000230
231 fProgramData = NULL;
232 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000233
234#if 0
235 ProgramUnitTest();
236#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000237}
238
239GrGpuGLShaders::~GrGpuGLShaders() {
240 delete fProgramCache;
241}
242
243const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000244#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000245 return fHWDrawState.fSamplerStates[stage].getMatrix();
246#else
247 GrAssert(fProgramData);
248 return fProgramData->fTextureMatrices[stage];
249#endif
250}
251
252void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000253#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000254 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
255#else
256 GrAssert(fProgramData);
257 fProgramData->fTextureMatrices[stage] = matrix;
258#endif
259}
260
261void GrGpuGLShaders::resetContext() {
262 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000263
junov@google.comf93e7172011-03-31 21:26:24 +0000264 fHWGeometryState.fVertexLayout = 0;
265 fHWGeometryState.fVertexOffset = ~0;
266 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
267 for (int t = 0; t < kMaxTexCoords; ++t) {
268 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
269 }
270 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
271
272 fHWProgramID = 0;
273}
274
275void GrGpuGLShaders::flushViewMatrix() {
276 GrAssert(NULL != fCurrDrawState.fRenderTarget);
277 GrMatrix m (
278 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
279 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
280 0, 0, GrMatrix::I()[8]);
281 m.setConcat(m, fCurrDrawState.fViewMatrix);
282
283 // ES doesn't allow you to pass true to the transpose param,
284 // so do our own transpose
285 GrScalar mt[] = {
286 m[GrMatrix::kScaleX],
287 m[GrMatrix::kSkewY],
288 m[GrMatrix::kPersp0],
289 m[GrMatrix::kSkewX],
290 m[GrMatrix::kScaleY],
291 m[GrMatrix::kPersp1],
292 m[GrMatrix::kTransX],
293 m[GrMatrix::kTransY],
294 m[GrMatrix::kPersp2]
295 };
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000296#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000297 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
298 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
299 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
300#else
301 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,1,false,mt));
302#endif
303}
304
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000305void GrGpuGLShaders::flushTextureMatrix(int s) {
306 const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
307 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
308 if (NULL != texture) {
309 if (-1 != uni &&
310 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
311 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000312
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000313 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000314
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000315 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000316
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000317 GrMatrix m = getSamplerMatrix(s);
318 GrSamplerState::SampleMode mode =
319 fCurrDrawState.fSamplerStates[s].getSampleMode();
320 AdjustTextureMatrix(texture, mode, &m);
321
322 // ES doesn't allow you to pass true to the transpose param,
323 // so do our own transpose
324 GrScalar mt[] = {
325 m[GrMatrix::kScaleX],
326 m[GrMatrix::kSkewY],
327 m[GrMatrix::kPersp0],
328 m[GrMatrix::kSkewX],
329 m[GrMatrix::kScaleY],
330 m[GrMatrix::kPersp1],
331 m[GrMatrix::kTransX],
332 m[GrMatrix::kTransY],
333 m[GrMatrix::kPersp2]
334 };
335 #if GR_GL_ATTRIBUTE_MATRICES
336 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
337 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
338 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
339 #else
340 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
341 #endif
342 recordHWSamplerMatrix(s, getSamplerMatrix(s));
343 }
344 }
junov@google.comf93e7172011-03-31 21:26:24 +0000345}
346
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000347void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000348
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000349 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
350 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
351 if (-1 != uni &&
352 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
353 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
354 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000355
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356 GrScalar centerX1 = sampler.getRadial2CenterX1();
357 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000358
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000360
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000361 float values[6] = {
362 GrScalarToFloat(a),
363 1 / (2.f * values[0]),
364 GrScalarToFloat(centerX1),
365 GrScalarToFloat(radius0),
366 GrScalarToFloat(GrMul(radius0, radius0)),
367 sampler.isRadial2PosRoot() ? 1.f : -1.f
368 };
369 GR_GL(Uniform1fv(uni, 6, values));
370 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
371 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
372 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
373 }
374}
375
376void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000377 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
378 if (-1 != uni) {
379 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
380 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
381 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
382
383 float texelSize[] = {1.f / texture->allocWidth(),
384 1.f / texture->allocHeight()};
385 GR_GL(Uniform2fv(uni, 1, texelSize));
386 }
387 }
junov@google.comf93e7172011-03-31 21:26:24 +0000388}
389
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000390void GrGpuGLShaders::flushColor() {
391 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
392 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
393 // color will be specified per-vertex as an attribute
394 // invalidate the const vertex attrib color
395 fHWDrawState.fColor = GrColor_ILLEGAL;
396 } else {
397 switch (desc.fColorType) {
398 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
399 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
400 // OpenGL ES only supports the float varities of glVertexAttrib
401 float c[] = {
402 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
403 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
404 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
405 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
406 };
407 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
408 fHWDrawState.fColor = fCurrDrawState.fColor;
409 }
410 break;
411 case GrGLProgram::ProgramDesc::kUniform_ColorType:
412 if (fProgramData->fColor != fCurrDrawState.fColor) {
413 // OpenGL ES only supports the float varities of glVertexAttrib
414 float c[] = {
415 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
416 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
417 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
418 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
419 };
420 GrAssert(-1 != fProgramData->fUniLocations.fColorUni);
421 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
422 fProgramData->fColor = fCurrDrawState.fColor;
423 }
424 break;
425 case GrGLProgram::ProgramDesc::kNone_ColorType:
426 GrAssert(0xffffffff == fCurrDrawState.fColor);
427 break;
428 default:
429 GrCrash("Unknown color type.");
430 }
431 }
432}
433
434
junov@google.comf93e7172011-03-31 21:26:24 +0000435bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
436 if (!flushGLStateCommon(type)) {
437 return false;
438 }
439
440 if (fDirtyFlags.fRenderTargetChanged) {
441 // our coords are in pixel space and the GL matrices map to NDC
442 // so if the viewport changed, our matrix is now wrong.
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000443#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000444 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
445#else
446 // we assume all shader matrices may be wrong after viewport changes
447 fProgramCache->invalidateViewMatrices();
448#endif
449 }
450
junov@google.comf93e7172011-03-31 21:26:24 +0000451 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000452 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
junov@google.comf93e7172011-03-31 21:26:24 +0000453
454 if (fHWProgramID != fProgramData->fProgramID) {
455 GR_GL(UseProgram(fProgramData->fProgramID));
456 fHWProgramID = fProgramData->fProgramID;
457 }
458
459 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
460 return false;
461 }
462
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000463 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000464
465#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000466 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
467#else
468 GrMatrix& currViewMatrix = fProgramData->fViewMatrix;
469#endif
470
471 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
472 flushViewMatrix();
473 currViewMatrix = fCurrDrawState.fViewMatrix;
474 }
475
476 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000477 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000478
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000479 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000480
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000481 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000482 }
483 resetDirtyFlags();
484 return true;
485}
486
487void GrGpuGLShaders::postDraw() {
488 fCurrentProgram.doGLPost();
489}
490
491void GrGpuGLShaders::setupGeometry(int* startVertex,
492 int* startIndex,
493 int vertexCount,
494 int indexCount) {
495
496 int newColorOffset;
497 int newTexCoordOffsets[kMaxTexCoords];
498
499 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
500 newTexCoordOffsets,
501 &newColorOffset);
502 int oldColorOffset;
503 int oldTexCoordOffsets[kMaxTexCoords];
504 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
505 oldTexCoordOffsets,
506 &oldColorOffset);
507 bool indexed = NULL != startIndex;
508
509 int extraVertexOffset;
510 int extraIndexOffset;
511 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
512
513 GrGLenum scalarType;
514 bool texCoordNorm;
515 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
516 scalarType = GrGLTextType;
517 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
518 } else {
519 scalarType = GrGLType;
520 texCoordNorm = false;
521 }
522
523 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
524 *startVertex = 0;
525 if (indexed) {
526 *startIndex += extraIndexOffset;
527 }
528
529 // all the Pointers must be set if any of these are true
530 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
531 vertexOffset != fHWGeometryState.fVertexOffset ||
532 newStride != oldStride;
533
534 // position and tex coord offsets change if above conditions are true
535 // or the type/normalization changed based on text vs nontext type coords.
536 bool posAndTexChange = allOffsetsChange ||
537 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
538 (kTextFormat_VertexLayoutBit &
539 (fHWGeometryState.fVertexLayout ^
540 fGeometrySrc.fVertexLayout)));
541
542 if (posAndTexChange) {
543 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
544 false, newStride, (GrGLvoid*)vertexOffset));
545 fHWGeometryState.fVertexOffset = vertexOffset;
546 }
547
548 for (int t = 0; t < kMaxTexCoords; ++t) {
549 if (newTexCoordOffsets[t] > 0) {
550 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
551 if (oldTexCoordOffsets[t] <= 0) {
552 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
553 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
554 texCoordNorm, newStride, texCoordOffset));
555 } else if (posAndTexChange ||
556 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
557 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
558 texCoordNorm, newStride, texCoordOffset));
559 }
560 } else if (oldTexCoordOffsets[t] > 0) {
561 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
562 }
563 }
564
565 if (newColorOffset > 0) {
566 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
567 if (oldColorOffset <= 0) {
568 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
569 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
570 GR_GL_UNSIGNED_BYTE,
571 true, newStride, colorOffset));
572 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
573 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
574 GR_GL_UNSIGNED_BYTE,
575 true, newStride, colorOffset));
576 }
577 } else if (oldColorOffset > 0) {
578 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
579 }
580
581 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
582 fHWGeometryState.fArrayPtrsDirty = false;
583}
584
585void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000586 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000587
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000588 // Must initialize all fields or cache will have false negatives!
589 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
590
591 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
592
593 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
594 // fColorType records how colors are specified for the program. Strip
595 // the bit from the layout to avoid false negatives when searching for an
596 // existing program in the cache.
597 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
598
junov@google.comf93e7172011-03-31 21:26:24 +0000599#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000600 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000601 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000602 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000603#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000604#if GR_GL_NO_CONSTANT_ATTRIBUTES
605 if (!requiresAttributeColors) {
606 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
607 } else
608#endif
609 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000610 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000611 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
612 }
junov@google.comf93e7172011-03-31 21:26:24 +0000613
614 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000615 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000616
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000617 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000618
619 if (stage.fEnabled) {
620 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
621 GrAssert(NULL != texture);
622 // we matrix to invert when orientation is TopDown, so make sure
623 // we aren't in that case before flagging as identity.
624 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
625 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
626 } else if (!getSamplerMatrix(s).hasPerspective()) {
627 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
628 } else {
629 stage.fOptFlags = 0;
630 }
631 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000632 case GrSamplerState::kNormal_SampleMode:
633 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
634 break;
635 case GrSamplerState::kRadial_SampleMode:
636 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
637 break;
638 case GrSamplerState::kRadial2_SampleMode:
639 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
640 break;
641 case GrSamplerState::kSweep_SampleMode:
642 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
643 break;
644 default:
645 GrCrash("Unexpected sample mode!");
646 break;
647 }
648
649 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
650 // these both can use a regular texture2D()
651 case GrSamplerState::kNearest_Filter:
652 case GrSamplerState::kBilinear_Filter:
653 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
654 break;
655 // performs 4 texture2D()s
656 case GrSamplerState::k4x4Downsample_Filter:
657 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
658 break;
659 default:
660 GrCrash("Unexpected filter!");
661 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000662 }
663
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000664 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000665 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
666 } else {
667 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
668 }
669
670 if (fCurrDrawState.fEffects[s]) {
671 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
672 } else {
673 delete fCurrentProgram.fStageEffects[s];
674 fCurrentProgram.fStageEffects[s] = NULL;
675 }
676 } else {
677 stage.fOptFlags = 0;
678 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
679 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
680 fCurrentProgram.fStageEffects[s] = NULL;
681 }
682 }
683}
684
685
686