blob: 2487563122973e6cabe6e1b0fbaf624df8cb2383 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrBinHashKey.h"
18#include "GrGLEffect.h"
19#include "GrGLProgram.h"
20#include "GrGpuGLShaders.h"
21#include "GrGpuVertex.h"
22#include "GrMemory.h"
23#include "GrNoncopyable.h"
24#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000025#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000026
junov@google.comf93e7172011-03-31 21:26:24 +000027#define SKIP_CACHE_CHECK true
28#define GR_UINT32_MAX static_cast<uint32_t>(-1)
29
junov@google.comf93e7172011-03-31 21:26:24 +000030#include "GrTHashCache.h"
31
32class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
33private:
34 class Entry;
35
36#if GR_DEBUG
37 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
38#else
39 typedef GrBinHashKey<Entry, 32> ProgramHashKey;
40#endif
41
42 class Entry : public ::GrNoncopyable {
43 public:
44 Entry() {}
45 private:
46 void copyAndTakeOwnership(Entry& entry) {
47 fProgramData.copyAndTakeOwnership(entry.fProgramData);
48 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000049 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000050 }
51
52 public:
53 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
54
55 public:
56 GrGLProgram::CachedData fProgramData;
57 ProgramHashKey fKey;
58 unsigned int fLRUStamp;
59 };
60
61 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
62
63 enum {
64 kMaxEntries = 32
65 };
66 Entry fEntries[kMaxEntries];
67 int fCount;
68 unsigned int fCurrLRUStamp;
69
70public:
71 ProgramCache()
72 : fCount(0)
73 , fCurrLRUStamp(0) {
74 }
75
76 ~ProgramCache() {
77 for (int i = 0; i < fCount; ++i) {
78 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
79 }
80 }
81
82 void abandon() {
83 fCount = 0;
84 }
85
86 void invalidateViewMatrices() {
87 for (int i = 0; i < fCount; ++i) {
88 // set to illegal matrix
89 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
90 }
91 }
92
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000093 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
junov@google.comf93e7172011-03-31 21:26:24 +000094 ProgramHashKey key;
95 while (key.doPass()) {
96 desc.buildKey(key);
97 }
98 Entry* entry = fHashCache.find(key);
99 if (NULL == entry) {
100 if (fCount < kMaxEntries) {
101 entry = fEntries + fCount;
102 ++fCount;
103 } else {
104 GrAssert(kMaxEntries == fCount);
105 entry = fEntries;
106 for (int i = 1; i < kMaxEntries; ++i) {
107 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
108 entry = fEntries + i;
109 }
110 }
111 fHashCache.remove(entry->fKey, entry);
112 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
113 }
114 entry->fKey.copyAndTakeOwnership(key);
bsalomon@google.com91961302011-05-09 18:39:58 +0000115 if (!desc.genProgram(&entry->fProgramData)) {
116 return NULL;
117 }
junov@google.comf93e7172011-03-31 21:26:24 +0000118 fHashCache.insert(entry->fKey, entry);
119 }
120
121 entry->fLRUStamp = fCurrLRUStamp;
122 if (GR_UINT32_MAX == fCurrLRUStamp) {
123 // wrap around! just trash our LRU, one time hit.
124 for (int i = 0; i < fCount; ++i) {
125 fEntries[i].fLRUStamp = 0;
126 }
127 }
128 ++fCurrLRUStamp;
129 return &entry->fProgramData;
130 }
131};
132
133void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
134 GR_GL(DeleteShader(programData->fVShaderID));
135 GR_GL(DeleteShader(programData->fFShaderID));
136 GR_GL(DeleteProgram(programData->fProgramID));
137 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
138}
139
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000140void GrGpuGLShaders::ProgramUnitTest() {
141
142 static const int STAGE_OPTS[] = {
143 0,
144 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
145 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
146 };
147 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
148 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
149 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
150 };
151 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
152 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
153 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
154 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
155 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
156 };
157 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
158 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
159 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
160 };
161 GrGLProgram program;
162 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
163
164 static const int NUM_TESTS = 512;
165
166 // GrRandoms nextU() values have patterns in the low bits
167 // So using nextU() % array_count might never take some values.
168 GrRandom random;
169 for (int t = 0; t < NUM_TESTS; ++t) {
170
171 pdesc.fVertexLayout = 0;
172 pdesc.fEmitsPointSize = random.nextF() > .5f;
173 float colorType = random.nextF();
174 if (colorType < 1.f / 3.f) {
175 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
176 } else if (colorType < 2.f / 3.f) {
177 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
178 } else {
179 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
180 }
181 for (int s = 0; s < kNumStages; ++s) {
182 // enable the stage?
183 if (random.nextF() > .5f) {
184 // use separate tex coords?
185 if (random.nextF() > .5f) {
186 int t = (int)(random.nextF() * kMaxTexCoords);
187 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
188 } else {
189 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
190 }
191 }
192 // use text-formatted verts?
193 if (random.nextF() > .5f) {
194 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
195 }
196 }
197
198 for (int s = 0; s < kNumStages; ++s) {
199 int x;
200 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
201 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
202 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
203 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
204 pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
205 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
206 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
207 x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
208 pdesc.fStages[s].fFetchMode = FETCH_MODES[x];
209 }
210 GrGLProgram::CachedData cachedData;
211 program.genProgram(&cachedData);
212 DeleteProgram(&cachedData);
213 bool again = false;
214 if (again) {
215 program.genProgram(&cachedData);
216 DeleteProgram(&cachedData);
217 }
218 }
219}
220
junov@google.comf93e7172011-03-31 21:26:24 +0000221
222GrGpuGLShaders::GrGpuGLShaders() {
223
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000224 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000225 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000226
227 fProgramData = NULL;
228 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000229
230#if 0
231 ProgramUnitTest();
232#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000233}
234
235GrGpuGLShaders::~GrGpuGLShaders() {
236 delete fProgramCache;
237}
238
239const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000240 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000241
242 if (GrGLProgram::kSetAsAttribute ==
243 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
244 return fHWDrawState.fSamplerStates[stage].getMatrix();
245 } else {
246 return fProgramData->fTextureMatrices[stage];
247 }
junov@google.comf93e7172011-03-31 21:26:24 +0000248}
249
250void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000251 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000252 if (GrGLProgram::kSetAsAttribute ==
253 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
254 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
255 } else {
256 fProgramData->fTextureMatrices[stage] = matrix;
257 }
junov@google.comf93e7172011-03-31 21:26:24 +0000258}
259
260void GrGpuGLShaders::resetContext() {
261 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000262
junov@google.comf93e7172011-03-31 21:26:24 +0000263 fHWGeometryState.fVertexLayout = 0;
264 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000265 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000266 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000267 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000268 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000269 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000270
271 fHWProgramID = 0;
272}
273
274void GrGpuGLShaders::flushViewMatrix() {
275 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000276 GrMatrix m;
277 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000278 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
279 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
280 0, 0, GrMatrix::I()[8]);
281 m.setConcat(m, fCurrDrawState.fViewMatrix);
282
283 // ES doesn't allow you to pass true to the transpose param,
284 // so do our own transpose
285 GrScalar mt[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000286 m[GrMatrix::kMScaleX],
287 m[GrMatrix::kMSkewY],
288 m[GrMatrix::kMPersp0],
289 m[GrMatrix::kMSkewX],
290 m[GrMatrix::kMScaleY],
291 m[GrMatrix::kMPersp1],
292 m[GrMatrix::kMTransX],
293 m[GrMatrix::kMTransY],
294 m[GrMatrix::kMPersp2]
junov@google.comf93e7172011-03-31 21:26:24 +0000295 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000296
297 if (GrGLProgram::kSetAsAttribute ==
298 fProgramData->fUniLocations.fViewMatrixUni) {
299 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
300 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
301 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
302 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
303 } else {
304 GrAssert(GrGLProgram::kUnusedUniform !=
305 fProgramData->fUniLocations.fViewMatrixUni);
306 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
307 1, false, mt));
308 }
junov@google.comf93e7172011-03-31 21:26:24 +0000309}
310
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000311void GrGpuGLShaders::flushTextureMatrix(int s) {
312 const int& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
313 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
314 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000315 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000316 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
317 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000318
bsalomon@google.com91961302011-05-09 18:39:58 +0000319 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000320
bsalomon@google.com91961302011-05-09 18:39:58 +0000321 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000322
bsalomon@google.com91961302011-05-09 18:39:58 +0000323 GrMatrix m = getSamplerMatrix(s);
324 GrSamplerState::SampleMode mode =
325 fCurrDrawState.fSamplerStates[s].getSampleMode();
326 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000327
bsalomon@google.com91961302011-05-09 18:39:58 +0000328 // ES doesn't allow you to pass true to the transpose param,
329 // so do our own transpose
330 GrScalar mt[] = {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000331 m[GrMatrix::kMScaleX],
332 m[GrMatrix::kMSkewY],
333 m[GrMatrix::kMPersp0],
334 m[GrMatrix::kMSkewX],
335 m[GrMatrix::kMScaleY],
336 m[GrMatrix::kMPersp1],
337 m[GrMatrix::kMTransX],
338 m[GrMatrix::kMTransY],
339 m[GrMatrix::kMPersp2]
bsalomon@google.com91961302011-05-09 18:39:58 +0000340 };
341 if (GrGLProgram::kSetAsAttribute ==
342 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
343 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
344 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
345 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
346 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
347 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000348 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000349 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 recordHWSamplerMatrix(s, getSamplerMatrix(s));
351 }
352 }
junov@google.comf93e7172011-03-31 21:26:24 +0000353}
354
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000355void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000356
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
358 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000359 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000360 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
361 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
362 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000363
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000364 GrScalar centerX1 = sampler.getRadial2CenterX1();
365 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000366
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000367 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000368
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000369 float values[6] = {
370 GrScalarToFloat(a),
371 1 / (2.f * values[0]),
372 GrScalarToFloat(centerX1),
373 GrScalarToFloat(radius0),
374 GrScalarToFloat(GrMul(radius0, radius0)),
375 sampler.isRadial2PosRoot() ? 1.f : -1.f
376 };
377 GR_GL(Uniform1fv(uni, 6, values));
378 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
379 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
380 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
381 }
382}
383
384void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000385 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000386 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
388 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
389 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
390
391 float texelSize[] = {1.f / texture->allocWidth(),
392 1.f / texture->allocHeight()};
393 GR_GL(Uniform2fv(uni, 1, texelSize));
394 }
395 }
junov@google.comf93e7172011-03-31 21:26:24 +0000396}
397
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000398void GrGpuGLShaders::flushColor() {
399 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
400 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
401 // color will be specified per-vertex as an attribute
402 // invalidate the const vertex attrib color
403 fHWDrawState.fColor = GrColor_ILLEGAL;
404 } else {
405 switch (desc.fColorType) {
406 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
407 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
408 // OpenGL ES only supports the float varities of glVertexAttrib
409 float c[] = {
410 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
411 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
412 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
413 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
414 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000415 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000416 fHWDrawState.fColor = fCurrDrawState.fColor;
417 }
418 break;
419 case GrGLProgram::ProgramDesc::kUniform_ColorType:
420 if (fProgramData->fColor != fCurrDrawState.fColor) {
421 // OpenGL ES only supports the float varities of glVertexAttrib
422 float c[] = {
423 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
424 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
425 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
426 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
427 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000428 GrAssert(GrGLProgram::kUnusedUniform !=
429 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000430 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
431 fProgramData->fColor = fCurrDrawState.fColor;
432 }
433 break;
434 case GrGLProgram::ProgramDesc::kNone_ColorType:
435 GrAssert(0xffffffff == fCurrDrawState.fColor);
436 break;
437 default:
438 GrCrash("Unknown color type.");
439 }
440 }
Scroggo97c88c22011-05-11 14:05:25 +0000441 if (fProgramData->fUniLocations.fColorFilterUni
442 != GrGLProgram::kUnusedUniform
443 && fProgramData->fColorFilterColor
444 != fCurrDrawState.fColorFilterColor) {
445 float c[] = {
446 GrColorUnpackR(fCurrDrawState.fColorFilterColor) / 255.f,
447 GrColorUnpackG(fCurrDrawState.fColorFilterColor) / 255.f,
448 GrColorUnpackB(fCurrDrawState.fColorFilterColor) / 255.f,
449 GrColorUnpackA(fCurrDrawState.fColorFilterColor) / 255.f
450 };
451 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
452 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
453 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000454}
455
456
junov@google.comf93e7172011-03-31 21:26:24 +0000457bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
458 if (!flushGLStateCommon(type)) {
459 return false;
460 }
461
462 if (fDirtyFlags.fRenderTargetChanged) {
463 // our coords are in pixel space and the GL matrices map to NDC
464 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000465 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000466 // we assume all shader matrices may be wrong after viewport changes
467 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000468 }
469
junov@google.comf93e7172011-03-31 21:26:24 +0000470 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000471 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000472 if (NULL == fProgramData) {
473 GrAssert(!"Failed to create program!");
474 return false;
475 }
junov@google.comf93e7172011-03-31 21:26:24 +0000476
477 if (fHWProgramID != fProgramData->fProgramID) {
478 GR_GL(UseProgram(fProgramData->fProgramID));
479 fHWProgramID = fProgramData->fProgramID;
480 }
481
482 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
483 return false;
484 }
485
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000486 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000487
bsalomon@google.com91961302011-05-09 18:39:58 +0000488 GrMatrix* currViewMatrix;
489 if (GrGLProgram::kSetAsAttribute ==
490 fProgramData->fUniLocations.fViewMatrixUni) {
491 currViewMatrix = &fHWDrawState.fViewMatrix;
492 } else {
493 currViewMatrix = &fProgramData->fViewMatrix;
494 }
junov@google.comf93e7172011-03-31 21:26:24 +0000495
bsalomon@google.com91961302011-05-09 18:39:58 +0000496 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000497 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000498 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000499 }
500
501 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000502 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000503
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000504 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000505
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000506 this->flushTexelSize(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000507 }
508 resetDirtyFlags();
509 return true;
510}
511
512void GrGpuGLShaders::postDraw() {
513 fCurrentProgram.doGLPost();
514}
515
516void GrGpuGLShaders::setupGeometry(int* startVertex,
517 int* startIndex,
518 int vertexCount,
519 int indexCount) {
520
521 int newColorOffset;
522 int newTexCoordOffsets[kMaxTexCoords];
523
524 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
525 newTexCoordOffsets,
526 &newColorOffset);
527 int oldColorOffset;
528 int oldTexCoordOffsets[kMaxTexCoords];
529 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
530 oldTexCoordOffsets,
531 &oldColorOffset);
532 bool indexed = NULL != startIndex;
533
534 int extraVertexOffset;
535 int extraIndexOffset;
536 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
537
538 GrGLenum scalarType;
539 bool texCoordNorm;
540 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
541 scalarType = GrGLTextType;
542 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
543 } else {
544 scalarType = GrGLType;
545 texCoordNorm = false;
546 }
547
548 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
549 *startVertex = 0;
550 if (indexed) {
551 *startIndex += extraIndexOffset;
552 }
553
554 // all the Pointers must be set if any of these are true
555 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
556 vertexOffset != fHWGeometryState.fVertexOffset ||
557 newStride != oldStride;
558
559 // position and tex coord offsets change if above conditions are true
560 // or the type/normalization changed based on text vs nontext type coords.
561 bool posAndTexChange = allOffsetsChange ||
562 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
563 (kTextFormat_VertexLayoutBit &
564 (fHWGeometryState.fVertexLayout ^
565 fGeometrySrc.fVertexLayout)));
566
567 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000568 int idx = GrGLProgram::PositionAttributeIdx();
569 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
570 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000571 fHWGeometryState.fVertexOffset = vertexOffset;
572 }
573
574 for (int t = 0; t < kMaxTexCoords; ++t) {
575 if (newTexCoordOffsets[t] > 0) {
576 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000577 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000578 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000579 GR_GL(EnableVertexAttribArray(idx));
580 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
581 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000582 } else if (posAndTexChange ||
583 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000584 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
585 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000586 }
587 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000588 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000589 }
590 }
591
592 if (newColorOffset > 0) {
593 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000594 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000595 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000596 GR_GL(EnableVertexAttribArray(idx));
597 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000598 true, newStride, colorOffset));
599 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000600 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000601 true, newStride, colorOffset));
602 }
603 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000604 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000605 }
606
607 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
608 fHWGeometryState.fArrayPtrsDirty = false;
609}
610
611void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000612 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000613
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000614 // Must initialize all fields or cache will have false negatives!
615 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
616
617 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
618
619 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
620 // fColorType records how colors are specified for the program. Strip
621 // the bit from the layout to avoid false negatives when searching for an
622 // existing program in the cache.
623 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
624
junov@google.comf93e7172011-03-31 21:26:24 +0000625#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000626 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000627 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000628 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000629#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000630#if GR_GL_NO_CONSTANT_ATTRIBUTES
631 if (!requiresAttributeColors) {
632 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
633 } else
634#endif
635 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000636 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000637 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
638 }
junov@google.comf93e7172011-03-31 21:26:24 +0000639
640 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000641 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000642
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000643 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000644
645 if (stage.fEnabled) {
646 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
647 GrAssert(NULL != texture);
648 // we matrix to invert when orientation is TopDown, so make sure
649 // we aren't in that case before flagging as identity.
650 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
651 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
652 } else if (!getSamplerMatrix(s).hasPerspective()) {
653 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
654 } else {
655 stage.fOptFlags = 0;
656 }
657 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000658 case GrSamplerState::kNormal_SampleMode:
659 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
660 break;
661 case GrSamplerState::kRadial_SampleMode:
662 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
663 break;
664 case GrSamplerState::kRadial2_SampleMode:
665 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
666 break;
667 case GrSamplerState::kSweep_SampleMode:
668 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
669 break;
670 default:
671 GrCrash("Unexpected sample mode!");
672 break;
673 }
674
675 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
676 // these both can use a regular texture2D()
677 case GrSamplerState::kNearest_Filter:
678 case GrSamplerState::kBilinear_Filter:
679 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
680 break;
681 // performs 4 texture2D()s
682 case GrSamplerState::k4x4Downsample_Filter:
683 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
684 break;
685 default:
686 GrCrash("Unexpected filter!");
687 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000688 }
689
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000690 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000691 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
692 } else {
693 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
694 }
695
696 if (fCurrDrawState.fEffects[s]) {
697 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
698 } else {
699 delete fCurrentProgram.fStageEffects[s];
700 fCurrentProgram.fStageEffects[s] = NULL;
701 }
702 } else {
703 stage.fOptFlags = 0;
704 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
705 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
706 fCurrentProgram.fStageEffects[s] = NULL;
707 }
708 }
Scroggo97c88c22011-05-11 14:05:25 +0000709 desc.fColorFilterColor = fCurrDrawState.fColorFilterColor;
710 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000711}
712
713
714