blob: 3ce6e55d69edc542dac4be2c2504157114838d47 [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);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000276 GrMatrix m;
277 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000278 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[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000286 m[GrMatrix::kMScaleX],
287 m[GrMatrix::kMSkewY],
288 m[GrMatrix::kMPersp0],
289 m[GrMatrix::kMSkewX],
290 m[GrMatrix::kMScaleY],
291 m[GrMatrix::kMPersp1],
292 m[GrMatrix::kMTransX],
293 m[GrMatrix::kMTransY],
294 m[GrMatrix::kMPersp2]
junov@google.comf93e7172011-03-31 21:26:24 +0000295 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000296
297 if (GrGLProgram::kSetAsAttribute ==
298 fProgramData->fUniLocations.fViewMatrixUni) {
299 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
300 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
301 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
302 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
303 } else {
304 GrAssert(GrGLProgram::kUnusedUniform !=
305 fProgramData->fUniLocations.fViewMatrixUni);
306 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
307 1, false, mt));
308 }
junov@google.comf93e7172011-03-31 21:26:24 +0000309}
310
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000311void GrGpuGLShaders::flushTextureMatrix(int s) {
312 const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
313 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
314 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000315 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000316 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
317 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000318
bsalomon@google.com91961302011-05-09 18:39:58 +0000319 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000320
bsalomon@google.com91961302011-05-09 18:39:58 +0000321 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000322
bsalomon@google.com91961302011-05-09 18:39:58 +0000323 GrMatrix m = getSamplerMatrix(s);
324 GrSamplerState::SampleMode mode =
325 fCurrDrawState.fSamplerStates[s].getSampleMode();
326 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000327
bsalomon@google.com91961302011-05-09 18:39:58 +0000328 // ES doesn't allow you to pass true to the transpose param,
329 // so do our own transpose
330 GrScalar mt[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000331 m[GrMatrix::kMScaleX],
332 m[GrMatrix::kMSkewY],
333 m[GrMatrix::kMPersp0],
334 m[GrMatrix::kMSkewX],
335 m[GrMatrix::kMScaleY],
336 m[GrMatrix::kMPersp1],
337 m[GrMatrix::kMTransX],
338 m[GrMatrix::kMTransY],
339 m[GrMatrix::kMPersp2]
bsalomon@google.com91961302011-05-09 18:39:58 +0000340 };
341 if (GrGLProgram::kSetAsAttribute ==
342 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
343 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
344 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
345 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
346 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
347 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000348 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000349 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 recordHWSamplerMatrix(s, getSamplerMatrix(s));
351 }
352 }
junov@google.comf93e7172011-03-31 21:26:24 +0000353}
354
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000355void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000356
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
358 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000359 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000360 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
361 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
362 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000363
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000364 GrScalar centerX1 = sampler.getRadial2CenterX1();
365 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000366
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000367 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000368
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000369 float values[6] = {
370 GrScalarToFloat(a),
371 1 / (2.f * values[0]),
372 GrScalarToFloat(centerX1),
373 GrScalarToFloat(radius0),
374 GrScalarToFloat(GrMul(radius0, radius0)),
375 sampler.isRadial2PosRoot() ? 1.f : -1.f
376 };
377 GR_GL(Uniform1fv(uni, 6, values));
378 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
379 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
380 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
381 }
382}
383
384void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000385 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000386 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
388 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
389 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
390
391 float texelSize[] = {1.f / texture->allocWidth(),
392 1.f / texture->allocHeight()};
393 GR_GL(Uniform2fv(uni, 1, texelSize));
394 }
395 }
junov@google.comf93e7172011-03-31 21:26:24 +0000396}
397
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000398void GrGpuGLShaders::flushColor() {
399 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
400 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
401 // color will be specified per-vertex as an attribute
402 // invalidate the const vertex attrib color
403 fHWDrawState.fColor = GrColor_ILLEGAL;
404 } else {
405 switch (desc.fColorType) {
406 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
407 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
408 // OpenGL ES only supports the float varities of glVertexAttrib
409 float c[] = {
410 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
411 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
412 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
413 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
414 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000415 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000416 fHWDrawState.fColor = fCurrDrawState.fColor;
417 }
418 break;
419 case GrGLProgram::ProgramDesc::kUniform_ColorType:
420 if (fProgramData->fColor != fCurrDrawState.fColor) {
421 // OpenGL ES only supports the float varities of glVertexAttrib
422 float c[] = {
423 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
424 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
425 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
426 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
427 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000428 GrAssert(GrGLProgram::kUnusedUniform !=
429 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000430 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
431 fProgramData->fColor = fCurrDrawState.fColor;
432 }
433 break;
434 case GrGLProgram::ProgramDesc::kNone_ColorType:
435 GrAssert(0xffffffff == fCurrDrawState.fColor);
436 break;
437 default:
438 GrCrash("Unknown color type.");
439 }
440 }
441}
442
443
junov@google.comf93e7172011-03-31 21:26:24 +0000444bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
445 if (!flushGLStateCommon(type)) {
446 return false;
447 }
448
449 if (fDirtyFlags.fRenderTargetChanged) {
450 // our coords are in pixel space and the GL matrices map to NDC
451 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000452 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000453 // we assume all shader matrices may be wrong after viewport changes
454 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000455 }
456
junov@google.comf93e7172011-03-31 21:26:24 +0000457 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000458 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000459 if (NULL == fProgramData) {
460 GrAssert(!"Failed to create program!");
461 return false;
462 }
junov@google.comf93e7172011-03-31 21:26:24 +0000463
464 if (fHWProgramID != fProgramData->fProgramID) {
465 GR_GL(UseProgram(fProgramData->fProgramID));
466 fHWProgramID = fProgramData->fProgramID;
467 }
468
469 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
470 return false;
471 }
472
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000473 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000474
bsalomon@google.com91961302011-05-09 18:39:58 +0000475 GrMatrix* currViewMatrix;
476 if (GrGLProgram::kSetAsAttribute ==
477 fProgramData->fUniLocations.fViewMatrixUni) {
478 currViewMatrix = &fHWDrawState.fViewMatrix;
479 } else {
480 currViewMatrix = &fProgramData->fViewMatrix;
481 }
junov@google.comf93e7172011-03-31 21:26:24 +0000482
bsalomon@google.com91961302011-05-09 18:39:58 +0000483 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000484 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000485 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000486 }
487
488 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000489 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000490
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000491 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000492
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000493 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000494 }
495 resetDirtyFlags();
496 return true;
497}
498
499void GrGpuGLShaders::postDraw() {
500 fCurrentProgram.doGLPost();
501}
502
503void GrGpuGLShaders::setupGeometry(int* startVertex,
504 int* startIndex,
505 int vertexCount,
506 int indexCount) {
507
508 int newColorOffset;
509 int newTexCoordOffsets[kMaxTexCoords];
510
511 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
512 newTexCoordOffsets,
513 &newColorOffset);
514 int oldColorOffset;
515 int oldTexCoordOffsets[kMaxTexCoords];
516 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
517 oldTexCoordOffsets,
518 &oldColorOffset);
519 bool indexed = NULL != startIndex;
520
521 int extraVertexOffset;
522 int extraIndexOffset;
523 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
524
525 GrGLenum scalarType;
526 bool texCoordNorm;
527 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
528 scalarType = GrGLTextType;
529 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
530 } else {
531 scalarType = GrGLType;
532 texCoordNorm = false;
533 }
534
535 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
536 *startVertex = 0;
537 if (indexed) {
538 *startIndex += extraIndexOffset;
539 }
540
541 // all the Pointers must be set if any of these are true
542 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
543 vertexOffset != fHWGeometryState.fVertexOffset ||
544 newStride != oldStride;
545
546 // position and tex coord offsets change if above conditions are true
547 // or the type/normalization changed based on text vs nontext type coords.
548 bool posAndTexChange = allOffsetsChange ||
549 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
550 (kTextFormat_VertexLayoutBit &
551 (fHWGeometryState.fVertexLayout ^
552 fGeometrySrc.fVertexLayout)));
553
554 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000555 int idx = GrGLProgram::PositionAttributeIdx();
556 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
557 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000558 fHWGeometryState.fVertexOffset = vertexOffset;
559 }
560
561 for (int t = 0; t < kMaxTexCoords; ++t) {
562 if (newTexCoordOffsets[t] > 0) {
563 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000564 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000565 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000566 GR_GL(EnableVertexAttribArray(idx));
567 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
568 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000569 } else if (posAndTexChange ||
570 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000571 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
572 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000573 }
574 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000575 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000576 }
577 }
578
579 if (newColorOffset > 0) {
580 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000581 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000582 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000583 GR_GL(EnableVertexAttribArray(idx));
584 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000585 true, newStride, colorOffset));
586 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000587 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000588 true, newStride, colorOffset));
589 }
590 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000591 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000592 }
593
594 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
595 fHWGeometryState.fArrayPtrsDirty = false;
596}
597
598void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000599 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000600
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000601 // Must initialize all fields or cache will have false negatives!
602 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
603
604 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
605
606 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
607 // fColorType records how colors are specified for the program. Strip
608 // the bit from the layout to avoid false negatives when searching for an
609 // existing program in the cache.
610 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
611
junov@google.comf93e7172011-03-31 21:26:24 +0000612#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000613 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000614 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000615 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000616#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000617#if GR_GL_NO_CONSTANT_ATTRIBUTES
618 if (!requiresAttributeColors) {
619 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
620 } else
621#endif
622 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000623 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000624 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
625 }
junov@google.comf93e7172011-03-31 21:26:24 +0000626
627 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000628 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000629
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000630 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000631
632 if (stage.fEnabled) {
633 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
634 GrAssert(NULL != texture);
635 // we matrix to invert when orientation is TopDown, so make sure
636 // we aren't in that case before flagging as identity.
637 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
638 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
639 } else if (!getSamplerMatrix(s).hasPerspective()) {
640 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
641 } else {
642 stage.fOptFlags = 0;
643 }
644 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000645 case GrSamplerState::kNormal_SampleMode:
646 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
647 break;
648 case GrSamplerState::kRadial_SampleMode:
649 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
650 break;
651 case GrSamplerState::kRadial2_SampleMode:
652 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
653 break;
654 case GrSamplerState::kSweep_SampleMode:
655 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
656 break;
657 default:
658 GrCrash("Unexpected sample mode!");
659 break;
660 }
661
662 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
663 // these both can use a regular texture2D()
664 case GrSamplerState::kNearest_Filter:
665 case GrSamplerState::kBilinear_Filter:
666 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
667 break;
668 // performs 4 texture2D()s
669 case GrSamplerState::k4x4Downsample_Filter:
670 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
671 break;
672 default:
673 GrCrash("Unexpected filter!");
674 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000675 }
676
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000677 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000678 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
679 } else {
680 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
681 }
682
683 if (fCurrDrawState.fEffects[s]) {
684 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
685 } else {
686 delete fCurrentProgram.fStageEffects[s];
687 fCurrentProgram.fStageEffects[s] = NULL;
688 }
689 } else {
690 stage.fOptFlags = 0;
691 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
692 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
693 fCurrentProgram.fStageEffects[s] = NULL;
694 }
695 }
696}
697
698
699