blob: fcfc12039a147d8b87d678487cdf7cde4ca5c52e [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
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000286 GrGLfloat mt[] = {
287 GrScalarToFloat(m[GrMatrix::kMScaleX]),
288 GrScalarToFloat(m[GrMatrix::kMSkewY]),
289 GrScalarToFloat(m[GrMatrix::kMPersp0]),
290 GrScalarToFloat(m[GrMatrix::kMSkewX]),
291 GrScalarToFloat(m[GrMatrix::kMScaleY]),
292 GrScalarToFloat(m[GrMatrix::kMPersp1]),
293 GrScalarToFloat(m[GrMatrix::kMTransX]),
294 GrScalarToFloat(m[GrMatrix::kMTransY]),
295 GrScalarToFloat(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
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000331 GrGLfloat mt[] = {
332 GrScalarToFloat(m[GrMatrix::kMScaleX]),
333 GrScalarToFloat(m[GrMatrix::kMSkewY]),
334 GrScalarToFloat(m[GrMatrix::kMPersp0]),
335 GrScalarToFloat(m[GrMatrix::kMSkewX]),
336 GrScalarToFloat(m[GrMatrix::kMScaleY]),
337 GrScalarToFloat(m[GrMatrix::kMPersp1]),
338 GrScalarToFloat(m[GrMatrix::kMTransX]),
339 GrScalarToFloat(m[GrMatrix::kMTransY]),
340 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000341 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000342
bsalomon@google.com91961302011-05-09 18:39:58 +0000343 if (GrGLProgram::kSetAsAttribute ==
344 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
345 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
346 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
347 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
348 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
349 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000351 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000352 recordHWSamplerMatrix(s, getSamplerMatrix(s));
353 }
354 }
junov@google.comf93e7172011-03-31 21:26:24 +0000355}
356
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000358
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
360 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000361 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000362 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
363 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
364 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000365
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000366 GrScalar centerX1 = sampler.getRadial2CenterX1();
367 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000368
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000369 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000370
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000371 float values[6] = {
372 GrScalarToFloat(a),
373 1 / (2.f * values[0]),
374 GrScalarToFloat(centerX1),
375 GrScalarToFloat(radius0),
376 GrScalarToFloat(GrMul(radius0, radius0)),
377 sampler.isRadial2PosRoot() ? 1.f : -1.f
378 };
379 GR_GL(Uniform1fv(uni, 6, values));
380 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
381 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
382 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
383 }
384}
385
386void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000388 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000389 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
390 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
391 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
392
393 float texelSize[] = {1.f / texture->allocWidth(),
394 1.f / texture->allocHeight()};
395 GR_GL(Uniform2fv(uni, 1, texelSize));
396 }
397 }
junov@google.comf93e7172011-03-31 21:26:24 +0000398}
399
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000400void GrGpuGLShaders::flushEdgeAAData() {
401 const int& uni = fProgramData->fUniLocations.fEdgesUni;
402 if (GrGLProgram::kUnusedUniform != uni) {
403 float edges[18];
404 memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
405 // Flip the edges in Y
406 float height = fCurrDrawState.fRenderTarget->height();
407 for (int i = 0; i < 6; ++i) {
408 float b = edges[i * 3 + 1];
409 edges[i * 3 + 1] = -b;
410 edges[i * 3 + 2] += b * height;
411 }
412 GR_GL(Uniform3fv(uni, 6, edges));
413 }
414}
415
Scroggo01b87ec2011-05-11 18:05:38 +0000416static const float ONE_OVER_255 = 1.f / 255.f;
417
418#define GR_COLOR_TO_VEC4(color) {\
419 GrColorUnpackR(color) * ONE_OVER_255,\
420 GrColorUnpackG(color) * ONE_OVER_255,\
421 GrColorUnpackB(color) * ONE_OVER_255,\
422 GrColorUnpackA(color) * ONE_OVER_255 \
423}
424
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000425void GrGpuGLShaders::flushColor() {
426 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
427 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
428 // color will be specified per-vertex as an attribute
429 // invalidate the const vertex attrib color
430 fHWDrawState.fColor = GrColor_ILLEGAL;
431 } else {
432 switch (desc.fColorType) {
433 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
434 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
435 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000436 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000437 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000438 fHWDrawState.fColor = fCurrDrawState.fColor;
439 }
440 break;
441 case GrGLProgram::ProgramDesc::kUniform_ColorType:
442 if (fProgramData->fColor != fCurrDrawState.fColor) {
443 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000444 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000445 GrAssert(GrGLProgram::kUnusedUniform !=
446 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000447 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
448 fProgramData->fColor = fCurrDrawState.fColor;
449 }
450 break;
451 case GrGLProgram::ProgramDesc::kNone_ColorType:
452 GrAssert(0xffffffff == fCurrDrawState.fColor);
453 break;
454 default:
455 GrCrash("Unknown color type.");
456 }
457 }
Scroggo97c88c22011-05-11 14:05:25 +0000458 if (fProgramData->fUniLocations.fColorFilterUni
459 != GrGLProgram::kUnusedUniform
460 && fProgramData->fColorFilterColor
461 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000462 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000463 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
464 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
465 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000466}
467
468
junov@google.comf93e7172011-03-31 21:26:24 +0000469bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
470 if (!flushGLStateCommon(type)) {
471 return false;
472 }
473
474 if (fDirtyFlags.fRenderTargetChanged) {
475 // our coords are in pixel space and the GL matrices map to NDC
476 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000477 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000478 // we assume all shader matrices may be wrong after viewport changes
479 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000480 }
481
junov@google.comf93e7172011-03-31 21:26:24 +0000482 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000483 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000484 if (NULL == fProgramData) {
485 GrAssert(!"Failed to create program!");
486 return false;
487 }
junov@google.comf93e7172011-03-31 21:26:24 +0000488
489 if (fHWProgramID != fProgramData->fProgramID) {
490 GR_GL(UseProgram(fProgramData->fProgramID));
491 fHWProgramID = fProgramData->fProgramID;
492 }
493
494 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
495 return false;
496 }
497
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000498 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000499
bsalomon@google.com91961302011-05-09 18:39:58 +0000500 GrMatrix* currViewMatrix;
501 if (GrGLProgram::kSetAsAttribute ==
502 fProgramData->fUniLocations.fViewMatrixUni) {
503 currViewMatrix = &fHWDrawState.fViewMatrix;
504 } else {
505 currViewMatrix = &fProgramData->fViewMatrix;
506 }
junov@google.comf93e7172011-03-31 21:26:24 +0000507
bsalomon@google.com91961302011-05-09 18:39:58 +0000508 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000509 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000510 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000511 }
512
513 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000514 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000515
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000516 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000517
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000518 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000519 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000520 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000521 resetDirtyFlags();
522 return true;
523}
524
525void GrGpuGLShaders::postDraw() {
526 fCurrentProgram.doGLPost();
527}
528
529void GrGpuGLShaders::setupGeometry(int* startVertex,
530 int* startIndex,
531 int vertexCount,
532 int indexCount) {
533
534 int newColorOffset;
535 int newTexCoordOffsets[kMaxTexCoords];
536
537 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
538 newTexCoordOffsets,
539 &newColorOffset);
540 int oldColorOffset;
541 int oldTexCoordOffsets[kMaxTexCoords];
542 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
543 oldTexCoordOffsets,
544 &oldColorOffset);
545 bool indexed = NULL != startIndex;
546
547 int extraVertexOffset;
548 int extraIndexOffset;
549 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
550
551 GrGLenum scalarType;
552 bool texCoordNorm;
553 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
554 scalarType = GrGLTextType;
555 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
556 } else {
557 scalarType = GrGLType;
558 texCoordNorm = false;
559 }
560
561 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
562 *startVertex = 0;
563 if (indexed) {
564 *startIndex += extraIndexOffset;
565 }
566
567 // all the Pointers must be set if any of these are true
568 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
569 vertexOffset != fHWGeometryState.fVertexOffset ||
570 newStride != oldStride;
571
572 // position and tex coord offsets change if above conditions are true
573 // or the type/normalization changed based on text vs nontext type coords.
574 bool posAndTexChange = allOffsetsChange ||
575 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
576 (kTextFormat_VertexLayoutBit &
577 (fHWGeometryState.fVertexLayout ^
578 fGeometrySrc.fVertexLayout)));
579
580 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000581 int idx = GrGLProgram::PositionAttributeIdx();
582 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
583 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000584 fHWGeometryState.fVertexOffset = vertexOffset;
585 }
586
587 for (int t = 0; t < kMaxTexCoords; ++t) {
588 if (newTexCoordOffsets[t] > 0) {
589 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000590 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000591 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000592 GR_GL(EnableVertexAttribArray(idx));
593 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
594 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000595 } else if (posAndTexChange ||
596 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000597 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
598 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000599 }
600 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000601 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000602 }
603 }
604
605 if (newColorOffset > 0) {
606 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000607 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000608 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000609 GR_GL(EnableVertexAttribArray(idx));
610 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000611 true, newStride, colorOffset));
612 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000613 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000614 true, newStride, colorOffset));
615 }
616 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000617 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000618 }
619
620 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
621 fHWGeometryState.fArrayPtrsDirty = false;
622}
623
624void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000625 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000626
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000627 // Must initialize all fields or cache will have false negatives!
628 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
629
630 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
631
632 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
633 // fColorType records how colors are specified for the program. Strip
634 // the bit from the layout to avoid false negatives when searching for an
635 // existing program in the cache.
636 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
637
junov@google.comf93e7172011-03-31 21:26:24 +0000638#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000639 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000640 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000641 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000642#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000643#if GR_GL_NO_CONSTANT_ATTRIBUTES
644 if (!requiresAttributeColors) {
645 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
646 } else
647#endif
648 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000649 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000650 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
651 }
junov@google.comf93e7172011-03-31 21:26:24 +0000652
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000653 desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
654
junov@google.comf93e7172011-03-31 21:26:24 +0000655 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000656 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000657
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000658 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000659
660 if (stage.fEnabled) {
661 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
662 GrAssert(NULL != texture);
663 // we matrix to invert when orientation is TopDown, so make sure
664 // we aren't in that case before flagging as identity.
665 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
666 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
667 } else if (!getSamplerMatrix(s).hasPerspective()) {
668 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
669 } else {
670 stage.fOptFlags = 0;
671 }
672 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000673 case GrSamplerState::kNormal_SampleMode:
674 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
675 break;
676 case GrSamplerState::kRadial_SampleMode:
677 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
678 break;
679 case GrSamplerState::kRadial2_SampleMode:
680 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
681 break;
682 case GrSamplerState::kSweep_SampleMode:
683 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
684 break;
685 default:
686 GrCrash("Unexpected sample mode!");
687 break;
688 }
689
690 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
691 // these both can use a regular texture2D()
692 case GrSamplerState::kNearest_Filter:
693 case GrSamplerState::kBilinear_Filter:
694 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
695 break;
696 // performs 4 texture2D()s
697 case GrSamplerState::k4x4Downsample_Filter:
698 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
699 break;
700 default:
701 GrCrash("Unexpected filter!");
702 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000703 }
704
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000705 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000706 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
707 } else {
708 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
709 }
710
711 if (fCurrDrawState.fEffects[s]) {
712 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
713 } else {
714 delete fCurrentProgram.fStageEffects[s];
715 fCurrentProgram.fStageEffects[s] = NULL;
716 }
717 } else {
718 stage.fOptFlags = 0;
719 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
720 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
721 fCurrentProgram.fStageEffects[s] = NULL;
722 }
723 }
Scroggo97c88c22011-05-11 14:05:25 +0000724 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000725}
726
727
728