blob: 8965b06520d98d99b33c4214b218b8734994c432 [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
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000039 typedef GrBinHashKey<Entry, 64> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000040#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
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000399void GrGpuGLShaders::flushEdgeAAData() {
400 const int& uni = fProgramData->fUniLocations.fEdgesUni;
401 if (GrGLProgram::kUnusedUniform != uni) {
402 float edges[18];
403 memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
404 // Flip the edges in Y
405 float height = fCurrDrawState.fRenderTarget->height();
406 for (int i = 0; i < 6; ++i) {
407 float b = edges[i * 3 + 1];
408 edges[i * 3 + 1] = -b;
409 edges[i * 3 + 2] += b * height;
410 }
411 GR_GL(Uniform3fv(uni, 6, edges));
412 }
413}
414
Scroggo01b87ec2011-05-11 18:05:38 +0000415static const float ONE_OVER_255 = 1.f / 255.f;
416
417#define GR_COLOR_TO_VEC4(color) {\
418 GrColorUnpackR(color) * ONE_OVER_255,\
419 GrColorUnpackG(color) * ONE_OVER_255,\
420 GrColorUnpackB(color) * ONE_OVER_255,\
421 GrColorUnpackA(color) * ONE_OVER_255 \
422}
423
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000424void GrGpuGLShaders::flushColor() {
425 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
426 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
427 // color will be specified per-vertex as an attribute
428 // invalidate the const vertex attrib color
429 fHWDrawState.fColor = GrColor_ILLEGAL;
430 } else {
431 switch (desc.fColorType) {
432 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
433 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
434 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000435 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000436 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000437 fHWDrawState.fColor = fCurrDrawState.fColor;
438 }
439 break;
440 case GrGLProgram::ProgramDesc::kUniform_ColorType:
441 if (fProgramData->fColor != fCurrDrawState.fColor) {
442 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000443 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000444 GrAssert(GrGLProgram::kUnusedUniform !=
445 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000446 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
447 fProgramData->fColor = fCurrDrawState.fColor;
448 }
449 break;
450 case GrGLProgram::ProgramDesc::kNone_ColorType:
451 GrAssert(0xffffffff == fCurrDrawState.fColor);
452 break;
453 default:
454 GrCrash("Unknown color type.");
455 }
456 }
Scroggo97c88c22011-05-11 14:05:25 +0000457 if (fProgramData->fUniLocations.fColorFilterUni
458 != GrGLProgram::kUnusedUniform
459 && fProgramData->fColorFilterColor
460 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000461 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000462 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
463 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
464 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000465}
466
467
junov@google.comf93e7172011-03-31 21:26:24 +0000468bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
469 if (!flushGLStateCommon(type)) {
470 return false;
471 }
472
473 if (fDirtyFlags.fRenderTargetChanged) {
474 // our coords are in pixel space and the GL matrices map to NDC
475 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000476 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000477 // we assume all shader matrices may be wrong after viewport changes
478 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000479 }
480
junov@google.comf93e7172011-03-31 21:26:24 +0000481 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000482 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000483 if (NULL == fProgramData) {
484 GrAssert(!"Failed to create program!");
485 return false;
486 }
junov@google.comf93e7172011-03-31 21:26:24 +0000487
488 if (fHWProgramID != fProgramData->fProgramID) {
489 GR_GL(UseProgram(fProgramData->fProgramID));
490 fHWProgramID = fProgramData->fProgramID;
491 }
492
493 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
494 return false;
495 }
496
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000498
bsalomon@google.com91961302011-05-09 18:39:58 +0000499 GrMatrix* currViewMatrix;
500 if (GrGLProgram::kSetAsAttribute ==
501 fProgramData->fUniLocations.fViewMatrixUni) {
502 currViewMatrix = &fHWDrawState.fViewMatrix;
503 } else {
504 currViewMatrix = &fProgramData->fViewMatrix;
505 }
junov@google.comf93e7172011-03-31 21:26:24 +0000506
bsalomon@google.com91961302011-05-09 18:39:58 +0000507 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000508 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000509 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000510 }
511
512 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000513 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000514
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000515 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000516
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000517 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000518 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000519 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000520 resetDirtyFlags();
521 return true;
522}
523
524void GrGpuGLShaders::postDraw() {
525 fCurrentProgram.doGLPost();
526}
527
528void GrGpuGLShaders::setupGeometry(int* startVertex,
529 int* startIndex,
530 int vertexCount,
531 int indexCount) {
532
533 int newColorOffset;
534 int newTexCoordOffsets[kMaxTexCoords];
535
536 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
537 newTexCoordOffsets,
538 &newColorOffset);
539 int oldColorOffset;
540 int oldTexCoordOffsets[kMaxTexCoords];
541 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
542 oldTexCoordOffsets,
543 &oldColorOffset);
544 bool indexed = NULL != startIndex;
545
546 int extraVertexOffset;
547 int extraIndexOffset;
548 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
549
550 GrGLenum scalarType;
551 bool texCoordNorm;
552 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
553 scalarType = GrGLTextType;
554 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
555 } else {
556 scalarType = GrGLType;
557 texCoordNorm = false;
558 }
559
560 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
561 *startVertex = 0;
562 if (indexed) {
563 *startIndex += extraIndexOffset;
564 }
565
566 // all the Pointers must be set if any of these are true
567 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
568 vertexOffset != fHWGeometryState.fVertexOffset ||
569 newStride != oldStride;
570
571 // position and tex coord offsets change if above conditions are true
572 // or the type/normalization changed based on text vs nontext type coords.
573 bool posAndTexChange = allOffsetsChange ||
574 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
575 (kTextFormat_VertexLayoutBit &
576 (fHWGeometryState.fVertexLayout ^
577 fGeometrySrc.fVertexLayout)));
578
579 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 int idx = GrGLProgram::PositionAttributeIdx();
581 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
582 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000583 fHWGeometryState.fVertexOffset = vertexOffset;
584 }
585
586 for (int t = 0; t < kMaxTexCoords; ++t) {
587 if (newTexCoordOffsets[t] > 0) {
588 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000589 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000590 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000591 GR_GL(EnableVertexAttribArray(idx));
592 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
593 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000594 } else if (posAndTexChange ||
595 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000596 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
597 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000598 }
599 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000600 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000601 }
602 }
603
604 if (newColorOffset > 0) {
605 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000606 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000607 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000608 GR_GL(EnableVertexAttribArray(idx));
609 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000610 true, newStride, colorOffset));
611 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000612 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000613 true, newStride, colorOffset));
614 }
615 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000616 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000617 }
618
619 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
620 fHWGeometryState.fArrayPtrsDirty = false;
621}
622
623void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000624 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000625
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000626 // Must initialize all fields or cache will have false negatives!
627 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
628
629 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
630
631 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
632 // fColorType records how colors are specified for the program. Strip
633 // the bit from the layout to avoid false negatives when searching for an
634 // existing program in the cache.
635 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
636
junov@google.comf93e7172011-03-31 21:26:24 +0000637#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000638 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000639 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000640 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000641#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000642#if GR_GL_NO_CONSTANT_ATTRIBUTES
643 if (!requiresAttributeColors) {
644 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
645 } else
646#endif
647 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000648 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000649 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
650 }
junov@google.comf93e7172011-03-31 21:26:24 +0000651
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000652 desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
653
junov@google.comf93e7172011-03-31 21:26:24 +0000654 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000655 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000656
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000657 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000658
659 if (stage.fEnabled) {
660 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
661 GrAssert(NULL != texture);
662 // we matrix to invert when orientation is TopDown, so make sure
663 // we aren't in that case before flagging as identity.
664 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
665 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
666 } else if (!getSamplerMatrix(s).hasPerspective()) {
667 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
668 } else {
669 stage.fOptFlags = 0;
670 }
671 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000672 case GrSamplerState::kNormal_SampleMode:
673 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
674 break;
675 case GrSamplerState::kRadial_SampleMode:
676 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
677 break;
678 case GrSamplerState::kRadial2_SampleMode:
679 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
680 break;
681 case GrSamplerState::kSweep_SampleMode:
682 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
683 break;
684 default:
685 GrCrash("Unexpected sample mode!");
686 break;
687 }
688
689 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
690 // these both can use a regular texture2D()
691 case GrSamplerState::kNearest_Filter:
692 case GrSamplerState::kBilinear_Filter:
693 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
694 break;
695 // performs 4 texture2D()s
696 case GrSamplerState::k4x4Downsample_Filter:
697 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
698 break;
699 default:
700 GrCrash("Unexpected filter!");
701 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000702 }
703
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000704 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000705 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
706 } else {
707 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
708 }
709
710 if (fCurrDrawState.fEffects[s]) {
711 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
712 } else {
713 delete fCurrentProgram.fStageEffects[s];
714 fCurrentProgram.fStageEffects[s] = NULL;
715 }
716 } else {
717 stage.fOptFlags = 0;
718 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
719 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
720 fCurrentProgram.fStageEffects[s] = NULL;
721 }
722 }
Scroggo97c88c22011-05-11 14:05:25 +0000723 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000724}
725
726
727