blob: 937c8ed4224314c1db8b6a69db734e725f01a6fe [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() {}
junov@google.comf93e7172011-03-31 21:26:24 +000045 void copyAndTakeOwnership(Entry& entry) {
46 fProgramData.copyAndTakeOwnership(entry.fProgramData);
47 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000048 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000049 }
50
51 public:
52 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
53
54 public:
55 GrGLProgram::CachedData fProgramData;
56 ProgramHashKey fKey;
57 unsigned int fLRUStamp;
58 };
59
60 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
61
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000062 // We may have kMaxEntries+1 shaders in the GL context because
63 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000064 enum {
65 kMaxEntries = 32
66 };
67 Entry fEntries[kMaxEntries];
68 int fCount;
69 unsigned int fCurrLRUStamp;
70
71public:
72 ProgramCache()
73 : fCount(0)
74 , fCurrLRUStamp(0) {
75 }
76
77 ~ProgramCache() {
78 for (int i = 0; i < fCount; ++i) {
79 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
80 }
81 }
82
83 void abandon() {
84 fCount = 0;
85 }
86
87 void invalidateViewMatrices() {
88 for (int i = 0; i < fCount; ++i) {
89 // set to illegal matrix
90 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
91 }
92 }
93
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000094 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000095 Entry newEntry;
96 while (newEntry.fKey.doPass()) {
97 desc.buildKey(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000098 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000099 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +0000100 if (NULL == entry) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000101 if (!desc.genProgram(&newEntry.fProgramData)) {
102 return NULL;
103 }
junov@google.comf93e7172011-03-31 21:26:24 +0000104 if (fCount < kMaxEntries) {
105 entry = fEntries + fCount;
106 ++fCount;
107 } else {
108 GrAssert(kMaxEntries == fCount);
109 entry = fEntries;
110 for (int i = 1; i < kMaxEntries; ++i) {
111 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
112 entry = fEntries + i;
113 }
114 }
115 fHashCache.remove(entry->fKey, entry);
116 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
117 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000118 entry->copyAndTakeOwnership(newEntry);
junov@google.comf93e7172011-03-31 21:26:24 +0000119 fHashCache.insert(entry->fKey, entry);
120 }
121
122 entry->fLRUStamp = fCurrLRUStamp;
123 if (GR_UINT32_MAX == fCurrLRUStamp) {
124 // wrap around! just trash our LRU, one time hit.
125 for (int i = 0; i < fCount; ++i) {
126 fEntries[i].fLRUStamp = 0;
127 }
128 }
129 ++fCurrLRUStamp;
130 return &entry->fProgramData;
131 }
132};
133
134void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
135 GR_GL(DeleteShader(programData->fVShaderID));
136 GR_GL(DeleteShader(programData->fFShaderID));
137 GR_GL(DeleteProgram(programData->fProgramID));
138 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
139}
140
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000141void GrGpuGLShaders::ProgramUnitTest() {
142
143 static const int STAGE_OPTS[] = {
144 0,
145 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
146 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
147 };
148 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
149 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
150 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
151 };
152 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
153 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
154 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
155 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
156 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
157 };
158 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
159 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
160 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
161 };
162 GrGLProgram program;
163 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
164
165 static const int NUM_TESTS = 512;
166
167 // GrRandoms nextU() values have patterns in the low bits
168 // So using nextU() % array_count might never take some values.
169 GrRandom random;
170 for (int t = 0; t < NUM_TESTS; ++t) {
171
172 pdesc.fVertexLayout = 0;
173 pdesc.fEmitsPointSize = random.nextF() > .5f;
174 float colorType = random.nextF();
175 if (colorType < 1.f / 3.f) {
176 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
177 } else if (colorType < 2.f / 3.f) {
178 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
179 } else {
180 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
181 }
182 for (int s = 0; s < kNumStages; ++s) {
183 // enable the stage?
184 if (random.nextF() > .5f) {
185 // use separate tex coords?
186 if (random.nextF() > .5f) {
187 int t = (int)(random.nextF() * kMaxTexCoords);
188 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
189 } else {
190 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
191 }
192 }
193 // use text-formatted verts?
194 if (random.nextF() > .5f) {
195 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
196 }
197 }
198
199 for (int s = 0; s < kNumStages; ++s) {
200 int x;
201 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
202 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
203 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
204 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
205 pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
206 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
207 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
208 x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
209 pdesc.fStages[s].fFetchMode = FETCH_MODES[x];
210 }
211 GrGLProgram::CachedData cachedData;
212 program.genProgram(&cachedData);
213 DeleteProgram(&cachedData);
214 bool again = false;
215 if (again) {
216 program.genProgram(&cachedData);
217 DeleteProgram(&cachedData);
218 }
219 }
220}
221
junov@google.comf93e7172011-03-31 21:26:24 +0000222
223GrGpuGLShaders::GrGpuGLShaders() {
224
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000225 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000226 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000227
228 fProgramData = NULL;
229 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000230
231#if 0
232 ProgramUnitTest();
233#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000234}
235
236GrGpuGLShaders::~GrGpuGLShaders() {
237 delete fProgramCache;
238}
239
240const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000241 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000242
243 if (GrGLProgram::kSetAsAttribute ==
244 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
245 return fHWDrawState.fSamplerStates[stage].getMatrix();
246 } else {
247 return fProgramData->fTextureMatrices[stage];
248 }
junov@google.comf93e7172011-03-31 21:26:24 +0000249}
250
251void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000252 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000253 if (GrGLProgram::kSetAsAttribute ==
254 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
255 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
256 } else {
257 fProgramData->fTextureMatrices[stage] = matrix;
258 }
junov@google.comf93e7172011-03-31 21:26:24 +0000259}
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;
bsalomon@google.com91961302011-05-09 18:39:58 +0000266 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000267 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000268 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000269 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000270 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000271
272 fHWProgramID = 0;
273}
274
275void GrGpuGLShaders::flushViewMatrix() {
276 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000277 GrMatrix m;
278 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000279 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
280 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
281 0, 0, GrMatrix::I()[8]);
282 m.setConcat(m, fCurrDrawState.fViewMatrix);
283
284 // ES doesn't allow you to pass true to the transpose param,
285 // so do our own transpose
286 GrScalar mt[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000287 m[GrMatrix::kMScaleX],
288 m[GrMatrix::kMSkewY],
289 m[GrMatrix::kMPersp0],
290 m[GrMatrix::kMSkewX],
291 m[GrMatrix::kMScaleY],
292 m[GrMatrix::kMPersp1],
293 m[GrMatrix::kMTransX],
294 m[GrMatrix::kMTransY],
295 m[GrMatrix::kMPersp2]
junov@google.comf93e7172011-03-31 21:26:24 +0000296 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000297
298 if (GrGLProgram::kSetAsAttribute ==
299 fProgramData->fUniLocations.fViewMatrixUni) {
300 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
301 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
302 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
303 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
304 } else {
305 GrAssert(GrGLProgram::kUnusedUniform !=
306 fProgramData->fUniLocations.fViewMatrixUni);
307 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
308 1, false, mt));
309 }
junov@google.comf93e7172011-03-31 21:26:24 +0000310}
311
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000312void GrGpuGLShaders::flushTextureMatrix(int s) {
313 const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
314 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
315 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000316 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000317 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
318 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000319
bsalomon@google.com91961302011-05-09 18:39:58 +0000320 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000321
bsalomon@google.com91961302011-05-09 18:39:58 +0000322 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000323
bsalomon@google.com91961302011-05-09 18:39:58 +0000324 GrMatrix m = getSamplerMatrix(s);
325 GrSamplerState::SampleMode mode =
326 fCurrDrawState.fSamplerStates[s].getSampleMode();
327 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000328
bsalomon@google.com91961302011-05-09 18:39:58 +0000329 // ES doesn't allow you to pass true to the transpose param,
330 // so do our own transpose
331 GrScalar mt[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000332 m[GrMatrix::kMScaleX],
333 m[GrMatrix::kMSkewY],
334 m[GrMatrix::kMPersp0],
335 m[GrMatrix::kMSkewX],
336 m[GrMatrix::kMScaleY],
337 m[GrMatrix::kMPersp1],
338 m[GrMatrix::kMTransX],
339 m[GrMatrix::kMTransY],
340 m[GrMatrix::kMPersp2]
bsalomon@google.com91961302011-05-09 18:39:58 +0000341 };
342 if (GrGLProgram::kSetAsAttribute ==
343 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
344 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
345 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
346 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
347 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
348 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000349 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000350 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000351 recordHWSamplerMatrix(s, getSamplerMatrix(s));
352 }
353 }
junov@google.comf93e7172011-03-31 21:26:24 +0000354}
355
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000357
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000358 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
359 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000360 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000361 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
362 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
363 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000364
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000365 GrScalar centerX1 = sampler.getRadial2CenterX1();
366 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000367
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000369
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000370 float values[6] = {
371 GrScalarToFloat(a),
372 1 / (2.f * values[0]),
373 GrScalarToFloat(centerX1),
374 GrScalarToFloat(radius0),
375 GrScalarToFloat(GrMul(radius0, radius0)),
376 sampler.isRadial2PosRoot() ? 1.f : -1.f
377 };
378 GR_GL(Uniform1fv(uni, 6, values));
379 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
380 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
381 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
382 }
383}
384
385void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000386 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000387 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000388 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
389 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
390 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
391
392 float texelSize[] = {1.f / texture->allocWidth(),
393 1.f / texture->allocHeight()};
394 GR_GL(Uniform2fv(uni, 1, texelSize));
395 }
396 }
junov@google.comf93e7172011-03-31 21:26:24 +0000397}
398
Scroggo01b87ec2011-05-11 18:05:38 +0000399static const float ONE_OVER_255 = 1.f / 255.f;
400
401#define GR_COLOR_TO_VEC4(color) {\
402 GrColorUnpackR(color) * ONE_OVER_255,\
403 GrColorUnpackG(color) * ONE_OVER_255,\
404 GrColorUnpackB(color) * ONE_OVER_255,\
405 GrColorUnpackA(color) * ONE_OVER_255 \
406}
407
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000408void GrGpuGLShaders::flushColor() {
409 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
410 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
411 // color will be specified per-vertex as an attribute
412 // invalidate the const vertex attrib color
413 fHWDrawState.fColor = GrColor_ILLEGAL;
414 } else {
415 switch (desc.fColorType) {
416 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
417 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
418 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000419 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000420 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000421 fHWDrawState.fColor = fCurrDrawState.fColor;
422 }
423 break;
424 case GrGLProgram::ProgramDesc::kUniform_ColorType:
425 if (fProgramData->fColor != fCurrDrawState.fColor) {
426 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000427 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
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 }
Scroggo97c88c22011-05-11 14:05:25 +0000441 if (fProgramData->fUniLocations.fColorFilterUni
442 != GrGLProgram::kUnusedUniform
443 && fProgramData->fColorFilterColor
444 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000445 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000446 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
447 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
448 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000449}
450
451
junov@google.comf93e7172011-03-31 21:26:24 +0000452bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
453 if (!flushGLStateCommon(type)) {
454 return false;
455 }
456
457 if (fDirtyFlags.fRenderTargetChanged) {
458 // our coords are in pixel space and the GL matrices map to NDC
459 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000460 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000461 // we assume all shader matrices may be wrong after viewport changes
462 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000463 }
464
junov@google.comf93e7172011-03-31 21:26:24 +0000465 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000466 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000467 if (NULL == fProgramData) {
468 GrAssert(!"Failed to create program!");
469 return false;
470 }
junov@google.comf93e7172011-03-31 21:26:24 +0000471
472 if (fHWProgramID != fProgramData->fProgramID) {
473 GR_GL(UseProgram(fProgramData->fProgramID));
474 fHWProgramID = fProgramData->fProgramID;
475 }
476
477 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
478 return false;
479 }
480
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000481 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000482
bsalomon@google.com91961302011-05-09 18:39:58 +0000483 GrMatrix* currViewMatrix;
484 if (GrGLProgram::kSetAsAttribute ==
485 fProgramData->fUniLocations.fViewMatrixUni) {
486 currViewMatrix = &fHWDrawState.fViewMatrix;
487 } else {
488 currViewMatrix = &fProgramData->fViewMatrix;
489 }
junov@google.comf93e7172011-03-31 21:26:24 +0000490
bsalomon@google.com91961302011-05-09 18:39:58 +0000491 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000492 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000493 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000494 }
495
496 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000498
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000499 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000500
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000501 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000502 }
503 resetDirtyFlags();
504 return true;
505}
506
507void GrGpuGLShaders::postDraw() {
508 fCurrentProgram.doGLPost();
509}
510
511void GrGpuGLShaders::setupGeometry(int* startVertex,
512 int* startIndex,
513 int vertexCount,
514 int indexCount) {
515
516 int newColorOffset;
517 int newTexCoordOffsets[kMaxTexCoords];
518
519 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
520 newTexCoordOffsets,
521 &newColorOffset);
522 int oldColorOffset;
523 int oldTexCoordOffsets[kMaxTexCoords];
524 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
525 oldTexCoordOffsets,
526 &oldColorOffset);
527 bool indexed = NULL != startIndex;
528
529 int extraVertexOffset;
530 int extraIndexOffset;
531 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
532
533 GrGLenum scalarType;
534 bool texCoordNorm;
535 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
536 scalarType = GrGLTextType;
537 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
538 } else {
539 scalarType = GrGLType;
540 texCoordNorm = false;
541 }
542
543 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
544 *startVertex = 0;
545 if (indexed) {
546 *startIndex += extraIndexOffset;
547 }
548
549 // all the Pointers must be set if any of these are true
550 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
551 vertexOffset != fHWGeometryState.fVertexOffset ||
552 newStride != oldStride;
553
554 // position and tex coord offsets change if above conditions are true
555 // or the type/normalization changed based on text vs nontext type coords.
556 bool posAndTexChange = allOffsetsChange ||
557 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
558 (kTextFormat_VertexLayoutBit &
559 (fHWGeometryState.fVertexLayout ^
560 fGeometrySrc.fVertexLayout)));
561
562 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000563 int idx = GrGLProgram::PositionAttributeIdx();
564 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
565 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000566 fHWGeometryState.fVertexOffset = vertexOffset;
567 }
568
569 for (int t = 0; t < kMaxTexCoords; ++t) {
570 if (newTexCoordOffsets[t] > 0) {
571 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000572 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000573 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000574 GR_GL(EnableVertexAttribArray(idx));
575 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
576 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000577 } else if (posAndTexChange ||
578 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000579 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
580 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000581 }
582 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000583 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000584 }
585 }
586
587 if (newColorOffset > 0) {
588 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000589 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000590 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000591 GR_GL(EnableVertexAttribArray(idx));
592 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000593 true, newStride, colorOffset));
594 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000595 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000596 true, newStride, colorOffset));
597 }
598 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000599 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000600 }
601
602 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
603 fHWGeometryState.fArrayPtrsDirty = false;
604}
605
606void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000607 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000608
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000609 // Must initialize all fields or cache will have false negatives!
610 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
611
612 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
613
614 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
615 // fColorType records how colors are specified for the program. Strip
616 // the bit from the layout to avoid false negatives when searching for an
617 // existing program in the cache.
618 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
619
junov@google.comf93e7172011-03-31 21:26:24 +0000620#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000621 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000622 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000623 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000624#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000625#if GR_GL_NO_CONSTANT_ATTRIBUTES
626 if (!requiresAttributeColors) {
627 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
628 } else
629#endif
630 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000631 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000632 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
633 }
junov@google.comf93e7172011-03-31 21:26:24 +0000634
635 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000636 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000637
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000638 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000639
640 if (stage.fEnabled) {
641 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
642 GrAssert(NULL != texture);
643 // we matrix to invert when orientation is TopDown, so make sure
644 // we aren't in that case before flagging as identity.
645 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
646 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
647 } else if (!getSamplerMatrix(s).hasPerspective()) {
648 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
649 } else {
650 stage.fOptFlags = 0;
651 }
652 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000653 case GrSamplerState::kNormal_SampleMode:
654 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
655 break;
656 case GrSamplerState::kRadial_SampleMode:
657 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
658 break;
659 case GrSamplerState::kRadial2_SampleMode:
660 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
661 break;
662 case GrSamplerState::kSweep_SampleMode:
663 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
664 break;
665 default:
666 GrCrash("Unexpected sample mode!");
667 break;
668 }
669
670 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
671 // these both can use a regular texture2D()
672 case GrSamplerState::kNearest_Filter:
673 case GrSamplerState::kBilinear_Filter:
674 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
675 break;
676 // performs 4 texture2D()s
677 case GrSamplerState::k4x4Downsample_Filter:
678 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
679 break;
680 default:
681 GrCrash("Unexpected filter!");
682 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000683 }
684
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000685 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000686 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
687 } else {
688 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
689 }
690
691 if (fCurrDrawState.fEffects[s]) {
692 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
693 } else {
694 delete fCurrentProgram.fStageEffects[s];
695 fCurrentProgram.fStageEffects[s] = NULL;
696 }
697 } else {
698 stage.fOptFlags = 0;
699 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
700 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
701 fCurrentProgram.fStageEffects[s] = NULL;
702 }
703 }
Scroggo97c88c22011-05-11 14:05:25 +0000704 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000705}
706
707
708