blob: b474be240e7c296842379b1a944bc9a41a1f5dc7 [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"
junov@google.comf93e7172011-03-31 21:26:24 +000021#include "GrNoncopyable.h"
22#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000023#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000024
junov@google.comf93e7172011-03-31 21:26:24 +000025#define SKIP_CACHE_CHECK true
26#define GR_UINT32_MAX static_cast<uint32_t>(-1)
27
junov@google.comf93e7172011-03-31 21:26:24 +000028#include "GrTHashCache.h"
29
30class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
31private:
32 class Entry;
33
34#if GR_DEBUG
35 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
36#else
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000037 typedef GrBinHashKey<Entry, 64> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000038#endif
39
40 class Entry : public ::GrNoncopyable {
41 public:
42 Entry() {}
junov@google.comf93e7172011-03-31 21:26:24 +000043 void copyAndTakeOwnership(Entry& entry) {
44 fProgramData.copyAndTakeOwnership(entry.fProgramData);
45 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000046 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000047 }
48
49 public:
50 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
51
52 public:
53 GrGLProgram::CachedData fProgramData;
54 ProgramHashKey fKey;
55 unsigned int fLRUStamp;
56 };
57
58 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
59
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000060 // We may have kMaxEntries+1 shaders in the GL context because
61 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000062 enum {
63 kMaxEntries = 32
64 };
65 Entry fEntries[kMaxEntries];
66 int fCount;
67 unsigned int fCurrLRUStamp;
68
69public:
70 ProgramCache()
71 : fCount(0)
72 , fCurrLRUStamp(0) {
73 }
74
75 ~ProgramCache() {
76 for (int i = 0; i < fCount; ++i) {
77 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
78 }
79 }
80
81 void abandon() {
82 fCount = 0;
83 }
84
85 void invalidateViewMatrices() {
86 for (int i = 0; i < fCount; ++i) {
87 // set to illegal matrix
88 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
89 }
90 }
91
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000092 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000093 Entry newEntry;
94 while (newEntry.fKey.doPass()) {
95 desc.buildKey(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000096 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000097 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000098 if (NULL == entry) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000099 if (!desc.genProgram(&newEntry.fProgramData)) {
100 return NULL;
101 }
junov@google.comf93e7172011-03-31 21:26:24 +0000102 if (fCount < kMaxEntries) {
103 entry = fEntries + fCount;
104 ++fCount;
105 } else {
106 GrAssert(kMaxEntries == fCount);
107 entry = fEntries;
108 for (int i = 1; i < kMaxEntries; ++i) {
109 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
110 entry = fEntries + i;
111 }
112 }
113 fHashCache.remove(entry->fKey, entry);
114 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
115 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000116 entry->copyAndTakeOwnership(newEntry);
junov@google.comf93e7172011-03-31 21:26:24 +0000117 fHashCache.insert(entry->fKey, entry);
118 }
119
120 entry->fLRUStamp = fCurrLRUStamp;
121 if (GR_UINT32_MAX == fCurrLRUStamp) {
122 // wrap around! just trash our LRU, one time hit.
123 for (int i = 0; i < fCount; ++i) {
124 fEntries[i].fLRUStamp = 0;
125 }
126 }
127 ++fCurrLRUStamp;
128 return &entry->fProgramData;
129 }
130};
131
junov@google.com53a55842011-06-08 22:55:10 +0000132void GrGpuGLShaders::abandonResources(){
133 INHERITED::abandonResources();
134 fProgramCache->abandon();
135}
136
junov@google.comf93e7172011-03-31 21:26:24 +0000137void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
138 GR_GL(DeleteShader(programData->fVShaderID));
139 GR_GL(DeleteShader(programData->fFShaderID));
140 GR_GL(DeleteProgram(programData->fProgramID));
141 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
142}
143
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000144void GrGpuGLShaders::ProgramUnitTest() {
145
146 static const int STAGE_OPTS[] = {
147 0,
148 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
149 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
150 };
151 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
152 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
153 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
154 };
155 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
156 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
157 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
158 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
159 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
160 };
161 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
162 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
163 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
164 };
165 GrGLProgram program;
166 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
167
168 static const int NUM_TESTS = 512;
169
170 // GrRandoms nextU() values have patterns in the low bits
171 // So using nextU() % array_count might never take some values.
172 GrRandom random;
173 for (int t = 0; t < NUM_TESTS; ++t) {
174
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000175#if 0
176 GrPrintf("\nTest Program %d\n-------------\n", t);
177 static const int stop = -1;
178 if (t == stop) {
179 int breakpointhere = 9;
180 }
181#endif
182
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000183 pdesc.fVertexLayout = 0;
184 pdesc.fEmitsPointSize = random.nextF() > .5f;
185 float colorType = random.nextF();
186 if (colorType < 1.f / 3.f) {
187 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
188 } else if (colorType < 2.f / 3.f) {
189 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
190 } else {
191 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
192 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000193
194 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
195 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
196
197 idx = (int)(random.nextF() * (kNumStages+1));
198 pdesc.fFirstCoverageStage = idx;
199
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000200 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000201 pdesc.fEdgeAAConcave = random.nextF() > .5f;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000202
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000203 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000204 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000205 (GrGLProgram::ProgramDesc::DualSrcOutput)
206 (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
207 } else {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000208 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000209 GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
210 }
211
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000212 for (int s = 0; s < kNumStages; ++s) {
213 // enable the stage?
214 if (random.nextF() > .5f) {
215 // use separate tex coords?
216 if (random.nextF() > .5f) {
217 int t = (int)(random.nextF() * kMaxTexCoords);
218 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
219 } else {
220 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
221 }
222 }
223 // use text-formatted verts?
224 if (random.nextF() > .5f) {
225 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
226 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000227 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
228 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
229 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
230 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
231 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
232 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
233 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
234 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
tomhudson@google.com0d831722011-06-02 15:37:14 +0000235 pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000236 }
237 GrGLProgram::CachedData cachedData;
238 program.genProgram(&cachedData);
239 DeleteProgram(&cachedData);
240 bool again = false;
241 if (again) {
242 program.genProgram(&cachedData);
243 DeleteProgram(&cachedData);
244 }
245 }
246}
247
junov@google.comf93e7172011-03-31 21:26:24 +0000248GrGpuGLShaders::GrGpuGLShaders() {
249
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000250 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000251 int major, minor;
252 gl_version(&major, &minor);
253
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000254 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000255 if (GR_GL_SUPPORT_DESKTOP) {
256 fDualSourceBlendingSupport =
257 major > 3 ||(3 == major && 3 <= minor) ||
258 has_gl_extension("GL_ARB_blend_func_extended");
259 } else {
260 fDualSourceBlendingSupport = false;
261 }
junov@google.comf93e7172011-03-31 21:26:24 +0000262
263 fProgramData = NULL;
264 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000265
266#if 0
267 ProgramUnitTest();
268#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000269}
270
271GrGpuGLShaders::~GrGpuGLShaders() {
272 delete fProgramCache;
273}
274
275const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000276 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000277
278 if (GrGLProgram::kSetAsAttribute ==
279 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
280 return fHWDrawState.fSamplerStates[stage].getMatrix();
281 } else {
282 return fProgramData->fTextureMatrices[stage];
283 }
junov@google.comf93e7172011-03-31 21:26:24 +0000284}
285
286void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000287 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000288 if (GrGLProgram::kSetAsAttribute ==
289 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
290 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
291 } else {
292 fProgramData->fTextureMatrices[stage] = matrix;
293 }
junov@google.comf93e7172011-03-31 21:26:24 +0000294}
295
296void GrGpuGLShaders::resetContext() {
297 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000298
junov@google.comf93e7172011-03-31 21:26:24 +0000299 fHWGeometryState.fVertexLayout = 0;
300 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000301 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000302 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000303 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000304 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000305 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000306
307 fHWProgramID = 0;
308}
309
310void GrGpuGLShaders::flushViewMatrix() {
311 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000312 GrMatrix m;
313 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000314 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
315 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
316 0, 0, GrMatrix::I()[8]);
317 m.setConcat(m, fCurrDrawState.fViewMatrix);
318
319 // ES doesn't allow you to pass true to the transpose param,
320 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000321 GrGLfloat mt[] = {
322 GrScalarToFloat(m[GrMatrix::kMScaleX]),
323 GrScalarToFloat(m[GrMatrix::kMSkewY]),
324 GrScalarToFloat(m[GrMatrix::kMPersp0]),
325 GrScalarToFloat(m[GrMatrix::kMSkewX]),
326 GrScalarToFloat(m[GrMatrix::kMScaleY]),
327 GrScalarToFloat(m[GrMatrix::kMPersp1]),
328 GrScalarToFloat(m[GrMatrix::kMTransX]),
329 GrScalarToFloat(m[GrMatrix::kMTransY]),
330 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000331 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000332
333 if (GrGLProgram::kSetAsAttribute ==
334 fProgramData->fUniLocations.fViewMatrixUni) {
335 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
336 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
337 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
338 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
339 } else {
340 GrAssert(GrGLProgram::kUnusedUniform !=
341 fProgramData->fUniLocations.fViewMatrixUni);
342 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
343 1, false, mt));
344 }
junov@google.comf93e7172011-03-31 21:26:24 +0000345}
346
junov@google.com6acc9b32011-05-16 18:32:07 +0000347void GrGpuGLShaders::flushTextureDomain(int s) {
348 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
349 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000350 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000351 fCurrDrawState.fSamplerStates[s].getTextureDomain();
352
twiz@google.com76b82742011-06-02 20:30:02 +0000353 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
354 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000355
junov@google.com2f839402011-05-24 15:13:01 +0000356 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000357
junov@google.com2f839402011-05-24 15:13:01 +0000358 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000359 GrScalarToFloat(texDom.left()),
360 GrScalarToFloat(texDom.top()),
361 GrScalarToFloat(texDom.right()),
362 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000363 };
364
365 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
366 GrGLTexture::Orientation orientation = texture->orientation();
367
368 // vertical flip if necessary
369 if (GrGLTexture::kBottomUp_Orientation == orientation) {
370 values[1] = 1.0f - values[1];
371 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000372 // The top and bottom were just flipped, so correct the ordering
373 // of elements so that values = (l, t, r, b).
374 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000375 }
376
377 values[0] *= SkScalarToFloat(texture->contentScaleX());
378 values[2] *= SkScalarToFloat(texture->contentScaleX());
379 values[1] *= SkScalarToFloat(texture->contentScaleY());
380 values[3] *= SkScalarToFloat(texture->contentScaleY());
381
382 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000383 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000384 }
385}
386
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000388 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000389 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
390 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000391 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000392 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
393 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000394
bsalomon@google.com91961302011-05-09 18:39:58 +0000395 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000396
bsalomon@google.com91961302011-05-09 18:39:58 +0000397 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000398
bsalomon@google.com91961302011-05-09 18:39:58 +0000399 GrMatrix m = getSamplerMatrix(s);
400 GrSamplerState::SampleMode mode =
401 fCurrDrawState.fSamplerStates[s].getSampleMode();
402 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000403
bsalomon@google.com91961302011-05-09 18:39:58 +0000404 // ES doesn't allow you to pass true to the transpose param,
405 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000406 GrGLfloat mt[] = {
407 GrScalarToFloat(m[GrMatrix::kMScaleX]),
408 GrScalarToFloat(m[GrMatrix::kMSkewY]),
409 GrScalarToFloat(m[GrMatrix::kMPersp0]),
410 GrScalarToFloat(m[GrMatrix::kMSkewX]),
411 GrScalarToFloat(m[GrMatrix::kMScaleY]),
412 GrScalarToFloat(m[GrMatrix::kMPersp1]),
413 GrScalarToFloat(m[GrMatrix::kMTransX]),
414 GrScalarToFloat(m[GrMatrix::kMTransY]),
415 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000416 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000417
bsalomon@google.com91961302011-05-09 18:39:58 +0000418 if (GrGLProgram::kSetAsAttribute ==
419 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
420 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
421 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
422 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
423 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
424 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000425 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000426 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427 recordHWSamplerMatrix(s, getSamplerMatrix(s));
428 }
429 }
junov@google.comf93e7172011-03-31 21:26:24 +0000430}
431
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000432void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
435 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000436 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000437 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
438 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
439 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000440
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 GrScalar centerX1 = sampler.getRadial2CenterX1();
442 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000443
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000444 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000445
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000446 float values[6] = {
447 GrScalarToFloat(a),
448 1 / (2.f * values[0]),
449 GrScalarToFloat(centerX1),
450 GrScalarToFloat(radius0),
451 GrScalarToFloat(GrMul(radius0, radius0)),
452 sampler.isRadial2PosRoot() ? 1.f : -1.f
453 };
454 GR_GL(Uniform1fv(uni, 6, values));
455 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
456 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
457 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
458 }
459}
460
461void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000462 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000463 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000464 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
465 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
466 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
467
468 float texelSize[] = {1.f / texture->allocWidth(),
469 1.f / texture->allocHeight()};
470 GR_GL(Uniform2fv(uni, 1, texelSize));
471 }
472 }
junov@google.comf93e7172011-03-31 21:26:24 +0000473}
474
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000475void GrGpuGLShaders::flushEdgeAAData() {
476 const int& uni = fProgramData->fUniLocations.fEdgesUni;
477 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000478 int count = fCurrDrawState.fEdgeAANumEdges;
479 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000480 // Flip the edges in Y
481 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000482 for (int i = 0; i < count; ++i) {
483 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
484 float b = edges[i].fY;
485 edges[i].fY = -b;
486 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000487 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000488 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000489 }
490}
491
Scroggo01b87ec2011-05-11 18:05:38 +0000492static const float ONE_OVER_255 = 1.f / 255.f;
493
494#define GR_COLOR_TO_VEC4(color) {\
495 GrColorUnpackR(color) * ONE_OVER_255,\
496 GrColorUnpackG(color) * ONE_OVER_255,\
497 GrColorUnpackB(color) * ONE_OVER_255,\
498 GrColorUnpackA(color) * ONE_OVER_255 \
499}
500
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000501void GrGpuGLShaders::flushColor() {
502 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000503 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000504 // color will be specified per-vertex as an attribute
505 // invalidate the const vertex attrib color
506 fHWDrawState.fColor = GrColor_ILLEGAL;
507 } else {
508 switch (desc.fColorType) {
509 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
510 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
511 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000512 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000513 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000514 fHWDrawState.fColor = fCurrDrawState.fColor;
515 }
516 break;
517 case GrGLProgram::ProgramDesc::kUniform_ColorType:
518 if (fProgramData->fColor != fCurrDrawState.fColor) {
519 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000520 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000521 GrAssert(GrGLProgram::kUnusedUniform !=
522 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000523 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
524 fProgramData->fColor = fCurrDrawState.fColor;
525 }
526 break;
527 case GrGLProgram::ProgramDesc::kNone_ColorType:
528 GrAssert(0xffffffff == fCurrDrawState.fColor);
529 break;
530 default:
531 GrCrash("Unknown color type.");
532 }
533 }
Scroggo97c88c22011-05-11 14:05:25 +0000534 if (fProgramData->fUniLocations.fColorFilterUni
535 != GrGLProgram::kUnusedUniform
536 && fProgramData->fColorFilterColor
537 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000538 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000539 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
540 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
541 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000542}
543
544
junov@google.comf93e7172011-03-31 21:26:24 +0000545bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
546 if (!flushGLStateCommon(type)) {
547 return false;
548 }
549
550 if (fDirtyFlags.fRenderTargetChanged) {
551 // our coords are in pixel space and the GL matrices map to NDC
552 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000553 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000554 // we assume all shader matrices may be wrong after viewport changes
555 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000556 }
557
junov@google.comf93e7172011-03-31 21:26:24 +0000558 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000559 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000560 if (NULL == fProgramData) {
561 GrAssert(!"Failed to create program!");
562 return false;
563 }
junov@google.comf93e7172011-03-31 21:26:24 +0000564
565 if (fHWProgramID != fProgramData->fProgramID) {
566 GR_GL(UseProgram(fProgramData->fProgramID));
567 fHWProgramID = fProgramData->fProgramID;
568 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000569 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
570 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
571
572 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
573 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000574
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000575 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000576
bsalomon@google.com91961302011-05-09 18:39:58 +0000577 GrMatrix* currViewMatrix;
578 if (GrGLProgram::kSetAsAttribute ==
579 fProgramData->fUniLocations.fViewMatrixUni) {
580 currViewMatrix = &fHWDrawState.fViewMatrix;
581 } else {
582 currViewMatrix = &fProgramData->fViewMatrix;
583 }
junov@google.comf93e7172011-03-31 21:26:24 +0000584
bsalomon@google.com91961302011-05-09 18:39:58 +0000585 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000586 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000587 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000588 }
589
590 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000591 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000592
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000593 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000594
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000595 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000596
597 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000598 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000599 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000600 resetDirtyFlags();
601 return true;
602}
603
604void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000605}
606
607void GrGpuGLShaders::setupGeometry(int* startVertex,
608 int* startIndex,
609 int vertexCount,
610 int indexCount) {
611
612 int newColorOffset;
613 int newTexCoordOffsets[kMaxTexCoords];
614
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000615 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
616 this->getGeomSrc().fVertexLayout,
617 newTexCoordOffsets,
618 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000619 int oldColorOffset;
620 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000621 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
622 fHWGeometryState.fVertexLayout,
623 oldTexCoordOffsets,
624 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000625 bool indexed = NULL != startIndex;
626
627 int extraVertexOffset;
628 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000629 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000630
631 GrGLenum scalarType;
632 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000633 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000634 scalarType = GrGLTextType;
635 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
636 } else {
637 scalarType = GrGLType;
638 texCoordNorm = false;
639 }
640
641 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
642 *startVertex = 0;
643 if (indexed) {
644 *startIndex += extraIndexOffset;
645 }
646
647 // all the Pointers must be set if any of these are true
648 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
649 vertexOffset != fHWGeometryState.fVertexOffset ||
650 newStride != oldStride;
651
652 // position and tex coord offsets change if above conditions are true
653 // or the type/normalization changed based on text vs nontext type coords.
654 bool posAndTexChange = allOffsetsChange ||
655 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
656 (kTextFormat_VertexLayoutBit &
657 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000658 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000659
660 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000661 int idx = GrGLProgram::PositionAttributeIdx();
662 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
663 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000664 fHWGeometryState.fVertexOffset = vertexOffset;
665 }
666
667 for (int t = 0; t < kMaxTexCoords; ++t) {
668 if (newTexCoordOffsets[t] > 0) {
669 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000670 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000671 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000672 GR_GL(EnableVertexAttribArray(idx));
673 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
674 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000675 } else if (posAndTexChange ||
676 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000677 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
678 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000679 }
680 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000681 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000682 }
683 }
684
685 if (newColorOffset > 0) {
686 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000687 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000688 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000689 GR_GL(EnableVertexAttribArray(idx));
690 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000691 true, newStride, colorOffset));
692 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000693 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000694 true, newStride, colorOffset));
695 }
696 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000697 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000698 }
699
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000700 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000701 fHWGeometryState.fArrayPtrsDirty = false;
702}
703
704void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000705 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000706
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000707 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000708 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000709
710 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
711
712 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
713 // fColorType records how colors are specified for the program. Strip
714 // the bit from the layout to avoid false negatives when searching for an
715 // existing program in the cache.
716 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
717
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000718 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
719
junov@google.comf93e7172011-03-31 21:26:24 +0000720#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000721 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000722 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000723 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000724#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000725#if GR_GL_NO_CONSTANT_ATTRIBUTES
726 if (!requiresAttributeColors) {
727 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
728 } else
729#endif
730 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000731 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000732 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
733 }
junov@google.comf93e7172011-03-31 21:26:24 +0000734
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000735 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000736 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000737
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000738 int lastEnabledStage = -1;
739
junov@google.comf93e7172011-03-31 21:26:24 +0000740 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000741 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000742
tomhudson@google.com0d831722011-06-02 15:37:14 +0000743 stage.fOptFlags = 0;
744 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000745
tomhudson@google.com0d831722011-06-02 15:37:14 +0000746 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000747 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000748 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
749 GrAssert(NULL != texture);
750 // we matrix to invert when orientation is TopDown, so make sure
751 // we aren't in that case before flagging as identity.
752 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000753 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000754 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000755 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000756 }
757 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000758 case GrSamplerState::kNormal_SampleMode:
759 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
760 break;
761 case GrSamplerState::kRadial_SampleMode:
762 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
763 break;
764 case GrSamplerState::kRadial2_SampleMode:
765 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
766 break;
767 case GrSamplerState::kSweep_SampleMode:
768 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
769 break;
770 default:
771 GrCrash("Unexpected sample mode!");
772 break;
773 }
774
775 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
776 // these both can use a regular texture2D()
777 case GrSamplerState::kNearest_Filter:
778 case GrSamplerState::kBilinear_Filter:
779 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
780 break;
781 // performs 4 texture2D()s
782 case GrSamplerState::k4x4Downsample_Filter:
783 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
784 break;
785 default:
786 GrCrash("Unexpected filter!");
787 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000788 }
789
junov@google.com6acc9b32011-05-16 18:32:07 +0000790 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000791 GrAssert(GrSamplerState::kClamp_WrapMode ==
792 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000793 GrSamplerState::kClamp_WrapMode ==
794 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000795 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000796 GrGLProgram::ProgramDesc::StageDesc::
797 kCustomTextureDomain_OptFlagBit;
798 }
799
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000800 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000801 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
802 } else {
803 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
804 }
junov@google.comf93e7172011-03-31 21:26:24 +0000805 } else {
806 stage.fOptFlags = 0;
807 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
808 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000809 }
810 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000811
812 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
813 // use canonical value when coverage/color distinction won't affect
814 // generated code to prevent duplicate programs.
815 desc.fFirstCoverageStage = kNumStages;
816 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
817 // color filter is applied between color/coverage computation
818 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
819 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
820 }
821
822 // We could consider cases where the final color is solid (0xff alpha)
823 // and the dst coeff can correctly be set to a non-dualsrc gl value.
824 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
825 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
826 // kOne).
827 if (fDualSourceBlendingSupport) {
828 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
829 // write the coverage value to second color
830 desc.fDualSrcOutput =
831 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
832 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
833 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
834 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
835 // cover
836 desc.fDualSrcOutput =
837 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
838 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
839 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
840 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
841 // cover
842 desc.fDualSrcOutput =
843 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
844 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
845 }
846 }
847 }
junov@google.comf93e7172011-03-31 21:26:24 +0000848}