blob: bcf29ae56d1a43af0dd6439c70293b13e309a70c [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
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000172#if 0
173 GrPrintf("\nTest Program %d\n-------------\n", t);
174 static const int stop = -1;
175 if (t == stop) {
176 int breakpointhere = 9;
177 }
178#endif
179
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000180 pdesc.fVertexLayout = 0;
181 pdesc.fEmitsPointSize = random.nextF() > .5f;
182 float colorType = random.nextF();
183 if (colorType < 1.f / 3.f) {
184 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
185 } else if (colorType < 2.f / 3.f) {
186 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
187 } else {
188 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
189 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000190
191 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
192 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
193
194 idx = (int)(random.nextF() * (kNumStages+1));
195 pdesc.fFirstCoverageStage = idx;
196
197 pdesc.fUsesEdgeAA = (random.nextF() > .5f);
198
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000199 for (int s = 0; s < kNumStages; ++s) {
200 // enable the stage?
201 if (random.nextF() > .5f) {
202 // use separate tex coords?
203 if (random.nextF() > .5f) {
204 int t = (int)(random.nextF() * kMaxTexCoords);
205 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
206 } else {
207 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
208 }
209 }
210 // use text-formatted verts?
211 if (random.nextF() > .5f) {
212 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
213 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000214 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000215 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
216 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
217 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
218 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
219 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
220 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
221 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
222 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000223 }
224 GrGLProgram::CachedData cachedData;
225 program.genProgram(&cachedData);
226 DeleteProgram(&cachedData);
227 bool again = false;
228 if (again) {
229 program.genProgram(&cachedData);
230 DeleteProgram(&cachedData);
231 }
232 }
233}
234
junov@google.comf93e7172011-03-31 21:26:24 +0000235GrGpuGLShaders::GrGpuGLShaders() {
236
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000237 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000238 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000239
240 fProgramData = NULL;
241 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000242
243#if 0
244 ProgramUnitTest();
245#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000246}
247
248GrGpuGLShaders::~GrGpuGLShaders() {
249 delete fProgramCache;
250}
251
252const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000253 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000254
255 if (GrGLProgram::kSetAsAttribute ==
256 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
257 return fHWDrawState.fSamplerStates[stage].getMatrix();
258 } else {
259 return fProgramData->fTextureMatrices[stage];
260 }
junov@google.comf93e7172011-03-31 21:26:24 +0000261}
262
263void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000264 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000265 if (GrGLProgram::kSetAsAttribute ==
266 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
267 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
268 } else {
269 fProgramData->fTextureMatrices[stage] = matrix;
270 }
junov@google.comf93e7172011-03-31 21:26:24 +0000271}
272
273void GrGpuGLShaders::resetContext() {
274 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000275
junov@google.comf93e7172011-03-31 21:26:24 +0000276 fHWGeometryState.fVertexLayout = 0;
277 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000278 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000279 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000280 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000281 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000282 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000283
284 fHWProgramID = 0;
285}
286
287void GrGpuGLShaders::flushViewMatrix() {
288 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000289 GrMatrix m;
290 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000291 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
292 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
293 0, 0, GrMatrix::I()[8]);
294 m.setConcat(m, fCurrDrawState.fViewMatrix);
295
296 // ES doesn't allow you to pass true to the transpose param,
297 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000298 GrGLfloat mt[] = {
299 GrScalarToFloat(m[GrMatrix::kMScaleX]),
300 GrScalarToFloat(m[GrMatrix::kMSkewY]),
301 GrScalarToFloat(m[GrMatrix::kMPersp0]),
302 GrScalarToFloat(m[GrMatrix::kMSkewX]),
303 GrScalarToFloat(m[GrMatrix::kMScaleY]),
304 GrScalarToFloat(m[GrMatrix::kMPersp1]),
305 GrScalarToFloat(m[GrMatrix::kMTransX]),
306 GrScalarToFloat(m[GrMatrix::kMTransY]),
307 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000308 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000309
310 if (GrGLProgram::kSetAsAttribute ==
311 fProgramData->fUniLocations.fViewMatrixUni) {
312 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
313 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
314 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
315 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
316 } else {
317 GrAssert(GrGLProgram::kUnusedUniform !=
318 fProgramData->fUniLocations.fViewMatrixUni);
319 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
320 1, false, mt));
321 }
junov@google.comf93e7172011-03-31 21:26:24 +0000322}
323
junov@google.com6acc9b32011-05-16 18:32:07 +0000324void GrGpuGLShaders::flushTextureDomain(int s) {
325 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
326 if (GrGLProgram::kUnusedUniform != uni) {
327 const GrRect &texDom =
328 fCurrDrawState.fSamplerStates[s].getTextureDomain();
329
330 float values[4] = {
331 GrScalarToFloat(texDom.left()),
332 GrScalarToFloat(texDom.top()),
333 GrScalarToFloat(texDom.right()),
334 GrScalarToFloat(texDom.bottom())
335 };
336
337 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
338 GrGLTexture::Orientation orientation = texture->orientation();
339
340 // vertical flip if necessary
341 if (GrGLTexture::kBottomUp_Orientation == orientation) {
342 values[1] = 1.0f - values[1];
343 values[3] = 1.0f - values[3];
344 }
345
346 values[0] *= SkScalarToFloat(texture->contentScaleX());
347 values[2] *= SkScalarToFloat(texture->contentScaleX());
348 values[1] *= SkScalarToFloat(texture->contentScaleY());
349 values[3] *= SkScalarToFloat(texture->contentScaleY());
350
351 GR_GL(Uniform4fv(uni, 1, values));
352 }
353}
354
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000355void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000356 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
358 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000359 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000360 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
361 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000362
bsalomon@google.com91961302011-05-09 18:39:58 +0000363 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000364
bsalomon@google.com91961302011-05-09 18:39:58 +0000365 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000366
bsalomon@google.com91961302011-05-09 18:39:58 +0000367 GrMatrix m = getSamplerMatrix(s);
368 GrSamplerState::SampleMode mode =
369 fCurrDrawState.fSamplerStates[s].getSampleMode();
370 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000371
bsalomon@google.com91961302011-05-09 18:39:58 +0000372 // ES doesn't allow you to pass true to the transpose param,
373 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000374 GrGLfloat mt[] = {
375 GrScalarToFloat(m[GrMatrix::kMScaleX]),
376 GrScalarToFloat(m[GrMatrix::kMSkewY]),
377 GrScalarToFloat(m[GrMatrix::kMPersp0]),
378 GrScalarToFloat(m[GrMatrix::kMSkewX]),
379 GrScalarToFloat(m[GrMatrix::kMScaleY]),
380 GrScalarToFloat(m[GrMatrix::kMPersp1]),
381 GrScalarToFloat(m[GrMatrix::kMTransX]),
382 GrScalarToFloat(m[GrMatrix::kMTransY]),
383 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000384 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000385
bsalomon@google.com91961302011-05-09 18:39:58 +0000386 if (GrGLProgram::kSetAsAttribute ==
387 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
388 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
389 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
390 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
391 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
392 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000393 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000394 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000395 recordHWSamplerMatrix(s, getSamplerMatrix(s));
396 }
397 }
junov@google.comf93e7172011-03-31 21:26:24 +0000398}
399
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000400void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000401
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000402 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
403 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000404 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000405 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
406 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
407 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000408
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000409 GrScalar centerX1 = sampler.getRadial2CenterX1();
410 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000411
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000412 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000413
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000414 float values[6] = {
415 GrScalarToFloat(a),
416 1 / (2.f * values[0]),
417 GrScalarToFloat(centerX1),
418 GrScalarToFloat(radius0),
419 GrScalarToFloat(GrMul(radius0, radius0)),
420 sampler.isRadial2PosRoot() ? 1.f : -1.f
421 };
422 GR_GL(Uniform1fv(uni, 6, values));
423 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
424 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
425 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
426 }
427}
428
429void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000430 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000431 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000432 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
433 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
434 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
435
436 float texelSize[] = {1.f / texture->allocWidth(),
437 1.f / texture->allocHeight()};
438 GR_GL(Uniform2fv(uni, 1, texelSize));
439 }
440 }
junov@google.comf93e7172011-03-31 21:26:24 +0000441}
442
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000443void GrGpuGLShaders::flushEdgeAAData() {
444 const int& uni = fProgramData->fUniLocations.fEdgesUni;
445 if (GrGLProgram::kUnusedUniform != uni) {
446 float edges[18];
447 memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
448 // Flip the edges in Y
449 float height = fCurrDrawState.fRenderTarget->height();
450 for (int i = 0; i < 6; ++i) {
451 float b = edges[i * 3 + 1];
452 edges[i * 3 + 1] = -b;
453 edges[i * 3 + 2] += b * height;
454 }
455 GR_GL(Uniform3fv(uni, 6, edges));
456 }
457}
458
Scroggo01b87ec2011-05-11 18:05:38 +0000459static const float ONE_OVER_255 = 1.f / 255.f;
460
461#define GR_COLOR_TO_VEC4(color) {\
462 GrColorUnpackR(color) * ONE_OVER_255,\
463 GrColorUnpackG(color) * ONE_OVER_255,\
464 GrColorUnpackB(color) * ONE_OVER_255,\
465 GrColorUnpackA(color) * ONE_OVER_255 \
466}
467
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000468void GrGpuGLShaders::flushColor() {
469 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
470 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
471 // color will be specified per-vertex as an attribute
472 // invalidate the const vertex attrib color
473 fHWDrawState.fColor = GrColor_ILLEGAL;
474 } else {
475 switch (desc.fColorType) {
476 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
477 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
478 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000479 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000480 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000481 fHWDrawState.fColor = fCurrDrawState.fColor;
482 }
483 break;
484 case GrGLProgram::ProgramDesc::kUniform_ColorType:
485 if (fProgramData->fColor != fCurrDrawState.fColor) {
486 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000487 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000488 GrAssert(GrGLProgram::kUnusedUniform !=
489 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000490 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
491 fProgramData->fColor = fCurrDrawState.fColor;
492 }
493 break;
494 case GrGLProgram::ProgramDesc::kNone_ColorType:
495 GrAssert(0xffffffff == fCurrDrawState.fColor);
496 break;
497 default:
498 GrCrash("Unknown color type.");
499 }
500 }
Scroggo97c88c22011-05-11 14:05:25 +0000501 if (fProgramData->fUniLocations.fColorFilterUni
502 != GrGLProgram::kUnusedUniform
503 && fProgramData->fColorFilterColor
504 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000505 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000506 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
507 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
508 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000509}
510
511
junov@google.comf93e7172011-03-31 21:26:24 +0000512bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
513 if (!flushGLStateCommon(type)) {
514 return false;
515 }
516
517 if (fDirtyFlags.fRenderTargetChanged) {
518 // our coords are in pixel space and the GL matrices map to NDC
519 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000520 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000521 // we assume all shader matrices may be wrong after viewport changes
522 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000523 }
524
junov@google.comf93e7172011-03-31 21:26:24 +0000525 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000526 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000527 if (NULL == fProgramData) {
528 GrAssert(!"Failed to create program!");
529 return false;
530 }
junov@google.comf93e7172011-03-31 21:26:24 +0000531
532 if (fHWProgramID != fProgramData->fProgramID) {
533 GR_GL(UseProgram(fProgramData->fProgramID));
534 fHWProgramID = fProgramData->fProgramID;
535 }
536
537 if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
538 return false;
539 }
540
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000541 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000542
bsalomon@google.com91961302011-05-09 18:39:58 +0000543 GrMatrix* currViewMatrix;
544 if (GrGLProgram::kSetAsAttribute ==
545 fProgramData->fUniLocations.fViewMatrixUni) {
546 currViewMatrix = &fHWDrawState.fViewMatrix;
547 } else {
548 currViewMatrix = &fProgramData->fViewMatrix;
549 }
junov@google.comf93e7172011-03-31 21:26:24 +0000550
bsalomon@google.com91961302011-05-09 18:39:58 +0000551 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000552 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000553 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000554 }
555
556 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000557 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000558
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000559 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000560
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000561 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000562
563 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000564 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000565 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000566 resetDirtyFlags();
567 return true;
568}
569
570void GrGpuGLShaders::postDraw() {
571 fCurrentProgram.doGLPost();
572}
573
574void GrGpuGLShaders::setupGeometry(int* startVertex,
575 int* startIndex,
576 int vertexCount,
577 int indexCount) {
578
579 int newColorOffset;
580 int newTexCoordOffsets[kMaxTexCoords];
581
582 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
583 newTexCoordOffsets,
584 &newColorOffset);
585 int oldColorOffset;
586 int oldTexCoordOffsets[kMaxTexCoords];
587 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
588 oldTexCoordOffsets,
589 &oldColorOffset);
590 bool indexed = NULL != startIndex;
591
592 int extraVertexOffset;
593 int extraIndexOffset;
594 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
595
596 GrGLenum scalarType;
597 bool texCoordNorm;
598 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
599 scalarType = GrGLTextType;
600 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
601 } else {
602 scalarType = GrGLType;
603 texCoordNorm = false;
604 }
605
606 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
607 *startVertex = 0;
608 if (indexed) {
609 *startIndex += extraIndexOffset;
610 }
611
612 // all the Pointers must be set if any of these are true
613 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
614 vertexOffset != fHWGeometryState.fVertexOffset ||
615 newStride != oldStride;
616
617 // position and tex coord offsets change if above conditions are true
618 // or the type/normalization changed based on text vs nontext type coords.
619 bool posAndTexChange = allOffsetsChange ||
620 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
621 (kTextFormat_VertexLayoutBit &
622 (fHWGeometryState.fVertexLayout ^
623 fGeometrySrc.fVertexLayout)));
624
625 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000626 int idx = GrGLProgram::PositionAttributeIdx();
627 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
628 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000629 fHWGeometryState.fVertexOffset = vertexOffset;
630 }
631
632 for (int t = 0; t < kMaxTexCoords; ++t) {
633 if (newTexCoordOffsets[t] > 0) {
634 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000635 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000636 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000637 GR_GL(EnableVertexAttribArray(idx));
638 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
639 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000640 } else if (posAndTexChange ||
641 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000642 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
643 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000644 }
645 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000646 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000647 }
648 }
649
650 if (newColorOffset > 0) {
651 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000652 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000653 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000654 GR_GL(EnableVertexAttribArray(idx));
655 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000656 true, newStride, colorOffset));
657 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000658 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000659 true, newStride, colorOffset));
660 }
661 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000662 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000663 }
664
665 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
666 fHWGeometryState.fArrayPtrsDirty = false;
667}
668
669void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000670 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000671
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000672 // Must initialize all fields or cache will have false negatives!
673 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
674
675 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
676
677 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
678 // fColorType records how colors are specified for the program. Strip
679 // the bit from the layout to avoid false negatives when searching for an
680 // existing program in the cache.
681 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
682
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000683 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
684
685 // coverage vs. color only applies when there is a color filter
686 // (currently)
687 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
688 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
689 } else {
690 // use canonical value when this won't affect generated
691 // code to prevent duplicate programs.
692 desc.fFirstCoverageStage = kNumStages;
693 }
694
junov@google.comf93e7172011-03-31 21:26:24 +0000695#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000696 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000697 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000698 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000699#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000700#if GR_GL_NO_CONSTANT_ATTRIBUTES
701 if (!requiresAttributeColors) {
702 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
703 } else
704#endif
705 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000706 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000707 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
708 }
junov@google.comf93e7172011-03-31 21:26:24 +0000709
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000710 desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
711
junov@google.comf93e7172011-03-31 21:26:24 +0000712 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000713 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000714
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000715 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000716
717 if (stage.fEnabled) {
718 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
719 GrAssert(NULL != texture);
720 // we matrix to invert when orientation is TopDown, so make sure
721 // we aren't in that case before flagging as identity.
722 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
723 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
724 } else if (!getSamplerMatrix(s).hasPerspective()) {
725 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
726 } else {
727 stage.fOptFlags = 0;
728 }
729 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000730 case GrSamplerState::kNormal_SampleMode:
731 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
732 break;
733 case GrSamplerState::kRadial_SampleMode:
734 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
735 break;
736 case GrSamplerState::kRadial2_SampleMode:
737 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
738 break;
739 case GrSamplerState::kSweep_SampleMode:
740 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
741 break;
742 default:
743 GrCrash("Unexpected sample mode!");
744 break;
745 }
746
747 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
748 // these both can use a regular texture2D()
749 case GrSamplerState::kNearest_Filter:
750 case GrSamplerState::kBilinear_Filter:
751 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
752 break;
753 // performs 4 texture2D()s
754 case GrSamplerState::k4x4Downsample_Filter:
755 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
756 break;
757 default:
758 GrCrash("Unexpected filter!");
759 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000760 }
761
junov@google.com6acc9b32011-05-16 18:32:07 +0000762 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
763 GrAssert(GrSamplerState::kClamp_WrapMode ==
764 fCurrDrawState.fSamplerStates[s].getWrapX() &&
765 GrSamplerState::kClamp_WrapMode ==
766 fCurrDrawState.fSamplerStates[s].getWrapY());
767 stage.fOptFlags |=
768 GrGLProgram::ProgramDesc::StageDesc::
769 kCustomTextureDomain_OptFlagBit;
770 }
771
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000772 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000773 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
774 } else {
775 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
776 }
777
778 if (fCurrDrawState.fEffects[s]) {
779 fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
780 } else {
781 delete fCurrentProgram.fStageEffects[s];
782 fCurrentProgram.fStageEffects[s] = NULL;
783 }
784 } else {
785 stage.fOptFlags = 0;
786 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
787 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
788 fCurrentProgram.fStageEffects[s] = NULL;
789 }
790 }
junov@google.comf93e7172011-03-31 21:26:24 +0000791}
792
793