blob: 125b8205af826ad64858b3c04c19bf4fca45f9a5 [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
junov@google.com6acc9b32011-05-16 18:32:07 +0000312void GrGpuGLShaders::flushTextureDomain(int s) {
313 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
314 if (GrGLProgram::kUnusedUniform != uni) {
315 const GrRect &texDom =
316 fCurrDrawState.fSamplerStates[s].getTextureDomain();
317
318 float values[4] = {
319 GrScalarToFloat(texDom.left()),
320 GrScalarToFloat(texDom.top()),
321 GrScalarToFloat(texDom.right()),
322 GrScalarToFloat(texDom.bottom())
323 };
324
325 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
326 GrGLTexture::Orientation orientation = texture->orientation();
327
328 // vertical flip if necessary
329 if (GrGLTexture::kBottomUp_Orientation == orientation) {
330 values[1] = 1.0f - values[1];
331 values[3] = 1.0f - values[3];
332 }
333
334 values[0] *= SkScalarToFloat(texture->contentScaleX());
335 values[2] *= SkScalarToFloat(texture->contentScaleX());
336 values[1] *= SkScalarToFloat(texture->contentScaleY());
337 values[3] *= SkScalarToFloat(texture->contentScaleY());
338
339 GR_GL(Uniform4fv(uni, 1, values));
340 }
341}
342
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000343void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000344 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000345 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
346 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000347 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000348 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
349 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000350
bsalomon@google.com91961302011-05-09 18:39:58 +0000351 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000352
bsalomon@google.com91961302011-05-09 18:39:58 +0000353 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000354
bsalomon@google.com91961302011-05-09 18:39:58 +0000355 GrMatrix m = getSamplerMatrix(s);
356 GrSamplerState::SampleMode mode =
357 fCurrDrawState.fSamplerStates[s].getSampleMode();
358 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359
bsalomon@google.com91961302011-05-09 18:39:58 +0000360 // ES doesn't allow you to pass true to the transpose param,
361 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000362 GrGLfloat mt[] = {
363 GrScalarToFloat(m[GrMatrix::kMScaleX]),
364 GrScalarToFloat(m[GrMatrix::kMSkewY]),
365 GrScalarToFloat(m[GrMatrix::kMPersp0]),
366 GrScalarToFloat(m[GrMatrix::kMSkewX]),
367 GrScalarToFloat(m[GrMatrix::kMScaleY]),
368 GrScalarToFloat(m[GrMatrix::kMPersp1]),
369 GrScalarToFloat(m[GrMatrix::kMTransX]),
370 GrScalarToFloat(m[GrMatrix::kMTransY]),
371 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000372 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000373
bsalomon@google.com91961302011-05-09 18:39:58 +0000374 if (GrGLProgram::kSetAsAttribute ==
375 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
376 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
377 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
378 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
379 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
380 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000381 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000382 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000383 recordHWSamplerMatrix(s, getSamplerMatrix(s));
384 }
385 }
junov@google.comf93e7172011-03-31 21:26:24 +0000386}
387
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000388void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000389
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000390 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
391 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000393 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
394 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
395 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000396
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000397 GrScalar centerX1 = sampler.getRadial2CenterX1();
398 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000399
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000400 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000401
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000402 float values[6] = {
403 GrScalarToFloat(a),
404 1 / (2.f * values[0]),
405 GrScalarToFloat(centerX1),
406 GrScalarToFloat(radius0),
407 GrScalarToFloat(GrMul(radius0, radius0)),
408 sampler.isRadial2PosRoot() ? 1.f : -1.f
409 };
410 GR_GL(Uniform1fv(uni, 6, values));
411 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
412 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
413 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
414 }
415}
416
417void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000418 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000419 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000420 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
421 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
422 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
423
424 float texelSize[] = {1.f / texture->allocWidth(),
425 1.f / texture->allocHeight()};
426 GR_GL(Uniform2fv(uni, 1, texelSize));
427 }
428 }
junov@google.comf93e7172011-03-31 21:26:24 +0000429}
430
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000431void GrGpuGLShaders::flushEdgeAAData() {
432 const int& uni = fProgramData->fUniLocations.fEdgesUni;
433 if (GrGLProgram::kUnusedUniform != uni) {
434 float edges[18];
435 memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
436 // Flip the edges in Y
437 float height = fCurrDrawState.fRenderTarget->height();
438 for (int i = 0; i < 6; ++i) {
439 float b = edges[i * 3 + 1];
440 edges[i * 3 + 1] = -b;
441 edges[i * 3 + 2] += b * height;
442 }
443 GR_GL(Uniform3fv(uni, 6, edges));
444 }
445}
446
Scroggo01b87ec2011-05-11 18:05:38 +0000447static const float ONE_OVER_255 = 1.f / 255.f;
448
449#define GR_COLOR_TO_VEC4(color) {\
450 GrColorUnpackR(color) * ONE_OVER_255,\
451 GrColorUnpackG(color) * ONE_OVER_255,\
452 GrColorUnpackB(color) * ONE_OVER_255,\
453 GrColorUnpackA(color) * ONE_OVER_255 \
454}
455
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000456void GrGpuGLShaders::flushColor() {
457 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
458 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
459 // color will be specified per-vertex as an attribute
460 // invalidate the const vertex attrib color
461 fHWDrawState.fColor = GrColor_ILLEGAL;
462 } else {
463 switch (desc.fColorType) {
464 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
465 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
466 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000467 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000468 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000469 fHWDrawState.fColor = fCurrDrawState.fColor;
470 }
471 break;
472 case GrGLProgram::ProgramDesc::kUniform_ColorType:
473 if (fProgramData->fColor != fCurrDrawState.fColor) {
474 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000475 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000476 GrAssert(GrGLProgram::kUnusedUniform !=
477 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000478 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
479 fProgramData->fColor = fCurrDrawState.fColor;
480 }
481 break;
482 case GrGLProgram::ProgramDesc::kNone_ColorType:
483 GrAssert(0xffffffff == fCurrDrawState.fColor);
484 break;
485 default:
486 GrCrash("Unknown color type.");
487 }
488 }
Scroggo97c88c22011-05-11 14:05:25 +0000489 if (fProgramData->fUniLocations.fColorFilterUni
490 != GrGLProgram::kUnusedUniform
491 && fProgramData->fColorFilterColor
492 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000493 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000494 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
495 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
496 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000497}
498
499
junov@google.comf93e7172011-03-31 21:26:24 +0000500bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
501 if (!flushGLStateCommon(type)) {
502 return false;
503 }
504
505 if (fDirtyFlags.fRenderTargetChanged) {
506 // our coords are in pixel space and the GL matrices map to NDC
507 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000508 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000509 // we assume all shader matrices may be wrong after viewport changes
510 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000511 }
512
junov@google.comf93e7172011-03-31 21:26:24 +0000513 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000514 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000515 if (NULL == fProgramData) {
516 GrAssert(!"Failed to create program!");
517 return false;
518 }
junov@google.comf93e7172011-03-31 21:26:24 +0000519
520 if (fHWProgramID != fProgramData->fProgramID) {
521 GR_GL(UseProgram(fProgramData->fProgramID));
522 fHWProgramID = fProgramData->fProgramID;
523 }
524
525 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
526 return false;
527 }
528
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000529 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000530
bsalomon@google.com91961302011-05-09 18:39:58 +0000531 GrMatrix* currViewMatrix;
532 if (GrGLProgram::kSetAsAttribute ==
533 fProgramData->fUniLocations.fViewMatrixUni) {
534 currViewMatrix = &fHWDrawState.fViewMatrix;
535 } else {
536 currViewMatrix = &fProgramData->fViewMatrix;
537 }
junov@google.comf93e7172011-03-31 21:26:24 +0000538
bsalomon@google.com91961302011-05-09 18:39:58 +0000539 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000540 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000541 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000542 }
543
544 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000545 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000546
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000547 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000548
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000549 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000550
551 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000552 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000553 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000554 resetDirtyFlags();
555 return true;
556}
557
558void GrGpuGLShaders::postDraw() {
559 fCurrentProgram.doGLPost();
560}
561
562void GrGpuGLShaders::setupGeometry(int* startVertex,
563 int* startIndex,
564 int vertexCount,
565 int indexCount) {
566
567 int newColorOffset;
568 int newTexCoordOffsets[kMaxTexCoords];
569
570 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
571 newTexCoordOffsets,
572 &newColorOffset);
573 int oldColorOffset;
574 int oldTexCoordOffsets[kMaxTexCoords];
575 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
576 oldTexCoordOffsets,
577 &oldColorOffset);
578 bool indexed = NULL != startIndex;
579
580 int extraVertexOffset;
581 int extraIndexOffset;
582 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
583
584 GrGLenum scalarType;
585 bool texCoordNorm;
586 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
587 scalarType = GrGLTextType;
588 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
589 } else {
590 scalarType = GrGLType;
591 texCoordNorm = false;
592 }
593
594 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
595 *startVertex = 0;
596 if (indexed) {
597 *startIndex += extraIndexOffset;
598 }
599
600 // all the Pointers must be set if any of these are true
601 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
602 vertexOffset != fHWGeometryState.fVertexOffset ||
603 newStride != oldStride;
604
605 // position and tex coord offsets change if above conditions are true
606 // or the type/normalization changed based on text vs nontext type coords.
607 bool posAndTexChange = allOffsetsChange ||
608 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
609 (kTextFormat_VertexLayoutBit &
610 (fHWGeometryState.fVertexLayout ^
611 fGeometrySrc.fVertexLayout)));
612
613 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000614 int idx = GrGLProgram::PositionAttributeIdx();
615 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
616 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000617 fHWGeometryState.fVertexOffset = vertexOffset;
618 }
619
620 for (int t = 0; t < kMaxTexCoords; ++t) {
621 if (newTexCoordOffsets[t] > 0) {
622 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000623 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000624 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000625 GR_GL(EnableVertexAttribArray(idx));
626 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
627 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000628 } else if (posAndTexChange ||
629 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000630 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
631 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000632 }
633 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000634 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000635 }
636 }
637
638 if (newColorOffset > 0) {
639 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000640 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000641 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000642 GR_GL(EnableVertexAttribArray(idx));
643 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000644 true, newStride, colorOffset));
645 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000646 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000647 true, newStride, colorOffset));
648 }
649 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000650 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000651 }
652
653 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
654 fHWGeometryState.fArrayPtrsDirty = false;
655}
656
657void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000658 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000659
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000660 // Must initialize all fields or cache will have false negatives!
661 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
662
663 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
664
665 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
666 // fColorType records how colors are specified for the program. Strip
667 // the bit from the layout to avoid false negatives when searching for an
668 // existing program in the cache.
669 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
670
junov@google.comf93e7172011-03-31 21:26:24 +0000671#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000672 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000673 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000674 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000675#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000676#if GR_GL_NO_CONSTANT_ATTRIBUTES
677 if (!requiresAttributeColors) {
678 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
679 } else
680#endif
681 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000682 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000683 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
684 }
junov@google.comf93e7172011-03-31 21:26:24 +0000685
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000686 desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
687
junov@google.comf93e7172011-03-31 21:26:24 +0000688 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000689 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000690
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000691 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000692
693 if (stage.fEnabled) {
694 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
695 GrAssert(NULL != texture);
696 // we matrix to invert when orientation is TopDown, so make sure
697 // we aren't in that case before flagging as identity.
698 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
699 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
700 } else if (!getSamplerMatrix(s).hasPerspective()) {
701 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
702 } else {
703 stage.fOptFlags = 0;
704 }
705 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000706 case GrSamplerState::kNormal_SampleMode:
707 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
708 break;
709 case GrSamplerState::kRadial_SampleMode:
710 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
711 break;
712 case GrSamplerState::kRadial2_SampleMode:
713 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
714 break;
715 case GrSamplerState::kSweep_SampleMode:
716 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
717 break;
718 default:
719 GrCrash("Unexpected sample mode!");
720 break;
721 }
722
723 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
724 // these both can use a regular texture2D()
725 case GrSamplerState::kNearest_Filter:
726 case GrSamplerState::kBilinear_Filter:
727 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
728 break;
729 // performs 4 texture2D()s
730 case GrSamplerState::k4x4Downsample_Filter:
731 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
732 break;
733 default:
734 GrCrash("Unexpected filter!");
735 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000736 }
737
junov@google.com6acc9b32011-05-16 18:32:07 +0000738 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
739 GrAssert(GrSamplerState::kClamp_WrapMode ==
740 fCurrDrawState.fSamplerStates[s].getWrapX() &&
741 GrSamplerState::kClamp_WrapMode ==
742 fCurrDrawState.fSamplerStates[s].getWrapY());
743 stage.fOptFlags |=
744 GrGLProgram::ProgramDesc::StageDesc::
745 kCustomTextureDomain_OptFlagBit;
746 }
747
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000748 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000749 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
750 } else {
751 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
752 }
753
754 if (fCurrDrawState.fEffects[s]) {
755 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
756 } else {
757 delete fCurrentProgram.fStageEffects[s];
758 fCurrentProgram.fStageEffects[s] = NULL;
759 }
760 } else {
761 stage.fOptFlags = 0;
762 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
763 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
764 fCurrentProgram.fStageEffects[s] = NULL;
765 }
766 }
Scroggo97c88c22011-05-11 14:05:25 +0000767 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
junov@google.comf93e7172011-03-31 21:26:24 +0000768}
769
770