blob: c2b89716de117dbbdb65fbb97b51db44bb1a6d7f [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
junov@google.comf93e7172011-03-31 21:26:24 +000030#include "GrTHashCache.h"
31
32class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
33private:
34 class Entry;
35
36#if GR_DEBUG
37 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
38#else
39 typedef GrBinHashKey<Entry, 32> ProgramHashKey;
40#endif
41
42 class Entry : public ::GrNoncopyable {
43 public:
44 Entry() {}
45 private:
46 void copyAndTakeOwnership(Entry& entry) {
47 fProgramData.copyAndTakeOwnership(entry.fProgramData);
48 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000049 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000050 }
51
52 public:
53 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
54
55 public:
56 GrGLProgram::CachedData fProgramData;
57 ProgramHashKey fKey;
58 unsigned int fLRUStamp;
59 };
60
61 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
62
63 enum {
64 kMaxEntries = 32
65 };
66 Entry fEntries[kMaxEntries];
67 int fCount;
68 unsigned int fCurrLRUStamp;
69
70public:
71 ProgramCache()
72 : fCount(0)
73 , fCurrLRUStamp(0) {
74 }
75
76 ~ProgramCache() {
77 for (int i = 0; i < fCount; ++i) {
78 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
79 }
80 }
81
82 void abandon() {
83 fCount = 0;
84 }
85
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
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000093 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
junov@google.comf93e7172011-03-31 21:26:24 +000094 ProgramHashKey key;
95 while (key.doPass()) {
96 desc.buildKey(key);
97 }
98 Entry* entry = fHashCache.find(key);
99 if (NULL == entry) {
100 if (fCount < kMaxEntries) {
101 entry = fEntries + fCount;
102 ++fCount;
103 } else {
104 GrAssert(kMaxEntries == fCount);
105 entry = fEntries;
106 for (int i = 1; i < kMaxEntries; ++i) {
107 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
108 entry = fEntries + i;
109 }
110 }
111 fHashCache.remove(entry->fKey, entry);
112 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
113 }
114 entry->fKey.copyAndTakeOwnership(key);
bsalomon@google.com91961302011-05-09 18:39:58 +0000115 if (!desc.genProgram(&entry->fProgramData)) {
116 return NULL;
117 }
junov@google.comf93e7172011-03-31 21:26:24 +0000118 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
133void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
134 GR_GL(DeleteShader(programData->fVShaderID));
135 GR_GL(DeleteShader(programData->fFShaderID));
136 GR_GL(DeleteProgram(programData->fProgramID));
137 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
138}
139
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000140void GrGpuGLShaders::ProgramUnitTest() {
141
142 static const int STAGE_OPTS[] = {
143 0,
144 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
145 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
146 };
147 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
148 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
149 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
150 };
151 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
152 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
153 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
154 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
155 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
156 };
157 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
158 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
159 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
160 };
161 GrGLProgram program;
162 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
163
164 static const int NUM_TESTS = 512;
165
166 // GrRandoms nextU() values have patterns in the low bits
167 // So using nextU() % array_count might never take some values.
168 GrRandom random;
169 for (int t = 0; t < NUM_TESTS; ++t) {
170
171 pdesc.fVertexLayout = 0;
172 pdesc.fEmitsPointSize = random.nextF() > .5f;
173 float colorType = random.nextF();
174 if (colorType < 1.f / 3.f) {
175 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
176 } else if (colorType < 2.f / 3.f) {
177 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
178 } else {
179 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
180 }
181 for (int s = 0; s < kNumStages; ++s) {
182 // enable the stage?
183 if (random.nextF() > .5f) {
184 // use separate tex coords?
185 if (random.nextF() > .5f) {
186 int t = (int)(random.nextF() * kMaxTexCoords);
187 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
188 } else {
189 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
190 }
191 }
192 // use text-formatted verts?
193 if (random.nextF() > .5f) {
194 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
195 }
196 }
197
198 for (int s = 0; s < kNumStages; ++s) {
199 int x;
200 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
201 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
202 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
203 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
204 pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
205 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
206 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
207 x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
208 pdesc.fStages[s].fFetchMode = FETCH_MODES[x];
209 }
210 GrGLProgram::CachedData cachedData;
211 program.genProgram(&cachedData);
212 DeleteProgram(&cachedData);
213 bool again = false;
214 if (again) {
215 program.genProgram(&cachedData);
216 DeleteProgram(&cachedData);
217 }
218 }
219}
220
junov@google.comf93e7172011-03-31 21:26:24 +0000221
222GrGpuGLShaders::GrGpuGLShaders() {
223
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000224 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000225 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000226
227 fProgramData = NULL;
228 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000229
230#if 0
231 ProgramUnitTest();
232#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000233}
234
235GrGpuGLShaders::~GrGpuGLShaders() {
236 delete fProgramCache;
237}
238
239const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000240 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000241
242 if (GrGLProgram::kSetAsAttribute ==
243 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
244 return fHWDrawState.fSamplerStates[stage].getMatrix();
245 } else {
246 return fProgramData->fTextureMatrices[stage];
247 }
junov@google.comf93e7172011-03-31 21:26:24 +0000248}
249
250void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000251 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000252 if (GrGLProgram::kSetAsAttribute ==
253 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
254 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
255 } else {
256 fProgramData->fTextureMatrices[stage] = matrix;
257 }
junov@google.comf93e7172011-03-31 21:26:24 +0000258}
259
260void GrGpuGLShaders::resetContext() {
261 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000262
junov@google.comf93e7172011-03-31 21:26:24 +0000263 fHWGeometryState.fVertexLayout = 0;
264 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000265 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000266 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000267 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000268 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000269 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000270
271 fHWProgramID = 0;
272}
273
274void GrGpuGLShaders::flushViewMatrix() {
275 GrAssert(NULL != fCurrDrawState.fRenderTarget);
276 GrMatrix m (
277 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
278 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
279 0, 0, GrMatrix::I()[8]);
280 m.setConcat(m, fCurrDrawState.fViewMatrix);
281
282 // ES doesn't allow you to pass true to the transpose param,
283 // so do our own transpose
284 GrScalar mt[] = {
285 m[GrMatrix::kScaleX],
286 m[GrMatrix::kSkewY],
287 m[GrMatrix::kPersp0],
288 m[GrMatrix::kSkewX],
289 m[GrMatrix::kScaleY],
290 m[GrMatrix::kPersp1],
291 m[GrMatrix::kTransX],
292 m[GrMatrix::kTransY],
293 m[GrMatrix::kPersp2]
294 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000295
296 if (GrGLProgram::kSetAsAttribute ==
297 fProgramData->fUniLocations.fViewMatrixUni) {
298 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
299 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
300 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
301 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
302 } else {
303 GrAssert(GrGLProgram::kUnusedUniform !=
304 fProgramData->fUniLocations.fViewMatrixUni);
305 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
306 1, false, mt));
307 }
junov@google.comf93e7172011-03-31 21:26:24 +0000308}
309
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000310void GrGpuGLShaders::flushTextureMatrix(int s) {
311 const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
312 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
313 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000314 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000315 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
316 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000317
bsalomon@google.com91961302011-05-09 18:39:58 +0000318 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000319
bsalomon@google.com91961302011-05-09 18:39:58 +0000320 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000321
bsalomon@google.com91961302011-05-09 18:39:58 +0000322 GrMatrix m = getSamplerMatrix(s);
323 GrSamplerState::SampleMode mode =
324 fCurrDrawState.fSamplerStates[s].getSampleMode();
325 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000326
bsalomon@google.com91961302011-05-09 18:39:58 +0000327 // ES doesn't allow you to pass true to the transpose param,
328 // so do our own transpose
329 GrScalar mt[] = {
330 m[GrMatrix::kScaleX],
331 m[GrMatrix::kSkewY],
332 m[GrMatrix::kPersp0],
333 m[GrMatrix::kSkewX],
334 m[GrMatrix::kScaleY],
335 m[GrMatrix::kPersp1],
336 m[GrMatrix::kTransX],
337 m[GrMatrix::kTransY],
338 m[GrMatrix::kPersp2]
339 };
340 if (GrGLProgram::kSetAsAttribute ==
341 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
342 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
343 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
344 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
345 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
346 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000347 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000348 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000349 recordHWSamplerMatrix(s, getSamplerMatrix(s));
350 }
351 }
junov@google.comf93e7172011-03-31 21:26:24 +0000352}
353
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000354void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000355
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
357 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000358 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
360 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
361 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000362
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000363 GrScalar centerX1 = sampler.getRadial2CenterX1();
364 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000365
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000366 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000367
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 float values[6] = {
369 GrScalarToFloat(a),
370 1 / (2.f * values[0]),
371 GrScalarToFloat(centerX1),
372 GrScalarToFloat(radius0),
373 GrScalarToFloat(GrMul(radius0, radius0)),
374 sampler.isRadial2PosRoot() ? 1.f : -1.f
375 };
376 GR_GL(Uniform1fv(uni, 6, values));
377 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
378 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
379 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
380 }
381}
382
383void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000384 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000385 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000386 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
387 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
388 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
389
390 float texelSize[] = {1.f / texture->allocWidth(),
391 1.f / texture->allocHeight()};
392 GR_GL(Uniform2fv(uni, 1, texelSize));
393 }
394 }
junov@google.comf93e7172011-03-31 21:26:24 +0000395}
396
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000397void GrGpuGLShaders::flushColor() {
398 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
399 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
400 // color will be specified per-vertex as an attribute
401 // invalidate the const vertex attrib color
402 fHWDrawState.fColor = GrColor_ILLEGAL;
403 } else {
404 switch (desc.fColorType) {
405 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
406 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
407 // OpenGL ES only supports the float varities of glVertexAttrib
408 float c[] = {
409 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
410 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
411 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
412 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
413 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000414 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000415 fHWDrawState.fColor = fCurrDrawState.fColor;
416 }
417 break;
418 case GrGLProgram::ProgramDesc::kUniform_ColorType:
419 if (fProgramData->fColor != fCurrDrawState.fColor) {
420 // OpenGL ES only supports the float varities of glVertexAttrib
421 float c[] = {
422 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
423 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
424 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
425 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
426 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000427 GrAssert(GrGLProgram::kUnusedUniform !=
428 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000429 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
430 fProgramData->fColor = fCurrDrawState.fColor;
431 }
432 break;
433 case GrGLProgram::ProgramDesc::kNone_ColorType:
434 GrAssert(0xffffffff == fCurrDrawState.fColor);
435 break;
436 default:
437 GrCrash("Unknown color type.");
438 }
439 }
440}
441
442
junov@google.comf93e7172011-03-31 21:26:24 +0000443bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
444 if (!flushGLStateCommon(type)) {
445 return false;
446 }
447
448 if (fDirtyFlags.fRenderTargetChanged) {
449 // our coords are in pixel space and the GL matrices map to NDC
450 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000451 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000452 // we assume all shader matrices may be wrong after viewport changes
453 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000454 }
455
junov@google.comf93e7172011-03-31 21:26:24 +0000456 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000457 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000458 if (NULL == fProgramData) {
459 GrAssert(!"Failed to create program!");
460 return false;
461 }
junov@google.comf93e7172011-03-31 21:26:24 +0000462
463 if (fHWProgramID != fProgramData->fProgramID) {
464 GR_GL(UseProgram(fProgramData->fProgramID));
465 fHWProgramID = fProgramData->fProgramID;
466 }
467
468 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
469 return false;
470 }
471
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000472 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000473
bsalomon@google.com91961302011-05-09 18:39:58 +0000474 GrMatrix* currViewMatrix;
475 if (GrGLProgram::kSetAsAttribute ==
476 fProgramData->fUniLocations.fViewMatrixUni) {
477 currViewMatrix = &fHWDrawState.fViewMatrix;
478 } else {
479 currViewMatrix = &fProgramData->fViewMatrix;
480 }
junov@google.comf93e7172011-03-31 21:26:24 +0000481
bsalomon@google.com91961302011-05-09 18:39:58 +0000482 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000483 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000484 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000485 }
486
487 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000488 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000489
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000490 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000491
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000492 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000493 }
494 resetDirtyFlags();
495 return true;
496}
497
498void GrGpuGLShaders::postDraw() {
499 fCurrentProgram.doGLPost();
500}
501
502void GrGpuGLShaders::setupGeometry(int* startVertex,
503 int* startIndex,
504 int vertexCount,
505 int indexCount) {
506
507 int newColorOffset;
508 int newTexCoordOffsets[kMaxTexCoords];
509
510 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
511 newTexCoordOffsets,
512 &newColorOffset);
513 int oldColorOffset;
514 int oldTexCoordOffsets[kMaxTexCoords];
515 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
516 oldTexCoordOffsets,
517 &oldColorOffset);
518 bool indexed = NULL != startIndex;
519
520 int extraVertexOffset;
521 int extraIndexOffset;
522 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
523
524 GrGLenum scalarType;
525 bool texCoordNorm;
526 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
527 scalarType = GrGLTextType;
528 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
529 } else {
530 scalarType = GrGLType;
531 texCoordNorm = false;
532 }
533
534 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
535 *startVertex = 0;
536 if (indexed) {
537 *startIndex += extraIndexOffset;
538 }
539
540 // all the Pointers must be set if any of these are true
541 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
542 vertexOffset != fHWGeometryState.fVertexOffset ||
543 newStride != oldStride;
544
545 // position and tex coord offsets change if above conditions are true
546 // or the type/normalization changed based on text vs nontext type coords.
547 bool posAndTexChange = allOffsetsChange ||
548 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
549 (kTextFormat_VertexLayoutBit &
550 (fHWGeometryState.fVertexLayout ^
551 fGeometrySrc.fVertexLayout)));
552
553 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000554 int idx = GrGLProgram::PositionAttributeIdx();
555 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
556 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000557 fHWGeometryState.fVertexOffset = vertexOffset;
558 }
559
560 for (int t = 0; t < kMaxTexCoords; ++t) {
561 if (newTexCoordOffsets[t] > 0) {
562 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000563 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000564 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000565 GR_GL(EnableVertexAttribArray(idx));
566 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
567 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000568 } else if (posAndTexChange ||
569 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000570 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
571 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000572 }
573 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000574 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000575 }
576 }
577
578 if (newColorOffset > 0) {
579 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000581 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000582 GR_GL(EnableVertexAttribArray(idx));
583 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000584 true, newStride, colorOffset));
585 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000586 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000587 true, newStride, colorOffset));
588 }
589 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000590 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000591 }
592
593 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
594 fHWGeometryState.fArrayPtrsDirty = false;
595}
596
597void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000598 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000599
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000600 // Must initialize all fields or cache will have false negatives!
601 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
602
603 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
604
605 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
606 // fColorType records how colors are specified for the program. Strip
607 // the bit from the layout to avoid false negatives when searching for an
608 // existing program in the cache.
609 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
610
junov@google.comf93e7172011-03-31 21:26:24 +0000611#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000612 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000613 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000614 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000615#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000616#if GR_GL_NO_CONSTANT_ATTRIBUTES
617 if (!requiresAttributeColors) {
618 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
619 } else
620#endif
621 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000622 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000623 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
624 }
junov@google.comf93e7172011-03-31 21:26:24 +0000625
626 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000627 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000628
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000629 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000630
631 if (stage.fEnabled) {
632 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
633 GrAssert(NULL != texture);
634 // we matrix to invert when orientation is TopDown, so make sure
635 // we aren't in that case before flagging as identity.
636 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
637 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
638 } else if (!getSamplerMatrix(s).hasPerspective()) {
639 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
640 } else {
641 stage.fOptFlags = 0;
642 }
643 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000644 case GrSamplerState::kNormal_SampleMode:
645 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
646 break;
647 case GrSamplerState::kRadial_SampleMode:
648 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
649 break;
650 case GrSamplerState::kRadial2_SampleMode:
651 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
652 break;
653 case GrSamplerState::kSweep_SampleMode:
654 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
655 break;
656 default:
657 GrCrash("Unexpected sample mode!");
658 break;
659 }
660
661 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
662 // these both can use a regular texture2D()
663 case GrSamplerState::kNearest_Filter:
664 case GrSamplerState::kBilinear_Filter:
665 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
666 break;
667 // performs 4 texture2D()s
668 case GrSamplerState::k4x4Downsample_Filter:
669 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
670 break;
671 default:
672 GrCrash("Unexpected filter!");
673 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000674 }
675
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000676 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000677 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
678 } else {
679 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
680 }
681
682 if (fCurrDrawState.fEffects[s]) {
683 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
684 } else {
685 delete fCurrentProgram.fStageEffects[s];
686 fCurrentProgram.fStageEffects[s] = NULL;
687 }
688 } else {
689 stage.fOptFlags = 0;
690 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
691 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
692 fCurrentProgram.fStageEffects[s] = NULL;
693 }
694 }
695}
696
697
698