blob: bd57291e90fc1ca76640bc7e6066a9a7c350d103 [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
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000196 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000197
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000198 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000199 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000200 (GrGLProgram::ProgramDesc::DualSrcOutput)
201 (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
202 } else {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000203 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000204 GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
205 }
206
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000207 for (int s = 0; s < kNumStages; ++s) {
208 // enable the stage?
209 if (random.nextF() > .5f) {
210 // use separate tex coords?
211 if (random.nextF() > .5f) {
212 int t = (int)(random.nextF() * kMaxTexCoords);
213 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
214 } else {
215 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
216 }
217 }
218 // use text-formatted verts?
219 if (random.nextF() > .5f) {
220 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
221 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000222 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
223 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
224 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
225 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
226 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
227 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
228 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
229 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
tomhudson@google.com0d831722011-06-02 15:37:14 +0000230 pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000231 }
232 GrGLProgram::CachedData cachedData;
233 program.genProgram(&cachedData);
234 DeleteProgram(&cachedData);
235 bool again = false;
236 if (again) {
237 program.genProgram(&cachedData);
238 DeleteProgram(&cachedData);
239 }
240 }
241}
242
junov@google.comf93e7172011-03-31 21:26:24 +0000243GrGpuGLShaders::GrGpuGLShaders() {
244
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000245 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000246 int major, minor;
247 gl_version(&major, &minor);
248
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000249 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000250 if (GR_GL_SUPPORT_DESKTOP) {
251 fDualSourceBlendingSupport =
252 major > 3 ||(3 == major && 3 <= minor) ||
253 has_gl_extension("GL_ARB_blend_func_extended");
254 } else {
255 fDualSourceBlendingSupport = false;
256 }
junov@google.comf93e7172011-03-31 21:26:24 +0000257
258 fProgramData = NULL;
259 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000260
261#if 0
262 ProgramUnitTest();
263#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000264}
265
266GrGpuGLShaders::~GrGpuGLShaders() {
267 delete fProgramCache;
268}
269
270const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000271 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000272
273 if (GrGLProgram::kSetAsAttribute ==
274 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
275 return fHWDrawState.fSamplerStates[stage].getMatrix();
276 } else {
277 return fProgramData->fTextureMatrices[stage];
278 }
junov@google.comf93e7172011-03-31 21:26:24 +0000279}
280
281void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000282 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000283 if (GrGLProgram::kSetAsAttribute ==
284 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
285 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
286 } else {
287 fProgramData->fTextureMatrices[stage] = matrix;
288 }
junov@google.comf93e7172011-03-31 21:26:24 +0000289}
290
291void GrGpuGLShaders::resetContext() {
292 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000293
junov@google.comf93e7172011-03-31 21:26:24 +0000294 fHWGeometryState.fVertexLayout = 0;
295 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000296 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000297 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000298 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000299 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000300 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000301
302 fHWProgramID = 0;
303}
304
305void GrGpuGLShaders::flushViewMatrix() {
306 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000307 GrMatrix m;
308 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000309 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
310 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
311 0, 0, GrMatrix::I()[8]);
312 m.setConcat(m, fCurrDrawState.fViewMatrix);
313
314 // ES doesn't allow you to pass true to the transpose param,
315 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000316 GrGLfloat mt[] = {
317 GrScalarToFloat(m[GrMatrix::kMScaleX]),
318 GrScalarToFloat(m[GrMatrix::kMSkewY]),
319 GrScalarToFloat(m[GrMatrix::kMPersp0]),
320 GrScalarToFloat(m[GrMatrix::kMSkewX]),
321 GrScalarToFloat(m[GrMatrix::kMScaleY]),
322 GrScalarToFloat(m[GrMatrix::kMPersp1]),
323 GrScalarToFloat(m[GrMatrix::kMTransX]),
324 GrScalarToFloat(m[GrMatrix::kMTransY]),
325 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000326 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000327
328 if (GrGLProgram::kSetAsAttribute ==
329 fProgramData->fUniLocations.fViewMatrixUni) {
330 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
331 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
332 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
333 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
334 } else {
335 GrAssert(GrGLProgram::kUnusedUniform !=
336 fProgramData->fUniLocations.fViewMatrixUni);
337 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
338 1, false, mt));
339 }
junov@google.comf93e7172011-03-31 21:26:24 +0000340}
341
junov@google.com6acc9b32011-05-16 18:32:07 +0000342void GrGpuGLShaders::flushTextureDomain(int s) {
343 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
344 if (GrGLProgram::kUnusedUniform != uni) {
345 const GrRect &texDom =
346 fCurrDrawState.fSamplerStates[s].getTextureDomain();
347
junov@google.com2f839402011-05-24 15:13:01 +0000348 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
349 fProgramData->fTextureDomain[s] != texDom)
junov@google.com6acc9b32011-05-16 18:32:07 +0000350
junov@google.com2f839402011-05-24 15:13:01 +0000351 {
352 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000353
junov@google.com2f839402011-05-24 15:13:01 +0000354 float values[4] = {
355 GrScalarToFloat(texDom.left()),
356 GrScalarToFloat(texDom.top()),
357 GrScalarToFloat(texDom.right()),
358 GrScalarToFloat(texDom.bottom())
359 };
360
361 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
362 GrGLTexture::Orientation orientation = texture->orientation();
363
364 // vertical flip if necessary
365 if (GrGLTexture::kBottomUp_Orientation == orientation) {
366 values[1] = 1.0f - values[1];
367 values[3] = 1.0f - values[3];
368 }
369
370 values[0] *= SkScalarToFloat(texture->contentScaleX());
371 values[2] *= SkScalarToFloat(texture->contentScaleX());
372 values[1] *= SkScalarToFloat(texture->contentScaleY());
373 values[3] *= SkScalarToFloat(texture->contentScaleY());
374
375 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000376 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000377 }
378}
379
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000380void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000381 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000382 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
383 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000384 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000385 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
386 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000387
bsalomon@google.com91961302011-05-09 18:39:58 +0000388 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000389
bsalomon@google.com91961302011-05-09 18:39:58 +0000390 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000391
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 GrMatrix m = getSamplerMatrix(s);
393 GrSamplerState::SampleMode mode =
394 fCurrDrawState.fSamplerStates[s].getSampleMode();
395 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000396
bsalomon@google.com91961302011-05-09 18:39:58 +0000397 // ES doesn't allow you to pass true to the transpose param,
398 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000399 GrGLfloat mt[] = {
400 GrScalarToFloat(m[GrMatrix::kMScaleX]),
401 GrScalarToFloat(m[GrMatrix::kMSkewY]),
402 GrScalarToFloat(m[GrMatrix::kMPersp0]),
403 GrScalarToFloat(m[GrMatrix::kMSkewX]),
404 GrScalarToFloat(m[GrMatrix::kMScaleY]),
405 GrScalarToFloat(m[GrMatrix::kMPersp1]),
406 GrScalarToFloat(m[GrMatrix::kMTransX]),
407 GrScalarToFloat(m[GrMatrix::kMTransY]),
408 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000409 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000410
bsalomon@google.com91961302011-05-09 18:39:58 +0000411 if (GrGLProgram::kSetAsAttribute ==
412 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
413 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
414 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
415 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
416 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
417 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000418 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000419 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000420 recordHWSamplerMatrix(s, getSamplerMatrix(s));
421 }
422 }
junov@google.comf93e7172011-03-31 21:26:24 +0000423}
424
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000425void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000426
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
428 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000429 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000430 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
431 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
432 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 GrScalar centerX1 = sampler.getRadial2CenterX1();
435 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000436
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000437 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000438
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 float values[6] = {
440 GrScalarToFloat(a),
441 1 / (2.f * values[0]),
442 GrScalarToFloat(centerX1),
443 GrScalarToFloat(radius0),
444 GrScalarToFloat(GrMul(radius0, radius0)),
445 sampler.isRadial2PosRoot() ? 1.f : -1.f
446 };
447 GR_GL(Uniform1fv(uni, 6, values));
448 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
449 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
450 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
451 }
452}
453
454void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000455 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000456 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000457 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
458 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
459 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
460
461 float texelSize[] = {1.f / texture->allocWidth(),
462 1.f / texture->allocHeight()};
463 GR_GL(Uniform2fv(uni, 1, texelSize));
464 }
465 }
junov@google.comf93e7172011-03-31 21:26:24 +0000466}
467
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000468void GrGpuGLShaders::flushEdgeAAData() {
469 const int& uni = fProgramData->fUniLocations.fEdgesUni;
470 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000471 int count = fCurrDrawState.fEdgeAANumEdges;
472 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000473 // Flip the edges in Y
474 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000475 for (int i = 0; i < count; ++i) {
476 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
477 float b = edges[i].fY;
478 edges[i].fY = -b;
479 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000480 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000481 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000482 }
483}
484
Scroggo01b87ec2011-05-11 18:05:38 +0000485static const float ONE_OVER_255 = 1.f / 255.f;
486
487#define GR_COLOR_TO_VEC4(color) {\
488 GrColorUnpackR(color) * ONE_OVER_255,\
489 GrColorUnpackG(color) * ONE_OVER_255,\
490 GrColorUnpackB(color) * ONE_OVER_255,\
491 GrColorUnpackA(color) * ONE_OVER_255 \
492}
493
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000494void GrGpuGLShaders::flushColor() {
495 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
496 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
497 // color will be specified per-vertex as an attribute
498 // invalidate the const vertex attrib color
499 fHWDrawState.fColor = GrColor_ILLEGAL;
500 } else {
501 switch (desc.fColorType) {
502 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
503 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
504 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000505 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000506 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000507 fHWDrawState.fColor = fCurrDrawState.fColor;
508 }
509 break;
510 case GrGLProgram::ProgramDesc::kUniform_ColorType:
511 if (fProgramData->fColor != fCurrDrawState.fColor) {
512 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000513 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000514 GrAssert(GrGLProgram::kUnusedUniform !=
515 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000516 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
517 fProgramData->fColor = fCurrDrawState.fColor;
518 }
519 break;
520 case GrGLProgram::ProgramDesc::kNone_ColorType:
521 GrAssert(0xffffffff == fCurrDrawState.fColor);
522 break;
523 default:
524 GrCrash("Unknown color type.");
525 }
526 }
Scroggo97c88c22011-05-11 14:05:25 +0000527 if (fProgramData->fUniLocations.fColorFilterUni
528 != GrGLProgram::kUnusedUniform
529 && fProgramData->fColorFilterColor
530 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000531 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000532 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
533 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
534 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000535}
536
537
junov@google.comf93e7172011-03-31 21:26:24 +0000538bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
539 if (!flushGLStateCommon(type)) {
540 return false;
541 }
542
543 if (fDirtyFlags.fRenderTargetChanged) {
544 // our coords are in pixel space and the GL matrices map to NDC
545 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000546 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000547 // we assume all shader matrices may be wrong after viewport changes
548 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000549 }
550
junov@google.comf93e7172011-03-31 21:26:24 +0000551 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000552 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000553 if (NULL == fProgramData) {
554 GrAssert(!"Failed to create program!");
555 return false;
556 }
junov@google.comf93e7172011-03-31 21:26:24 +0000557
558 if (fHWProgramID != fProgramData->fProgramID) {
559 GR_GL(UseProgram(fProgramData->fProgramID));
560 fHWProgramID = fProgramData->fProgramID;
561 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000562 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
563 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
564
565 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
566 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000567
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000568 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000569
bsalomon@google.com91961302011-05-09 18:39:58 +0000570 GrMatrix* currViewMatrix;
571 if (GrGLProgram::kSetAsAttribute ==
572 fProgramData->fUniLocations.fViewMatrixUni) {
573 currViewMatrix = &fHWDrawState.fViewMatrix;
574 } else {
575 currViewMatrix = &fProgramData->fViewMatrix;
576 }
junov@google.comf93e7172011-03-31 21:26:24 +0000577
bsalomon@google.com91961302011-05-09 18:39:58 +0000578 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000579 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000581 }
582
583 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000584 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000585
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000586 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000587
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000588 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000589
590 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000591 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000592 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000593 resetDirtyFlags();
594 return true;
595}
596
597void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000598}
599
600void GrGpuGLShaders::setupGeometry(int* startVertex,
601 int* startIndex,
602 int vertexCount,
603 int indexCount) {
604
605 int newColorOffset;
606 int newTexCoordOffsets[kMaxTexCoords];
607
608 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
609 newTexCoordOffsets,
610 &newColorOffset);
611 int oldColorOffset;
612 int oldTexCoordOffsets[kMaxTexCoords];
613 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
614 oldTexCoordOffsets,
615 &oldColorOffset);
616 bool indexed = NULL != startIndex;
617
618 int extraVertexOffset;
619 int extraIndexOffset;
620 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
621
622 GrGLenum scalarType;
623 bool texCoordNorm;
624 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
625 scalarType = GrGLTextType;
626 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
627 } else {
628 scalarType = GrGLType;
629 texCoordNorm = false;
630 }
631
632 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
633 *startVertex = 0;
634 if (indexed) {
635 *startIndex += extraIndexOffset;
636 }
637
638 // all the Pointers must be set if any of these are true
639 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
640 vertexOffset != fHWGeometryState.fVertexOffset ||
641 newStride != oldStride;
642
643 // position and tex coord offsets change if above conditions are true
644 // or the type/normalization changed based on text vs nontext type coords.
645 bool posAndTexChange = allOffsetsChange ||
646 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
647 (kTextFormat_VertexLayoutBit &
648 (fHWGeometryState.fVertexLayout ^
649 fGeometrySrc.fVertexLayout)));
650
651 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000652 int idx = GrGLProgram::PositionAttributeIdx();
653 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
654 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000655 fHWGeometryState.fVertexOffset = vertexOffset;
656 }
657
658 for (int t = 0; t < kMaxTexCoords; ++t) {
659 if (newTexCoordOffsets[t] > 0) {
660 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000661 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000662 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000663 GR_GL(EnableVertexAttribArray(idx));
664 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
665 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000666 } else if (posAndTexChange ||
667 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000668 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
669 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000670 }
671 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000672 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000673 }
674 }
675
676 if (newColorOffset > 0) {
677 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000678 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000679 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000680 GR_GL(EnableVertexAttribArray(idx));
681 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000682 true, newStride, colorOffset));
683 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000684 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000685 true, newStride, colorOffset));
686 }
687 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000688 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000689 }
690
691 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
692 fHWGeometryState.fArrayPtrsDirty = false;
693}
694
695void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000696 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000697
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000698 // Must initialize all fields or cache will have false negatives!
699 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
700
701 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
702
703 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
704 // fColorType records how colors are specified for the program. Strip
705 // the bit from the layout to avoid false negatives when searching for an
706 // existing program in the cache.
707 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
708
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000709 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
710
junov@google.comf93e7172011-03-31 21:26:24 +0000711#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000712 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000713 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000714 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000715#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000716#if GR_GL_NO_CONSTANT_ATTRIBUTES
717 if (!requiresAttributeColors) {
718 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
719 } else
720#endif
721 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000722 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000723 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
724 }
junov@google.comf93e7172011-03-31 21:26:24 +0000725
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000726 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000727
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000728 int lastEnabledStage = -1;
729
junov@google.comf93e7172011-03-31 21:26:24 +0000730 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000731 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000732
tomhudson@google.com0d831722011-06-02 15:37:14 +0000733 stage.fOptFlags = 0;
734 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000735
tomhudson@google.com0d831722011-06-02 15:37:14 +0000736 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000737 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000738 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
739 GrAssert(NULL != texture);
740 // we matrix to invert when orientation is TopDown, so make sure
741 // we aren't in that case before flagging as identity.
742 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000743 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000744 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000745 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000746 }
747 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 case GrSamplerState::kNormal_SampleMode:
749 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
750 break;
751 case GrSamplerState::kRadial_SampleMode:
752 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
753 break;
754 case GrSamplerState::kRadial2_SampleMode:
755 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
756 break;
757 case GrSamplerState::kSweep_SampleMode:
758 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
759 break;
760 default:
761 GrCrash("Unexpected sample mode!");
762 break;
763 }
764
765 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
766 // these both can use a regular texture2D()
767 case GrSamplerState::kNearest_Filter:
768 case GrSamplerState::kBilinear_Filter:
769 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
770 break;
771 // performs 4 texture2D()s
772 case GrSamplerState::k4x4Downsample_Filter:
773 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
774 break;
775 default:
776 GrCrash("Unexpected filter!");
777 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000778 }
779
junov@google.com6acc9b32011-05-16 18:32:07 +0000780 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000781 GrAssert(GrSamplerState::kClamp_WrapMode ==
782 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000783 GrSamplerState::kClamp_WrapMode ==
784 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000785 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000786 GrGLProgram::ProgramDesc::StageDesc::
787 kCustomTextureDomain_OptFlagBit;
788 }
789
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000790 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000791 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
792 } else {
793 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
794 }
junov@google.comf93e7172011-03-31 21:26:24 +0000795 } else {
796 stage.fOptFlags = 0;
797 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
798 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000799 }
800 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000801
802 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
803 // use canonical value when coverage/color distinction won't affect
804 // generated code to prevent duplicate programs.
805 desc.fFirstCoverageStage = kNumStages;
806 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
807 // color filter is applied between color/coverage computation
808 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
809 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
810 }
811
812 // We could consider cases where the final color is solid (0xff alpha)
813 // and the dst coeff can correctly be set to a non-dualsrc gl value.
814 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
815 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
816 // kOne).
817 if (fDualSourceBlendingSupport) {
818 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
819 // write the coverage value to second color
820 desc.fDualSrcOutput =
821 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
822 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
823 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
824 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
825 // cover
826 desc.fDualSrcOutput =
827 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
828 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
829 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
830 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
831 // cover
832 desc.fDualSrcOutput =
833 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
834 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
835 }
836 }
837 }
junov@google.comf93e7172011-03-31 21:26:24 +0000838}