blob: 50be67f0bee19fc7b944445b130a73a7c19a5296 [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) {
twiz@google.com76b82742011-06-02 20:30:02 +0000345 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000346 fCurrDrawState.fSamplerStates[s].getTextureDomain();
347
twiz@google.com76b82742011-06-02 20:30:02 +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 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000352
junov@google.com2f839402011-05-24 15:13:01 +0000353 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000354 GrScalarToFloat(texDom.left()),
355 GrScalarToFloat(texDom.top()),
356 GrScalarToFloat(texDom.right()),
357 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000358 };
359
360 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
361 GrGLTexture::Orientation orientation = texture->orientation();
362
363 // vertical flip if necessary
364 if (GrGLTexture::kBottomUp_Orientation == orientation) {
365 values[1] = 1.0f - values[1];
366 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000367 // The top and bottom were just flipped, so correct the ordering
368 // of elements so that values = (l, t, r, b).
369 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000370 }
371
372 values[0] *= SkScalarToFloat(texture->contentScaleX());
373 values[2] *= SkScalarToFloat(texture->contentScaleX());
374 values[1] *= SkScalarToFloat(texture->contentScaleY());
375 values[3] *= SkScalarToFloat(texture->contentScaleY());
376
377 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000378 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000379 }
380}
381
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000382void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000383 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000384 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
385 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000386 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
388 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000389
bsalomon@google.com91961302011-05-09 18:39:58 +0000390 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000391
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000393
bsalomon@google.com91961302011-05-09 18:39:58 +0000394 GrMatrix m = getSamplerMatrix(s);
395 GrSamplerState::SampleMode mode =
396 fCurrDrawState.fSamplerStates[s].getSampleMode();
397 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000398
bsalomon@google.com91961302011-05-09 18:39:58 +0000399 // ES doesn't allow you to pass true to the transpose param,
400 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000401 GrGLfloat mt[] = {
402 GrScalarToFloat(m[GrMatrix::kMScaleX]),
403 GrScalarToFloat(m[GrMatrix::kMSkewY]),
404 GrScalarToFloat(m[GrMatrix::kMPersp0]),
405 GrScalarToFloat(m[GrMatrix::kMSkewX]),
406 GrScalarToFloat(m[GrMatrix::kMScaleY]),
407 GrScalarToFloat(m[GrMatrix::kMPersp1]),
408 GrScalarToFloat(m[GrMatrix::kMTransX]),
409 GrScalarToFloat(m[GrMatrix::kMTransY]),
410 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000411 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000412
bsalomon@google.com91961302011-05-09 18:39:58 +0000413 if (GrGLProgram::kSetAsAttribute ==
414 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
415 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
416 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
417 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
418 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
419 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000420 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000421 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000422 recordHWSamplerMatrix(s, getSamplerMatrix(s));
423 }
424 }
junov@google.comf93e7172011-03-31 21:26:24 +0000425}
426
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000428
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000429 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
430 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000431 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000432 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
433 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
434 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000435
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000436 GrScalar centerX1 = sampler.getRadial2CenterX1();
437 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000438
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000440
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 float values[6] = {
442 GrScalarToFloat(a),
443 1 / (2.f * values[0]),
444 GrScalarToFloat(centerX1),
445 GrScalarToFloat(radius0),
446 GrScalarToFloat(GrMul(radius0, radius0)),
447 sampler.isRadial2PosRoot() ? 1.f : -1.f
448 };
449 GR_GL(Uniform1fv(uni, 6, values));
450 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
451 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
452 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
453 }
454}
455
456void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000457 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000458 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000459 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
460 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
461 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
462
463 float texelSize[] = {1.f / texture->allocWidth(),
464 1.f / texture->allocHeight()};
465 GR_GL(Uniform2fv(uni, 1, texelSize));
466 }
467 }
junov@google.comf93e7172011-03-31 21:26:24 +0000468}
469
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000470void GrGpuGLShaders::flushEdgeAAData() {
471 const int& uni = fProgramData->fUniLocations.fEdgesUni;
472 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000473 int count = fCurrDrawState.fEdgeAANumEdges;
474 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000475 // Flip the edges in Y
476 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000477 for (int i = 0; i < count; ++i) {
478 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
479 float b = edges[i].fY;
480 edges[i].fY = -b;
481 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000482 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000483 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000484 }
485}
486
Scroggo01b87ec2011-05-11 18:05:38 +0000487static const float ONE_OVER_255 = 1.f / 255.f;
488
489#define GR_COLOR_TO_VEC4(color) {\
490 GrColorUnpackR(color) * ONE_OVER_255,\
491 GrColorUnpackG(color) * ONE_OVER_255,\
492 GrColorUnpackB(color) * ONE_OVER_255,\
493 GrColorUnpackA(color) * ONE_OVER_255 \
494}
495
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000496void GrGpuGLShaders::flushColor() {
497 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
498 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
499 // color will be specified per-vertex as an attribute
500 // invalidate the const vertex attrib color
501 fHWDrawState.fColor = GrColor_ILLEGAL;
502 } else {
503 switch (desc.fColorType) {
504 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
505 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
506 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000507 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000508 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000509 fHWDrawState.fColor = fCurrDrawState.fColor;
510 }
511 break;
512 case GrGLProgram::ProgramDesc::kUniform_ColorType:
513 if (fProgramData->fColor != fCurrDrawState.fColor) {
514 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000515 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000516 GrAssert(GrGLProgram::kUnusedUniform !=
517 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000518 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
519 fProgramData->fColor = fCurrDrawState.fColor;
520 }
521 break;
522 case GrGLProgram::ProgramDesc::kNone_ColorType:
523 GrAssert(0xffffffff == fCurrDrawState.fColor);
524 break;
525 default:
526 GrCrash("Unknown color type.");
527 }
528 }
Scroggo97c88c22011-05-11 14:05:25 +0000529 if (fProgramData->fUniLocations.fColorFilterUni
530 != GrGLProgram::kUnusedUniform
531 && fProgramData->fColorFilterColor
532 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000533 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000534 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
535 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
536 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000537}
538
539
junov@google.comf93e7172011-03-31 21:26:24 +0000540bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
541 if (!flushGLStateCommon(type)) {
542 return false;
543 }
544
545 if (fDirtyFlags.fRenderTargetChanged) {
546 // our coords are in pixel space and the GL matrices map to NDC
547 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000548 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000549 // we assume all shader matrices may be wrong after viewport changes
550 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000551 }
552
junov@google.comf93e7172011-03-31 21:26:24 +0000553 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000554 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000555 if (NULL == fProgramData) {
556 GrAssert(!"Failed to create program!");
557 return false;
558 }
junov@google.comf93e7172011-03-31 21:26:24 +0000559
560 if (fHWProgramID != fProgramData->fProgramID) {
561 GR_GL(UseProgram(fProgramData->fProgramID));
562 fHWProgramID = fProgramData->fProgramID;
563 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000564 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
565 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
566
567 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
568 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000569
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000570 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000571
bsalomon@google.com91961302011-05-09 18:39:58 +0000572 GrMatrix* currViewMatrix;
573 if (GrGLProgram::kSetAsAttribute ==
574 fProgramData->fUniLocations.fViewMatrixUni) {
575 currViewMatrix = &fHWDrawState.fViewMatrix;
576 } else {
577 currViewMatrix = &fProgramData->fViewMatrix;
578 }
junov@google.comf93e7172011-03-31 21:26:24 +0000579
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000581 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000582 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000583 }
584
585 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000586 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000587
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000588 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000589
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000590 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000591
592 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000593 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000594 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000595 resetDirtyFlags();
596 return true;
597}
598
599void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000600}
601
602void GrGpuGLShaders::setupGeometry(int* startVertex,
603 int* startIndex,
604 int vertexCount,
605 int indexCount) {
606
607 int newColorOffset;
608 int newTexCoordOffsets[kMaxTexCoords];
609
610 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
611 newTexCoordOffsets,
612 &newColorOffset);
613 int oldColorOffset;
614 int oldTexCoordOffsets[kMaxTexCoords];
615 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
616 oldTexCoordOffsets,
617 &oldColorOffset);
618 bool indexed = NULL != startIndex;
619
620 int extraVertexOffset;
621 int extraIndexOffset;
622 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
623
624 GrGLenum scalarType;
625 bool texCoordNorm;
626 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
627 scalarType = GrGLTextType;
628 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
629 } else {
630 scalarType = GrGLType;
631 texCoordNorm = false;
632 }
633
634 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
635 *startVertex = 0;
636 if (indexed) {
637 *startIndex += extraIndexOffset;
638 }
639
640 // all the Pointers must be set if any of these are true
641 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
642 vertexOffset != fHWGeometryState.fVertexOffset ||
643 newStride != oldStride;
644
645 // position and tex coord offsets change if above conditions are true
646 // or the type/normalization changed based on text vs nontext type coords.
647 bool posAndTexChange = allOffsetsChange ||
648 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
649 (kTextFormat_VertexLayoutBit &
650 (fHWGeometryState.fVertexLayout ^
651 fGeometrySrc.fVertexLayout)));
652
653 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000654 int idx = GrGLProgram::PositionAttributeIdx();
655 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
656 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000657 fHWGeometryState.fVertexOffset = vertexOffset;
658 }
659
660 for (int t = 0; t < kMaxTexCoords; ++t) {
661 if (newTexCoordOffsets[t] > 0) {
662 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000663 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000664 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000665 GR_GL(EnableVertexAttribArray(idx));
666 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
667 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000668 } else if (posAndTexChange ||
669 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000670 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
671 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000672 }
673 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000674 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000675 }
676 }
677
678 if (newColorOffset > 0) {
679 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000680 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000681 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000682 GR_GL(EnableVertexAttribArray(idx));
683 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000684 true, newStride, colorOffset));
685 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000686 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000687 true, newStride, colorOffset));
688 }
689 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000690 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000691 }
692
693 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
694 fHWGeometryState.fArrayPtrsDirty = false;
695}
696
697void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000698 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000699
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000700 // Must initialize all fields or cache will have false negatives!
701 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
702
703 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
704
705 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
706 // fColorType records how colors are specified for the program. Strip
707 // the bit from the layout to avoid false negatives when searching for an
708 // existing program in the cache.
709 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
710
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000711 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
712
junov@google.comf93e7172011-03-31 21:26:24 +0000713#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000714 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000715 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000716 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000717#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000718#if GR_GL_NO_CONSTANT_ATTRIBUTES
719 if (!requiresAttributeColors) {
720 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
721 } else
722#endif
723 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000724 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000725 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
726 }
junov@google.comf93e7172011-03-31 21:26:24 +0000727
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000728 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000729
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000730 int lastEnabledStage = -1;
731
junov@google.comf93e7172011-03-31 21:26:24 +0000732 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000733 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000734
tomhudson@google.com0d831722011-06-02 15:37:14 +0000735 stage.fOptFlags = 0;
736 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000737
tomhudson@google.com0d831722011-06-02 15:37:14 +0000738 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000739 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000740 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
741 GrAssert(NULL != texture);
742 // we matrix to invert when orientation is TopDown, so make sure
743 // we aren't in that case before flagging as identity.
744 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000745 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000746 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000747 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000748 }
749 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000750 case GrSamplerState::kNormal_SampleMode:
751 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
752 break;
753 case GrSamplerState::kRadial_SampleMode:
754 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
755 break;
756 case GrSamplerState::kRadial2_SampleMode:
757 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
758 break;
759 case GrSamplerState::kSweep_SampleMode:
760 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
761 break;
762 default:
763 GrCrash("Unexpected sample mode!");
764 break;
765 }
766
767 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
768 // these both can use a regular texture2D()
769 case GrSamplerState::kNearest_Filter:
770 case GrSamplerState::kBilinear_Filter:
771 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
772 break;
773 // performs 4 texture2D()s
774 case GrSamplerState::k4x4Downsample_Filter:
775 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
776 break;
777 default:
778 GrCrash("Unexpected filter!");
779 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000780 }
781
junov@google.com6acc9b32011-05-16 18:32:07 +0000782 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000783 GrAssert(GrSamplerState::kClamp_WrapMode ==
784 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000785 GrSamplerState::kClamp_WrapMode ==
786 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000787 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000788 GrGLProgram::ProgramDesc::StageDesc::
789 kCustomTextureDomain_OptFlagBit;
790 }
791
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000792 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000793 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
794 } else {
795 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
796 }
junov@google.comf93e7172011-03-31 21:26:24 +0000797 } else {
798 stage.fOptFlags = 0;
799 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
800 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000801 }
802 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000803
804 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
805 // use canonical value when coverage/color distinction won't affect
806 // generated code to prevent duplicate programs.
807 desc.fFirstCoverageStage = kNumStages;
808 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
809 // color filter is applied between color/coverage computation
810 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
811 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
812 }
813
814 // We could consider cases where the final color is solid (0xff alpha)
815 // and the dst coeff can correctly be set to a non-dualsrc gl value.
816 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
817 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
818 // kOne).
819 if (fDualSourceBlendingSupport) {
820 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
821 // write the coverage value to second color
822 desc.fDualSrcOutput =
823 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
824 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
825 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
826 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
827 // cover
828 desc.fDualSrcOutput =
829 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
830 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
831 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
832 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
833 // cover
834 desc.fDualSrcOutput =
835 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
836 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
837 }
838 }
839 }
junov@google.comf93e7172011-03-31 21:26:24 +0000840}