blob: be030f1e6d2a123a7e8f2cc32dfc6a2550761ce8 [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
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000399void GrGpuGLShaders::flushColor() {
400 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
401 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
402 // color will be specified per-vertex as an attribute
403 // invalidate the const vertex attrib color
404 fHWDrawState.fColor = GrColor_ILLEGAL;
405 } else {
406 switch (desc.fColorType) {
407 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
408 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
409 // OpenGL ES only supports the float varities of glVertexAttrib
410 float c[] = {
411 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
412 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
413 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
414 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
415 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000416 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000417 fHWDrawState.fColor = fCurrDrawState.fColor;
418 }
419 break;
420 case GrGLProgram::ProgramDesc::kUniform_ColorType:
421 if (fProgramData->fColor != fCurrDrawState.fColor) {
422 // OpenGL ES only supports the float varities of glVertexAttrib
423 float c[] = {
424 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
425 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
426 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
427 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
428 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000429 GrAssert(GrGLProgram::kUnusedUniform !=
430 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000431 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
432 fProgramData->fColor = fCurrDrawState.fColor;
433 }
434 break;
435 case GrGLProgram::ProgramDesc::kNone_ColorType:
436 GrAssert(0xffffffff == fCurrDrawState.fColor);
437 break;
438 default:
439 GrCrash("Unknown color type.");
440 }
441 }
Scroggo97c88c22011-05-11 14:05:25 +0000442 if (fProgramData->fUniLocations.fColorFilterUni
443 != GrGLProgram::kUnusedUniform
444 && fProgramData->fColorFilterColor
445 != fCurrDrawState.fColorFilterColor) {
446 float c[] = {
447 GrColorUnpackR(fCurrDrawState.fColorFilterColor) / 255.f,
448 GrColorUnpackG(fCurrDrawState.fColorFilterColor) / 255.f,
449 GrColorUnpackB(fCurrDrawState.fColorFilterColor) / 255.f,
450 GrColorUnpackA(fCurrDrawState.fColorFilterColor) / 255.f
451 };
452 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
453 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
454 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000455}
456
457
junov@google.comf93e7172011-03-31 21:26:24 +0000458bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
459 if (!flushGLStateCommon(type)) {
460 return false;
461 }
462
463 if (fDirtyFlags.fRenderTargetChanged) {
464 // our coords are in pixel space and the GL matrices map to NDC
465 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000466 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000467 // we assume all shader matrices may be wrong after viewport changes
468 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000469 }
470
junov@google.comf93e7172011-03-31 21:26:24 +0000471 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000472 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000473 if (NULL == fProgramData) {
474 GrAssert(!"Failed to create program!");
475 return false;
476 }
junov@google.comf93e7172011-03-31 21:26:24 +0000477
478 if (fHWProgramID != fProgramData->fProgramID) {
479 GR_GL(UseProgram(fProgramData->fProgramID));
480 fHWProgramID = fProgramData->fProgramID;
481 }
482
483 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
484 return false;
485 }
486
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000487 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000488
bsalomon@google.com91961302011-05-09 18:39:58 +0000489 GrMatrix* currViewMatrix;
490 if (GrGLProgram::kSetAsAttribute ==
491 fProgramData->fUniLocations.fViewMatrixUni) {
492 currViewMatrix = &fHWDrawState.fViewMatrix;
493 } else {
494 currViewMatrix = &fProgramData->fViewMatrix;
495 }
junov@google.comf93e7172011-03-31 21:26:24 +0000496
bsalomon@google.com91961302011-05-09 18:39:58 +0000497 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000498 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000499 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000500 }
501
502 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000503 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000504
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000505 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000506
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000507 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000508 }
509 resetDirtyFlags();
510 return true;
511}
512
513void GrGpuGLShaders::postDraw() {
514 fCurrentProgram.doGLPost();
515}
516
517void GrGpuGLShaders::setupGeometry(int* startVertex,
518 int* startIndex,
519 int vertexCount,
520 int indexCount) {
521
522 int newColorOffset;
523 int newTexCoordOffsets[kMaxTexCoords];
524
525 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
526 newTexCoordOffsets,
527 &newColorOffset);
528 int oldColorOffset;
529 int oldTexCoordOffsets[kMaxTexCoords];
530 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
531 oldTexCoordOffsets,
532 &oldColorOffset);
533 bool indexed = NULL != startIndex;
534
535 int extraVertexOffset;
536 int extraIndexOffset;
537 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
538
539 GrGLenum scalarType;
540 bool texCoordNorm;
541 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
542 scalarType = GrGLTextType;
543 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
544 } else {
545 scalarType = GrGLType;
546 texCoordNorm = false;
547 }
548
549 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
550 *startVertex = 0;
551 if (indexed) {
552 *startIndex += extraIndexOffset;
553 }
554
555 // all the Pointers must be set if any of these are true
556 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
557 vertexOffset != fHWGeometryState.fVertexOffset ||
558 newStride != oldStride;
559
560 // position and tex coord offsets change if above conditions are true
561 // or the type/normalization changed based on text vs nontext type coords.
562 bool posAndTexChange = allOffsetsChange ||
563 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
564 (kTextFormat_VertexLayoutBit &
565 (fHWGeometryState.fVertexLayout ^
566 fGeometrySrc.fVertexLayout)));
567
568 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000569 int idx = GrGLProgram::PositionAttributeIdx();
570 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
571 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000572 fHWGeometryState.fVertexOffset = vertexOffset;
573 }
574
575 for (int t = 0; t < kMaxTexCoords; ++t) {
576 if (newTexCoordOffsets[t] > 0) {
577 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000578 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000579 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 GR_GL(EnableVertexAttribArray(idx));
581 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
582 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000583 } else if (posAndTexChange ||
584 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000585 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
586 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000587 }
588 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000589 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000590 }
591 }
592
593 if (newColorOffset > 0) {
594 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000595 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000596 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000597 GR_GL(EnableVertexAttribArray(idx));
598 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000599 true, newStride, colorOffset));
600 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000601 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000602 true, newStride, colorOffset));
603 }
604 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000605 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000606 }
607
608 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
609 fHWGeometryState.fArrayPtrsDirty = false;
610}
611
612void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000613 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000614
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000615 // Must initialize all fields or cache will have false negatives!
616 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
617
618 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
619
620 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
621 // fColorType records how colors are specified for the program. Strip
622 // the bit from the layout to avoid false negatives when searching for an
623 // existing program in the cache.
624 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
625
junov@google.comf93e7172011-03-31 21:26:24 +0000626#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000627 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000628 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000629 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000630#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000631#if GR_GL_NO_CONSTANT_ATTRIBUTES
632 if (!requiresAttributeColors) {
633 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
634 } else
635#endif
636 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000637 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000638 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
639 }
junov@google.comf93e7172011-03-31 21:26:24 +0000640
641 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000642 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000643
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000644 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000645
646 if (stage.fEnabled) {
647 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
648 GrAssert(NULL != texture);
649 // we matrix to invert when orientation is TopDown, so make sure
650 // we aren't in that case before flagging as identity.
651 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
652 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
653 } else if (!getSamplerMatrix(s).hasPerspective()) {
654 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
655 } else {
656 stage.fOptFlags = 0;
657 }
658 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000659 case GrSamplerState::kNormal_SampleMode:
660 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
661 break;
662 case GrSamplerState::kRadial_SampleMode:
663 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
664 break;
665 case GrSamplerState::kRadial2_SampleMode:
666 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
667 break;
668 case GrSamplerState::kSweep_SampleMode:
669 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
670 break;
671 default:
672 GrCrash("Unexpected sample mode!");
673 break;
674 }
675
676 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
677 // these both can use a regular texture2D()
678 case GrSamplerState::kNearest_Filter:
679 case GrSamplerState::kBilinear_Filter:
680 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
681 break;
682 // performs 4 texture2D()s
683 case GrSamplerState::k4x4Downsample_Filter:
684 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
685 break;
686 default:
687 GrCrash("Unexpected filter!");
688 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000689 }
690
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000691 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000692 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
693 } else {
694 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
695 }
696
697 if (fCurrDrawState.fEffects[s]) {
698 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
699 } else {
700 delete fCurrentProgram.fStageEffects[s];
701 fCurrentProgram.fStageEffects[s] = NULL;
702 }
703 } else {
704 stage.fOptFlags = 0;
705 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
706 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
707 fCurrentProgram.fStageEffects[s] = NULL;
708 }
709 }
Scroggo97c88c22011-05-11 14:05:25 +0000710 desc.fColorFilterColor = fCurrDrawState.fColorFilterColor;
711 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000712}
713
714
715