blob: 08845a9258d7aeafdb97484190459bde9d634218 [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"
junov@google.comf93e7172011-03-31 21:26:24 +000018#include "GrGLProgram.h"
19#include "GrGpuGLShaders.h"
20#include "GrGpuVertex.h"
21#include "GrMemory.h"
22#include "GrNoncopyable.h"
23#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000024#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000025
junov@google.comf93e7172011-03-31 21:26:24 +000026#define SKIP_CACHE_CHECK true
27#define GR_UINT32_MAX static_cast<uint32_t>(-1)
28
junov@google.comf93e7172011-03-31 21:26:24 +000029#include "GrTHashCache.h"
30
31class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
32private:
33 class Entry;
34
35#if GR_DEBUG
36 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
37#else
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000038 typedef GrBinHashKey<Entry, 64> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000039#endif
40
41 class Entry : public ::GrNoncopyable {
42 public:
43 Entry() {}
junov@google.comf93e7172011-03-31 21:26:24 +000044 void copyAndTakeOwnership(Entry& entry) {
45 fProgramData.copyAndTakeOwnership(entry.fProgramData);
46 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000047 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000048 }
49
50 public:
51 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
52
53 public:
54 GrGLProgram::CachedData fProgramData;
55 ProgramHashKey fKey;
56 unsigned int fLRUStamp;
57 };
58
59 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
60
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000061 // We may have kMaxEntries+1 shaders in the GL context because
62 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000063 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) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000094 Entry newEntry;
95 while (newEntry.fKey.doPass()) {
96 desc.buildKey(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000097 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000098 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000099 if (NULL == entry) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000100 if (!desc.genProgram(&newEntry.fProgramData)) {
101 return NULL;
102 }
junov@google.comf93e7172011-03-31 21:26:24 +0000103 if (fCount < kMaxEntries) {
104 entry = fEntries + fCount;
105 ++fCount;
106 } else {
107 GrAssert(kMaxEntries == fCount);
108 entry = fEntries;
109 for (int i = 1; i < kMaxEntries; ++i) {
110 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
111 entry = fEntries + i;
112 }
113 }
114 fHashCache.remove(entry->fKey, entry);
115 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
116 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000117 entry->copyAndTakeOwnership(newEntry);
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
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000171#if 0
172 GrPrintf("\nTest Program %d\n-------------\n", t);
173 static const int stop = -1;
174 if (t == stop) {
175 int breakpointhere = 9;
176 }
177#endif
178
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000179 pdesc.fVertexLayout = 0;
180 pdesc.fEmitsPointSize = random.nextF() > .5f;
181 float colorType = random.nextF();
182 if (colorType < 1.f / 3.f) {
183 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
184 } else if (colorType < 2.f / 3.f) {
185 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
186 } else {
187 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
188 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000189
190 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
191 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
192
193 idx = (int)(random.nextF() * (kNumStages+1));
194 pdesc.fFirstCoverageStage = idx;
195
196 pdesc.fUsesEdgeAA = (random.nextF() > .5f);
197
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000198 for (int s = 0; s < kNumStages; ++s) {
199 // enable the stage?
200 if (random.nextF() > .5f) {
201 // use separate tex coords?
202 if (random.nextF() > .5f) {
203 int t = (int)(random.nextF() * kMaxTexCoords);
204 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
205 } else {
206 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
207 }
208 }
209 // use text-formatted verts?
210 if (random.nextF() > .5f) {
211 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
212 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000213 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000214 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
215 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
216 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
217 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
218 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
219 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
220 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
221 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000222 }
223 GrGLProgram::CachedData cachedData;
224 program.genProgram(&cachedData);
225 DeleteProgram(&cachedData);
226 bool again = false;
227 if (again) {
228 program.genProgram(&cachedData);
229 DeleteProgram(&cachedData);
230 }
231 }
232}
233
junov@google.comf93e7172011-03-31 21:26:24 +0000234GrGpuGLShaders::GrGpuGLShaders() {
235
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000236 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000238
239 fProgramData = NULL;
240 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000241
242#if 0
243 ProgramUnitTest();
244#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000245}
246
247GrGpuGLShaders::~GrGpuGLShaders() {
248 delete fProgramCache;
249}
250
251const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000252 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000253
254 if (GrGLProgram::kSetAsAttribute ==
255 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
256 return fHWDrawState.fSamplerStates[stage].getMatrix();
257 } else {
258 return fProgramData->fTextureMatrices[stage];
259 }
junov@google.comf93e7172011-03-31 21:26:24 +0000260}
261
262void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000263 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000264 if (GrGLProgram::kSetAsAttribute ==
265 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
266 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
267 } else {
268 fProgramData->fTextureMatrices[stage] = matrix;
269 }
junov@google.comf93e7172011-03-31 21:26:24 +0000270}
271
272void GrGpuGLShaders::resetContext() {
273 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000274
junov@google.comf93e7172011-03-31 21:26:24 +0000275 fHWGeometryState.fVertexLayout = 0;
276 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000277 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000278 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000279 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000280 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000281 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000282
283 fHWProgramID = 0;
284}
285
286void GrGpuGLShaders::flushViewMatrix() {
287 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000288 GrMatrix m;
289 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000290 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
291 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
292 0, 0, GrMatrix::I()[8]);
293 m.setConcat(m, fCurrDrawState.fViewMatrix);
294
295 // ES doesn't allow you to pass true to the transpose param,
296 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000297 GrGLfloat mt[] = {
298 GrScalarToFloat(m[GrMatrix::kMScaleX]),
299 GrScalarToFloat(m[GrMatrix::kMSkewY]),
300 GrScalarToFloat(m[GrMatrix::kMPersp0]),
301 GrScalarToFloat(m[GrMatrix::kMSkewX]),
302 GrScalarToFloat(m[GrMatrix::kMScaleY]),
303 GrScalarToFloat(m[GrMatrix::kMPersp1]),
304 GrScalarToFloat(m[GrMatrix::kMTransX]),
305 GrScalarToFloat(m[GrMatrix::kMTransY]),
306 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000307 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000308
309 if (GrGLProgram::kSetAsAttribute ==
310 fProgramData->fUniLocations.fViewMatrixUni) {
311 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
312 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
313 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
314 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
315 } else {
316 GrAssert(GrGLProgram::kUnusedUniform !=
317 fProgramData->fUniLocations.fViewMatrixUni);
318 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
319 1, false, mt));
320 }
junov@google.comf93e7172011-03-31 21:26:24 +0000321}
322
junov@google.com6acc9b32011-05-16 18:32:07 +0000323void GrGpuGLShaders::flushTextureDomain(int s) {
324 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
325 if (GrGLProgram::kUnusedUniform != uni) {
326 const GrRect &texDom =
327 fCurrDrawState.fSamplerStates[s].getTextureDomain();
328
329 float values[4] = {
330 GrScalarToFloat(texDom.left()),
331 GrScalarToFloat(texDom.top()),
332 GrScalarToFloat(texDom.right()),
333 GrScalarToFloat(texDom.bottom())
334 };
335
336 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
337 GrGLTexture::Orientation orientation = texture->orientation();
338
339 // vertical flip if necessary
340 if (GrGLTexture::kBottomUp_Orientation == orientation) {
341 values[1] = 1.0f - values[1];
342 values[3] = 1.0f - values[3];
343 }
344
345 values[0] *= SkScalarToFloat(texture->contentScaleX());
346 values[2] *= SkScalarToFloat(texture->contentScaleX());
347 values[1] *= SkScalarToFloat(texture->contentScaleY());
348 values[3] *= SkScalarToFloat(texture->contentScaleY());
349
350 GR_GL(Uniform4fv(uni, 1, values));
351 }
352}
353
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000354void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000355 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
357 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000358 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
360 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000361
bsalomon@google.com91961302011-05-09 18:39:58 +0000362 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000363
bsalomon@google.com91961302011-05-09 18:39:58 +0000364 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000365
bsalomon@google.com91961302011-05-09 18:39:58 +0000366 GrMatrix m = getSamplerMatrix(s);
367 GrSamplerState::SampleMode mode =
368 fCurrDrawState.fSamplerStates[s].getSampleMode();
369 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000370
bsalomon@google.com91961302011-05-09 18:39:58 +0000371 // ES doesn't allow you to pass true to the transpose param,
372 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000373 GrGLfloat mt[] = {
374 GrScalarToFloat(m[GrMatrix::kMScaleX]),
375 GrScalarToFloat(m[GrMatrix::kMSkewY]),
376 GrScalarToFloat(m[GrMatrix::kMPersp0]),
377 GrScalarToFloat(m[GrMatrix::kMSkewX]),
378 GrScalarToFloat(m[GrMatrix::kMScaleY]),
379 GrScalarToFloat(m[GrMatrix::kMPersp1]),
380 GrScalarToFloat(m[GrMatrix::kMTransX]),
381 GrScalarToFloat(m[GrMatrix::kMTransY]),
382 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000383 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000384
bsalomon@google.com91961302011-05-09 18:39:58 +0000385 if (GrGLProgram::kSetAsAttribute ==
386 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
387 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
388 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
389 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
390 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
391 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000392 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000393 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000394 recordHWSamplerMatrix(s, getSamplerMatrix(s));
395 }
396 }
junov@google.comf93e7172011-03-31 21:26:24 +0000397}
398
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000399void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000400
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000401 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
402 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000403 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000404 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
405 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
406 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000407
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000408 GrScalar centerX1 = sampler.getRadial2CenterX1();
409 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000410
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000411 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000412
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000413 float values[6] = {
414 GrScalarToFloat(a),
415 1 / (2.f * values[0]),
416 GrScalarToFloat(centerX1),
417 GrScalarToFloat(radius0),
418 GrScalarToFloat(GrMul(radius0, radius0)),
419 sampler.isRadial2PosRoot() ? 1.f : -1.f
420 };
421 GR_GL(Uniform1fv(uni, 6, values));
422 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
423 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
424 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
425 }
426}
427
428void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000429 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000430 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000431 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
432 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
433 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
434
435 float texelSize[] = {1.f / texture->allocWidth(),
436 1.f / texture->allocHeight()};
437 GR_GL(Uniform2fv(uni, 1, texelSize));
438 }
439 }
junov@google.comf93e7172011-03-31 21:26:24 +0000440}
441
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000442void GrGpuGLShaders::flushEdgeAAData() {
443 const int& uni = fProgramData->fUniLocations.fEdgesUni;
444 if (GrGLProgram::kUnusedUniform != uni) {
445 float edges[18];
446 memcpy(edges, fCurrDrawState.fEdgeAAEdges, sizeof(edges));
447 // Flip the edges in Y
448 float height = fCurrDrawState.fRenderTarget->height();
449 for (int i = 0; i < 6; ++i) {
450 float b = edges[i * 3 + 1];
451 edges[i * 3 + 1] = -b;
452 edges[i * 3 + 2] += b * height;
453 }
454 GR_GL(Uniform3fv(uni, 6, edges));
455 }
456}
457
Scroggo01b87ec2011-05-11 18:05:38 +0000458static const float ONE_OVER_255 = 1.f / 255.f;
459
460#define GR_COLOR_TO_VEC4(color) {\
461 GrColorUnpackR(color) * ONE_OVER_255,\
462 GrColorUnpackG(color) * ONE_OVER_255,\
463 GrColorUnpackB(color) * ONE_OVER_255,\
464 GrColorUnpackA(color) * ONE_OVER_255 \
465}
466
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000467void GrGpuGLShaders::flushColor() {
468 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
469 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
470 // color will be specified per-vertex as an attribute
471 // invalidate the const vertex attrib color
472 fHWDrawState.fColor = GrColor_ILLEGAL;
473 } else {
474 switch (desc.fColorType) {
475 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
476 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
477 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000478 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000479 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000480 fHWDrawState.fColor = fCurrDrawState.fColor;
481 }
482 break;
483 case GrGLProgram::ProgramDesc::kUniform_ColorType:
484 if (fProgramData->fColor != fCurrDrawState.fColor) {
485 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000486 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000487 GrAssert(GrGLProgram::kUnusedUniform !=
488 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000489 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
490 fProgramData->fColor = fCurrDrawState.fColor;
491 }
492 break;
493 case GrGLProgram::ProgramDesc::kNone_ColorType:
494 GrAssert(0xffffffff == fCurrDrawState.fColor);
495 break;
496 default:
497 GrCrash("Unknown color type.");
498 }
499 }
Scroggo97c88c22011-05-11 14:05:25 +0000500 if (fProgramData->fUniLocations.fColorFilterUni
501 != GrGLProgram::kUnusedUniform
502 && fProgramData->fColorFilterColor
503 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000504 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000505 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
506 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
507 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000508}
509
510
junov@google.comf93e7172011-03-31 21:26:24 +0000511bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
512 if (!flushGLStateCommon(type)) {
513 return false;
514 }
515
516 if (fDirtyFlags.fRenderTargetChanged) {
517 // our coords are in pixel space and the GL matrices map to NDC
518 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000519 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000520 // we assume all shader matrices may be wrong after viewport changes
521 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000522 }
523
junov@google.comf93e7172011-03-31 21:26:24 +0000524 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000525 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000526 if (NULL == fProgramData) {
527 GrAssert(!"Failed to create program!");
528 return false;
529 }
junov@google.comf93e7172011-03-31 21:26:24 +0000530
531 if (fHWProgramID != fProgramData->fProgramID) {
532 GR_GL(UseProgram(fProgramData->fProgramID));
533 fHWProgramID = fProgramData->fProgramID;
534 }
535
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000536 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000537
bsalomon@google.com91961302011-05-09 18:39:58 +0000538 GrMatrix* currViewMatrix;
539 if (GrGLProgram::kSetAsAttribute ==
540 fProgramData->fUniLocations.fViewMatrixUni) {
541 currViewMatrix = &fHWDrawState.fViewMatrix;
542 } else {
543 currViewMatrix = &fProgramData->fViewMatrix;
544 }
junov@google.comf93e7172011-03-31 21:26:24 +0000545
bsalomon@google.com91961302011-05-09 18:39:58 +0000546 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000547 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000548 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000549 }
550
551 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000552 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000553
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000554 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000555
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000556 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000557
558 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000559 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000560 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000561 resetDirtyFlags();
562 return true;
563}
564
565void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000566}
567
568void GrGpuGLShaders::setupGeometry(int* startVertex,
569 int* startIndex,
570 int vertexCount,
571 int indexCount) {
572
573 int newColorOffset;
574 int newTexCoordOffsets[kMaxTexCoords];
575
576 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
577 newTexCoordOffsets,
578 &newColorOffset);
579 int oldColorOffset;
580 int oldTexCoordOffsets[kMaxTexCoords];
581 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
582 oldTexCoordOffsets,
583 &oldColorOffset);
584 bool indexed = NULL != startIndex;
585
586 int extraVertexOffset;
587 int extraIndexOffset;
588 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
589
590 GrGLenum scalarType;
591 bool texCoordNorm;
592 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
593 scalarType = GrGLTextType;
594 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
595 } else {
596 scalarType = GrGLType;
597 texCoordNorm = false;
598 }
599
600 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
601 *startVertex = 0;
602 if (indexed) {
603 *startIndex += extraIndexOffset;
604 }
605
606 // all the Pointers must be set if any of these are true
607 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
608 vertexOffset != fHWGeometryState.fVertexOffset ||
609 newStride != oldStride;
610
611 // position and tex coord offsets change if above conditions are true
612 // or the type/normalization changed based on text vs nontext type coords.
613 bool posAndTexChange = allOffsetsChange ||
614 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
615 (kTextFormat_VertexLayoutBit &
616 (fHWGeometryState.fVertexLayout ^
617 fGeometrySrc.fVertexLayout)));
618
619 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000620 int idx = GrGLProgram::PositionAttributeIdx();
621 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
622 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000623 fHWGeometryState.fVertexOffset = vertexOffset;
624 }
625
626 for (int t = 0; t < kMaxTexCoords; ++t) {
627 if (newTexCoordOffsets[t] > 0) {
628 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000629 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000630 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000631 GR_GL(EnableVertexAttribArray(idx));
632 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
633 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000634 } else if (posAndTexChange ||
635 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000636 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
637 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000638 }
639 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000640 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000641 }
642 }
643
644 if (newColorOffset > 0) {
645 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000646 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000647 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000648 GR_GL(EnableVertexAttribArray(idx));
649 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000650 true, newStride, colorOffset));
651 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000652 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000653 true, newStride, colorOffset));
654 }
655 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000656 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000657 }
658
659 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
660 fHWGeometryState.fArrayPtrsDirty = false;
661}
662
663void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000664 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000665
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000666 // Must initialize all fields or cache will have false negatives!
667 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
668
669 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
670
671 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
672 // fColorType records how colors are specified for the program. Strip
673 // the bit from the layout to avoid false negatives when searching for an
674 // existing program in the cache.
675 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
676
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000677 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
678
679 // coverage vs. color only applies when there is a color filter
680 // (currently)
681 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
682 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
683 } else {
684 // use canonical value when this won't affect generated
685 // code to prevent duplicate programs.
686 desc.fFirstCoverageStage = kNumStages;
687 }
688
junov@google.comf93e7172011-03-31 21:26:24 +0000689#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000690 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000691 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000692 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000693#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000694#if GR_GL_NO_CONSTANT_ATTRIBUTES
695 if (!requiresAttributeColors) {
696 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
697 } else
698#endif
699 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000700 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000701 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
702 }
junov@google.comf93e7172011-03-31 21:26:24 +0000703
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000704 desc.fUsesEdgeAA = fCurrDrawState.fFlagBits & kEdgeAA_StateBit;
705
junov@google.comf93e7172011-03-31 21:26:24 +0000706 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000707 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000708
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000709 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000710
711 if (stage.fEnabled) {
712 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
713 GrAssert(NULL != texture);
714 // we matrix to invert when orientation is TopDown, so make sure
715 // we aren't in that case before flagging as identity.
716 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
717 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
718 } else if (!getSamplerMatrix(s).hasPerspective()) {
719 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
720 } else {
721 stage.fOptFlags = 0;
722 }
723 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000724 case GrSamplerState::kNormal_SampleMode:
725 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
726 break;
727 case GrSamplerState::kRadial_SampleMode:
728 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
729 break;
730 case GrSamplerState::kRadial2_SampleMode:
731 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
732 break;
733 case GrSamplerState::kSweep_SampleMode:
734 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
735 break;
736 default:
737 GrCrash("Unexpected sample mode!");
738 break;
739 }
740
741 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
742 // these both can use a regular texture2D()
743 case GrSamplerState::kNearest_Filter:
744 case GrSamplerState::kBilinear_Filter:
745 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
746 break;
747 // performs 4 texture2D()s
748 case GrSamplerState::k4x4Downsample_Filter:
749 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
750 break;
751 default:
752 GrCrash("Unexpected filter!");
753 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000754 }
755
junov@google.com6acc9b32011-05-16 18:32:07 +0000756 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
757 GrAssert(GrSamplerState::kClamp_WrapMode ==
758 fCurrDrawState.fSamplerStates[s].getWrapX() &&
759 GrSamplerState::kClamp_WrapMode ==
760 fCurrDrawState.fSamplerStates[s].getWrapY());
761 stage.fOptFlags |=
762 GrGLProgram::ProgramDesc::StageDesc::
763 kCustomTextureDomain_OptFlagBit;
764 }
765
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000766 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000767 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
768 } else {
769 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
770 }
junov@google.comf93e7172011-03-31 21:26:24 +0000771 } else {
772 stage.fOptFlags = 0;
773 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
774 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000775 }
776 }
junov@google.comf93e7172011-03-31 21:26:24 +0000777}
778
779