blob: c977ea4c7e9c79e11927db0d9e7acfad10effc30 [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) {
377 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
378 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
379 if (-1 != uni) {
380 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
381 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
382 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
383
384 float texelSize[] = {1.f / texture->allocWidth(),
385 1.f / texture->allocHeight()};
386 GR_GL(Uniform2fv(uni, 1, texelSize));
387 }
388 }
junov@google.comf93e7172011-03-31 21:26:24 +0000389}
390
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000391void GrGpuGLShaders::flushColor() {
392 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
393 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
394 // color will be specified per-vertex as an attribute
395 // invalidate the const vertex attrib color
396 fHWDrawState.fColor = GrColor_ILLEGAL;
397 } else {
398 switch (desc.fColorType) {
399 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
400 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
401 // OpenGL ES only supports the float varities of glVertexAttrib
402 float c[] = {
403 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
404 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
405 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
406 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
407 };
408 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
409 fHWDrawState.fColor = fCurrDrawState.fColor;
410 }
411 break;
412 case GrGLProgram::ProgramDesc::kUniform_ColorType:
413 if (fProgramData->fColor != fCurrDrawState.fColor) {
414 // OpenGL ES only supports the float varities of glVertexAttrib
415 float c[] = {
416 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
417 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
418 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
419 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
420 };
421 GrAssert(-1 != fProgramData->fUniLocations.fColorUni);
422 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
423 fProgramData->fColor = fCurrDrawState.fColor;
424 }
425 break;
426 case GrGLProgram::ProgramDesc::kNone_ColorType:
427 GrAssert(0xffffffff == fCurrDrawState.fColor);
428 break;
429 default:
430 GrCrash("Unknown color type.");
431 }
432 }
433}
434
435
junov@google.comf93e7172011-03-31 21:26:24 +0000436bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
437 if (!flushGLStateCommon(type)) {
438 return false;
439 }
440
441 if (fDirtyFlags.fRenderTargetChanged) {
442 // our coords are in pixel space and the GL matrices map to NDC
443 // so if the viewport changed, our matrix is now wrong.
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000444#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000445 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
446#else
447 // we assume all shader matrices may be wrong after viewport changes
448 fProgramCache->invalidateViewMatrices();
449#endif
450 }
451
junov@google.comf93e7172011-03-31 21:26:24 +0000452 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000453 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
junov@google.comf93e7172011-03-31 21:26:24 +0000454
455 if (fHWProgramID != fProgramData->fProgramID) {
456 GR_GL(UseProgram(fProgramData->fProgramID));
457 fHWProgramID = fProgramData->fProgramID;
458 }
459
460 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
461 return false;
462 }
463
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000464 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000465
466#if GR_GL_ATTRIBUTE_MATRICES
junov@google.comf93e7172011-03-31 21:26:24 +0000467 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
468#else
469 GrMatrix& currViewMatrix = fProgramData->fViewMatrix;
470#endif
471
472 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
473 flushViewMatrix();
474 currViewMatrix = fCurrDrawState.fViewMatrix;
475 }
476
477 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000478 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000479
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000480 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000481
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000482 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000483 }
484 resetDirtyFlags();
485 return true;
486}
487
488void GrGpuGLShaders::postDraw() {
489 fCurrentProgram.doGLPost();
490}
491
492void GrGpuGLShaders::setupGeometry(int* startVertex,
493 int* startIndex,
494 int vertexCount,
495 int indexCount) {
496
497 int newColorOffset;
498 int newTexCoordOffsets[kMaxTexCoords];
499
500 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
501 newTexCoordOffsets,
502 &newColorOffset);
503 int oldColorOffset;
504 int oldTexCoordOffsets[kMaxTexCoords];
505 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
506 oldTexCoordOffsets,
507 &oldColorOffset);
508 bool indexed = NULL != startIndex;
509
510 int extraVertexOffset;
511 int extraIndexOffset;
512 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
513
514 GrGLenum scalarType;
515 bool texCoordNorm;
516 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
517 scalarType = GrGLTextType;
518 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
519 } else {
520 scalarType = GrGLType;
521 texCoordNorm = false;
522 }
523
524 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
525 *startVertex = 0;
526 if (indexed) {
527 *startIndex += extraIndexOffset;
528 }
529
530 // all the Pointers must be set if any of these are true
531 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
532 vertexOffset != fHWGeometryState.fVertexOffset ||
533 newStride != oldStride;
534
535 // position and tex coord offsets change if above conditions are true
536 // or the type/normalization changed based on text vs nontext type coords.
537 bool posAndTexChange = allOffsetsChange ||
538 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
539 (kTextFormat_VertexLayoutBit &
540 (fHWGeometryState.fVertexLayout ^
541 fGeometrySrc.fVertexLayout)));
542
543 if (posAndTexChange) {
544 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
545 false, newStride, (GrGLvoid*)vertexOffset));
546 fHWGeometryState.fVertexOffset = vertexOffset;
547 }
548
549 for (int t = 0; t < kMaxTexCoords; ++t) {
550 if (newTexCoordOffsets[t] > 0) {
551 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
552 if (oldTexCoordOffsets[t] <= 0) {
553 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
554 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
555 texCoordNorm, newStride, texCoordOffset));
556 } else if (posAndTexChange ||
557 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
558 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
559 texCoordNorm, newStride, texCoordOffset));
560 }
561 } else if (oldTexCoordOffsets[t] > 0) {
562 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
563 }
564 }
565
566 if (newColorOffset > 0) {
567 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
568 if (oldColorOffset <= 0) {
569 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
570 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
571 GR_GL_UNSIGNED_BYTE,
572 true, newStride, colorOffset));
573 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
574 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
575 GR_GL_UNSIGNED_BYTE,
576 true, newStride, colorOffset));
577 }
578 } else if (oldColorOffset > 0) {
579 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
580 }
581
582 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
583 fHWGeometryState.fArrayPtrsDirty = false;
584}
585
586void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000587 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000588
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000589 // Must initialize all fields or cache will have false negatives!
590 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
591
592 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
593
594 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
595 // fColorType records how colors are specified for the program. Strip
596 // the bit from the layout to avoid false negatives when searching for an
597 // existing program in the cache.
598 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
599
junov@google.comf93e7172011-03-31 21:26:24 +0000600#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000601 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000602 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000603 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000604#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000605#if GR_GL_NO_CONSTANT_ATTRIBUTES
606 if (!requiresAttributeColors) {
607 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
608 } else
609#endif
610 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000611 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000612 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
613 }
junov@google.comf93e7172011-03-31 21:26:24 +0000614
615 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000616 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000617
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000618 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000619
620 if (stage.fEnabled) {
621 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
622 GrAssert(NULL != texture);
623 // we matrix to invert when orientation is TopDown, so make sure
624 // we aren't in that case before flagging as identity.
625 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
626 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
627 } else if (!getSamplerMatrix(s).hasPerspective()) {
628 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
629 } else {
630 stage.fOptFlags = 0;
631 }
632 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000633 case GrSamplerState::kNormal_SampleMode:
634 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
635 break;
636 case GrSamplerState::kRadial_SampleMode:
637 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
638 break;
639 case GrSamplerState::kRadial2_SampleMode:
640 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
641 break;
642 case GrSamplerState::kSweep_SampleMode:
643 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
644 break;
645 default:
646 GrCrash("Unexpected sample mode!");
647 break;
648 }
649
650 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
651 // these both can use a regular texture2D()
652 case GrSamplerState::kNearest_Filter:
653 case GrSamplerState::kBilinear_Filter:
654 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
655 break;
656 // performs 4 texture2D()s
657 case GrSamplerState::k4x4Downsample_Filter:
658 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
659 break;
660 default:
661 GrCrash("Unexpected filter!");
662 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000663 }
664
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000665 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000666 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
667 } else {
668 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
669 }
670
671 if (fCurrDrawState.fEffects[s]) {
672 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
673 } else {
674 delete fCurrentProgram.fStageEffects[s];
675 fCurrentProgram.fStageEffects[s] = NULL;
676 }
677 } else {
678 stage.fOptFlags = 0;
679 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
680 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
681 fCurrentProgram.fStageEffects[s] = NULL;
682 }
683 }
684}
685
686
687