blob: 689c1fce9df6ca3d0f6c46831e24b296cbb3481a [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
junov@google.com53a55842011-06-08 22:55:10 +0000133void GrGpuGLShaders::abandonResources(){
134 INHERITED::abandonResources();
135 fProgramCache->abandon();
136}
137
junov@google.comf93e7172011-03-31 21:26:24 +0000138void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
139 GR_GL(DeleteShader(programData->fVShaderID));
140 GR_GL(DeleteShader(programData->fFShaderID));
141 GR_GL(DeleteProgram(programData->fProgramID));
142 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
143}
144
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000145void GrGpuGLShaders::ProgramUnitTest() {
146
147 static const int STAGE_OPTS[] = {
148 0,
149 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
150 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
151 };
152 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
153 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
154 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
155 };
156 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
157 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
158 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
159 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
160 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
161 };
162 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
163 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
164 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
165 };
166 GrGLProgram program;
167 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
168
169 static const int NUM_TESTS = 512;
170
171 // GrRandoms nextU() values have patterns in the low bits
172 // So using nextU() % array_count might never take some values.
173 GrRandom random;
174 for (int t = 0; t < NUM_TESTS; ++t) {
175
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000176#if 0
177 GrPrintf("\nTest Program %d\n-------------\n", t);
178 static const int stop = -1;
179 if (t == stop) {
180 int breakpointhere = 9;
181 }
182#endif
183
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000184 pdesc.fVertexLayout = 0;
185 pdesc.fEmitsPointSize = random.nextF() > .5f;
186 float colorType = random.nextF();
187 if (colorType < 1.f / 3.f) {
188 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
189 } else if (colorType < 2.f / 3.f) {
190 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
191 } else {
192 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
193 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000194
195 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
196 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
197
198 idx = (int)(random.nextF() * (kNumStages+1));
199 pdesc.fFirstCoverageStage = idx;
200
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000201 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000202 pdesc.fEdgeAAConcave = random.nextF() > .5f;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000203
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000204 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000205 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000206 (GrGLProgram::ProgramDesc::DualSrcOutput)
207 (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
208 } else {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000209 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000210 GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
211 }
212
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000213 for (int s = 0; s < kNumStages; ++s) {
214 // enable the stage?
215 if (random.nextF() > .5f) {
216 // use separate tex coords?
217 if (random.nextF() > .5f) {
218 int t = (int)(random.nextF() * kMaxTexCoords);
219 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
220 } else {
221 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
222 }
223 }
224 // use text-formatted verts?
225 if (random.nextF() > .5f) {
226 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
227 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000228 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
229 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
230 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
231 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
232 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
233 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
234 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
235 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
tomhudson@google.com0d831722011-06-02 15:37:14 +0000236 pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 }
238 GrGLProgram::CachedData cachedData;
239 program.genProgram(&cachedData);
240 DeleteProgram(&cachedData);
241 bool again = false;
242 if (again) {
243 program.genProgram(&cachedData);
244 DeleteProgram(&cachedData);
245 }
246 }
247}
248
junov@google.comf93e7172011-03-31 21:26:24 +0000249GrGpuGLShaders::GrGpuGLShaders() {
250
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000251 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000252 int major, minor;
253 gl_version(&major, &minor);
254
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000255 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000256 if (GR_GL_SUPPORT_DESKTOP) {
257 fDualSourceBlendingSupport =
258 major > 3 ||(3 == major && 3 <= minor) ||
259 has_gl_extension("GL_ARB_blend_func_extended");
260 } else {
261 fDualSourceBlendingSupport = false;
262 }
junov@google.comf93e7172011-03-31 21:26:24 +0000263
264 fProgramData = NULL;
265 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000266
267#if 0
268 ProgramUnitTest();
269#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000270}
271
272GrGpuGLShaders::~GrGpuGLShaders() {
273 delete fProgramCache;
274}
275
276const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000277 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000278
279 if (GrGLProgram::kSetAsAttribute ==
280 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
281 return fHWDrawState.fSamplerStates[stage].getMatrix();
282 } else {
283 return fProgramData->fTextureMatrices[stage];
284 }
junov@google.comf93e7172011-03-31 21:26:24 +0000285}
286
287void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000288 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000289 if (GrGLProgram::kSetAsAttribute ==
290 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
291 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
292 } else {
293 fProgramData->fTextureMatrices[stage] = matrix;
294 }
junov@google.comf93e7172011-03-31 21:26:24 +0000295}
296
297void GrGpuGLShaders::resetContext() {
298 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000299
junov@google.comf93e7172011-03-31 21:26:24 +0000300 fHWGeometryState.fVertexLayout = 0;
301 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000302 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000303 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000304 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000305 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000306 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000307
308 fHWProgramID = 0;
309}
310
311void GrGpuGLShaders::flushViewMatrix() {
312 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000313 GrMatrix m;
314 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000315 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
316 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
317 0, 0, GrMatrix::I()[8]);
318 m.setConcat(m, fCurrDrawState.fViewMatrix);
319
320 // ES doesn't allow you to pass true to the transpose param,
321 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000322 GrGLfloat mt[] = {
323 GrScalarToFloat(m[GrMatrix::kMScaleX]),
324 GrScalarToFloat(m[GrMatrix::kMSkewY]),
325 GrScalarToFloat(m[GrMatrix::kMPersp0]),
326 GrScalarToFloat(m[GrMatrix::kMSkewX]),
327 GrScalarToFloat(m[GrMatrix::kMScaleY]),
328 GrScalarToFloat(m[GrMatrix::kMPersp1]),
329 GrScalarToFloat(m[GrMatrix::kMTransX]),
330 GrScalarToFloat(m[GrMatrix::kMTransY]),
331 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000332 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000333
334 if (GrGLProgram::kSetAsAttribute ==
335 fProgramData->fUniLocations.fViewMatrixUni) {
336 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
337 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
338 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
339 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
340 } else {
341 GrAssert(GrGLProgram::kUnusedUniform !=
342 fProgramData->fUniLocations.fViewMatrixUni);
343 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
344 1, false, mt));
345 }
junov@google.comf93e7172011-03-31 21:26:24 +0000346}
347
junov@google.com6acc9b32011-05-16 18:32:07 +0000348void GrGpuGLShaders::flushTextureDomain(int s) {
349 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
350 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000351 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000352 fCurrDrawState.fSamplerStates[s].getTextureDomain();
353
twiz@google.com76b82742011-06-02 20:30:02 +0000354 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
355 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000356
junov@google.com2f839402011-05-24 15:13:01 +0000357 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000358
junov@google.com2f839402011-05-24 15:13:01 +0000359 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000360 GrScalarToFloat(texDom.left()),
361 GrScalarToFloat(texDom.top()),
362 GrScalarToFloat(texDom.right()),
363 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000364 };
365
366 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
367 GrGLTexture::Orientation orientation = texture->orientation();
368
369 // vertical flip if necessary
370 if (GrGLTexture::kBottomUp_Orientation == orientation) {
371 values[1] = 1.0f - values[1];
372 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000373 // The top and bottom were just flipped, so correct the ordering
374 // of elements so that values = (l, t, r, b).
375 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000376 }
377
378 values[0] *= SkScalarToFloat(texture->contentScaleX());
379 values[2] *= SkScalarToFloat(texture->contentScaleX());
380 values[1] *= SkScalarToFloat(texture->contentScaleY());
381 values[3] *= SkScalarToFloat(texture->contentScaleY());
382
383 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000384 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000385 }
386}
387
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000388void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000389 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000390 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
391 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000393 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
394 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000395
bsalomon@google.com91961302011-05-09 18:39:58 +0000396 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000397
bsalomon@google.com91961302011-05-09 18:39:58 +0000398 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000399
bsalomon@google.com91961302011-05-09 18:39:58 +0000400 GrMatrix m = getSamplerMatrix(s);
401 GrSamplerState::SampleMode mode =
402 fCurrDrawState.fSamplerStates[s].getSampleMode();
403 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000404
bsalomon@google.com91961302011-05-09 18:39:58 +0000405 // ES doesn't allow you to pass true to the transpose param,
406 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000407 GrGLfloat mt[] = {
408 GrScalarToFloat(m[GrMatrix::kMScaleX]),
409 GrScalarToFloat(m[GrMatrix::kMSkewY]),
410 GrScalarToFloat(m[GrMatrix::kMPersp0]),
411 GrScalarToFloat(m[GrMatrix::kMSkewX]),
412 GrScalarToFloat(m[GrMatrix::kMScaleY]),
413 GrScalarToFloat(m[GrMatrix::kMPersp1]),
414 GrScalarToFloat(m[GrMatrix::kMTransX]),
415 GrScalarToFloat(m[GrMatrix::kMTransY]),
416 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000417 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000418
bsalomon@google.com91961302011-05-09 18:39:58 +0000419 if (GrGLProgram::kSetAsAttribute ==
420 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
421 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
422 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
423 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
424 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
425 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000426 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000427 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000428 recordHWSamplerMatrix(s, getSamplerMatrix(s));
429 }
430 }
junov@google.comf93e7172011-03-31 21:26:24 +0000431}
432
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000433void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000434
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000435 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
436 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000437 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000438 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
439 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
440 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000441
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000442 GrScalar centerX1 = sampler.getRadial2CenterX1();
443 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000444
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000445 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000446
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000447 float values[6] = {
448 GrScalarToFloat(a),
449 1 / (2.f * values[0]),
450 GrScalarToFloat(centerX1),
451 GrScalarToFloat(radius0),
452 GrScalarToFloat(GrMul(radius0, radius0)),
453 sampler.isRadial2PosRoot() ? 1.f : -1.f
454 };
455 GR_GL(Uniform1fv(uni, 6, values));
456 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
457 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
458 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
459 }
460}
461
462void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000463 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000464 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000465 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
466 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
467 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
468
469 float texelSize[] = {1.f / texture->allocWidth(),
470 1.f / texture->allocHeight()};
471 GR_GL(Uniform2fv(uni, 1, texelSize));
472 }
473 }
junov@google.comf93e7172011-03-31 21:26:24 +0000474}
475
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000476void GrGpuGLShaders::flushEdgeAAData() {
477 const int& uni = fProgramData->fUniLocations.fEdgesUni;
478 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000479 int count = fCurrDrawState.fEdgeAANumEdges;
480 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000481 // Flip the edges in Y
482 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000483 for (int i = 0; i < count; ++i) {
484 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
485 float b = edges[i].fY;
486 edges[i].fY = -b;
487 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000488 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000489 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000490 }
491}
492
Scroggo01b87ec2011-05-11 18:05:38 +0000493static const float ONE_OVER_255 = 1.f / 255.f;
494
495#define GR_COLOR_TO_VEC4(color) {\
496 GrColorUnpackR(color) * ONE_OVER_255,\
497 GrColorUnpackG(color) * ONE_OVER_255,\
498 GrColorUnpackB(color) * ONE_OVER_255,\
499 GrColorUnpackA(color) * ONE_OVER_255 \
500}
501
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000502void GrGpuGLShaders::flushColor() {
503 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
504 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
505 // color will be specified per-vertex as an attribute
506 // invalidate the const vertex attrib color
507 fHWDrawState.fColor = GrColor_ILLEGAL;
508 } else {
509 switch (desc.fColorType) {
510 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
511 if (fHWDrawState.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 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000515 fHWDrawState.fColor = fCurrDrawState.fColor;
516 }
517 break;
518 case GrGLProgram::ProgramDesc::kUniform_ColorType:
519 if (fProgramData->fColor != fCurrDrawState.fColor) {
520 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000521 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000522 GrAssert(GrGLProgram::kUnusedUniform !=
523 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000524 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
525 fProgramData->fColor = fCurrDrawState.fColor;
526 }
527 break;
528 case GrGLProgram::ProgramDesc::kNone_ColorType:
529 GrAssert(0xffffffff == fCurrDrawState.fColor);
530 break;
531 default:
532 GrCrash("Unknown color type.");
533 }
534 }
Scroggo97c88c22011-05-11 14:05:25 +0000535 if (fProgramData->fUniLocations.fColorFilterUni
536 != GrGLProgram::kUnusedUniform
537 && fProgramData->fColorFilterColor
538 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000539 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000540 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
541 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
542 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000543}
544
545
junov@google.comf93e7172011-03-31 21:26:24 +0000546bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
547 if (!flushGLStateCommon(type)) {
548 return false;
549 }
550
551 if (fDirtyFlags.fRenderTargetChanged) {
552 // our coords are in pixel space and the GL matrices map to NDC
553 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000554 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000555 // we assume all shader matrices may be wrong after viewport changes
556 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000557 }
558
junov@google.comf93e7172011-03-31 21:26:24 +0000559 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000560 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000561 if (NULL == fProgramData) {
562 GrAssert(!"Failed to create program!");
563 return false;
564 }
junov@google.comf93e7172011-03-31 21:26:24 +0000565
566 if (fHWProgramID != fProgramData->fProgramID) {
567 GR_GL(UseProgram(fProgramData->fProgramID));
568 fHWProgramID = fProgramData->fProgramID;
569 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000570 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
571 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
572
573 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
574 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000575
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000576 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000577
bsalomon@google.com91961302011-05-09 18:39:58 +0000578 GrMatrix* currViewMatrix;
579 if (GrGLProgram::kSetAsAttribute ==
580 fProgramData->fUniLocations.fViewMatrixUni) {
581 currViewMatrix = &fHWDrawState.fViewMatrix;
582 } else {
583 currViewMatrix = &fProgramData->fViewMatrix;
584 }
junov@google.comf93e7172011-03-31 21:26:24 +0000585
bsalomon@google.com91961302011-05-09 18:39:58 +0000586 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000587 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000588 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000589 }
590
591 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000592 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000593
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000594 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000595
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000596 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000597
598 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000599 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000600 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000601 resetDirtyFlags();
602 return true;
603}
604
605void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000606}
607
608void GrGpuGLShaders::setupGeometry(int* startVertex,
609 int* startIndex,
610 int vertexCount,
611 int indexCount) {
612
613 int newColorOffset;
614 int newTexCoordOffsets[kMaxTexCoords];
615
616 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
617 newTexCoordOffsets,
618 &newColorOffset);
619 int oldColorOffset;
620 int oldTexCoordOffsets[kMaxTexCoords];
621 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
622 oldTexCoordOffsets,
623 &oldColorOffset);
624 bool indexed = NULL != startIndex;
625
626 int extraVertexOffset;
627 int extraIndexOffset;
628 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
629
630 GrGLenum scalarType;
631 bool texCoordNorm;
632 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
633 scalarType = GrGLTextType;
634 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
635 } else {
636 scalarType = GrGLType;
637 texCoordNorm = false;
638 }
639
640 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
641 *startVertex = 0;
642 if (indexed) {
643 *startIndex += extraIndexOffset;
644 }
645
646 // all the Pointers must be set if any of these are true
647 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
648 vertexOffset != fHWGeometryState.fVertexOffset ||
649 newStride != oldStride;
650
651 // position and tex coord offsets change if above conditions are true
652 // or the type/normalization changed based on text vs nontext type coords.
653 bool posAndTexChange = allOffsetsChange ||
654 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
655 (kTextFormat_VertexLayoutBit &
656 (fHWGeometryState.fVertexLayout ^
657 fGeometrySrc.fVertexLayout)));
658
659 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000660 int idx = GrGLProgram::PositionAttributeIdx();
661 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
662 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000663 fHWGeometryState.fVertexOffset = vertexOffset;
664 }
665
666 for (int t = 0; t < kMaxTexCoords; ++t) {
667 if (newTexCoordOffsets[t] > 0) {
668 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000669 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000670 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000671 GR_GL(EnableVertexAttribArray(idx));
672 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
673 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000674 } else if (posAndTexChange ||
675 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000676 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
677 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000678 }
679 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000680 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000681 }
682 }
683
684 if (newColorOffset > 0) {
685 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000686 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000687 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000688 GR_GL(EnableVertexAttribArray(idx));
689 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000690 true, newStride, colorOffset));
691 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000692 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000693 true, newStride, colorOffset));
694 }
695 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000696 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000697 }
698
699 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
700 fHWGeometryState.fArrayPtrsDirty = false;
701}
702
703void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000704 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000705
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000706 // Must initialize all fields or cache will have false negatives!
707 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
708
709 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
710
711 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
712 // fColorType records how colors are specified for the program. Strip
713 // the bit from the layout to avoid false negatives when searching for an
714 // existing program in the cache.
715 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
716
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000717 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
718
junov@google.comf93e7172011-03-31 21:26:24 +0000719#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000720 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000721 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000722 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000723#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000724#if GR_GL_NO_CONSTANT_ATTRIBUTES
725 if (!requiresAttributeColors) {
726 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
727 } else
728#endif
729 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000730 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000731 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
732 }
junov@google.comf93e7172011-03-31 21:26:24 +0000733
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000734 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000735 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000736
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000737 int lastEnabledStage = -1;
738
junov@google.comf93e7172011-03-31 21:26:24 +0000739 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000740 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000741
tomhudson@google.com0d831722011-06-02 15:37:14 +0000742 stage.fOptFlags = 0;
743 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000744
tomhudson@google.com0d831722011-06-02 15:37:14 +0000745 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000746 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000747 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
748 GrAssert(NULL != texture);
749 // we matrix to invert when orientation is TopDown, so make sure
750 // we aren't in that case before flagging as identity.
751 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000752 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000753 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000754 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000755 }
756 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000757 case GrSamplerState::kNormal_SampleMode:
758 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
759 break;
760 case GrSamplerState::kRadial_SampleMode:
761 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
762 break;
763 case GrSamplerState::kRadial2_SampleMode:
764 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
765 break;
766 case GrSamplerState::kSweep_SampleMode:
767 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
768 break;
769 default:
770 GrCrash("Unexpected sample mode!");
771 break;
772 }
773
774 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
775 // these both can use a regular texture2D()
776 case GrSamplerState::kNearest_Filter:
777 case GrSamplerState::kBilinear_Filter:
778 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
779 break;
780 // performs 4 texture2D()s
781 case GrSamplerState::k4x4Downsample_Filter:
782 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
783 break;
784 default:
785 GrCrash("Unexpected filter!");
786 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000787 }
788
junov@google.com6acc9b32011-05-16 18:32:07 +0000789 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000790 GrAssert(GrSamplerState::kClamp_WrapMode ==
791 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000792 GrSamplerState::kClamp_WrapMode ==
793 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000794 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000795 GrGLProgram::ProgramDesc::StageDesc::
796 kCustomTextureDomain_OptFlagBit;
797 }
798
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000799 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000800 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
801 } else {
802 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
803 }
junov@google.comf93e7172011-03-31 21:26:24 +0000804 } else {
805 stage.fOptFlags = 0;
806 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
807 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000808 }
809 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000810
811 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
812 // use canonical value when coverage/color distinction won't affect
813 // generated code to prevent duplicate programs.
814 desc.fFirstCoverageStage = kNumStages;
815 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
816 // color filter is applied between color/coverage computation
817 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
818 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
819 }
820
821 // We could consider cases where the final color is solid (0xff alpha)
822 // and the dst coeff can correctly be set to a non-dualsrc gl value.
823 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
824 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
825 // kOne).
826 if (fDualSourceBlendingSupport) {
827 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
828 // write the coverage value to second color
829 desc.fDualSrcOutput =
830 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
831 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
832 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
833 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
834 // cover
835 desc.fDualSrcOutput =
836 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
837 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
838 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
839 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
840 // cover
841 desc.fDualSrcOutput =
842 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
843 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
844 }
845 }
846 }
junov@google.comf93e7172011-03-31 21:26:24 +0000847}