blob: 13f7543ae585dd4b2ce05e2a7cc1fa5ecc0fa6b8 [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
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000252 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000253 if (GR_GL_SUPPORT_DESKTOP) {
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000254 fDualSourceBlendingSupport =
255 fGLVersion >= 3.3f ||
256 this->hasExtension("GL_ARB_blend_func_extended");
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000257 } else {
258 fDualSourceBlendingSupport = false;
259 }
junov@google.comf93e7172011-03-31 21:26:24 +0000260
261 fProgramData = NULL;
262 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000263
264#if 0
265 ProgramUnitTest();
266#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000267}
268
269GrGpuGLShaders::~GrGpuGLShaders() {
270 delete fProgramCache;
271}
272
273const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000274 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000275
276 if (GrGLProgram::kSetAsAttribute ==
277 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
278 return fHWDrawState.fSamplerStates[stage].getMatrix();
279 } else {
280 return fProgramData->fTextureMatrices[stage];
281 }
junov@google.comf93e7172011-03-31 21:26:24 +0000282}
283
284void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000285 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000286 if (GrGLProgram::kSetAsAttribute ==
287 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
288 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
289 } else {
290 fProgramData->fTextureMatrices[stage] = matrix;
291 }
junov@google.comf93e7172011-03-31 21:26:24 +0000292}
293
294void GrGpuGLShaders::resetContext() {
295 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000296
junov@google.comf93e7172011-03-31 21:26:24 +0000297 fHWGeometryState.fVertexLayout = 0;
298 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000299 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000300 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000301 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000302 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000303 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000304
305 fHWProgramID = 0;
306}
307
308void GrGpuGLShaders::flushViewMatrix() {
309 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000310 GrMatrix m;
311 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000312 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
313 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
314 0, 0, GrMatrix::I()[8]);
315 m.setConcat(m, fCurrDrawState.fViewMatrix);
316
317 // ES doesn't allow you to pass true to the transpose param,
318 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000319 GrGLfloat mt[] = {
320 GrScalarToFloat(m[GrMatrix::kMScaleX]),
321 GrScalarToFloat(m[GrMatrix::kMSkewY]),
322 GrScalarToFloat(m[GrMatrix::kMPersp0]),
323 GrScalarToFloat(m[GrMatrix::kMSkewX]),
324 GrScalarToFloat(m[GrMatrix::kMScaleY]),
325 GrScalarToFloat(m[GrMatrix::kMPersp1]),
326 GrScalarToFloat(m[GrMatrix::kMTransX]),
327 GrScalarToFloat(m[GrMatrix::kMTransY]),
328 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000329 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000330
331 if (GrGLProgram::kSetAsAttribute ==
332 fProgramData->fUniLocations.fViewMatrixUni) {
333 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
334 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
335 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
336 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
337 } else {
338 GrAssert(GrGLProgram::kUnusedUniform !=
339 fProgramData->fUniLocations.fViewMatrixUni);
340 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
341 1, false, mt));
342 }
junov@google.comf93e7172011-03-31 21:26:24 +0000343}
344
junov@google.com6acc9b32011-05-16 18:32:07 +0000345void GrGpuGLShaders::flushTextureDomain(int s) {
346 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
347 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000348 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000349 fCurrDrawState.fSamplerStates[s].getTextureDomain();
350
twiz@google.com76b82742011-06-02 20:30:02 +0000351 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
352 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000353
junov@google.com2f839402011-05-24 15:13:01 +0000354 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000355
junov@google.com2f839402011-05-24 15:13:01 +0000356 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000357 GrScalarToFloat(texDom.left()),
358 GrScalarToFloat(texDom.top()),
359 GrScalarToFloat(texDom.right()),
360 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000361 };
362
363 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
364 GrGLTexture::Orientation orientation = texture->orientation();
365
366 // vertical flip if necessary
367 if (GrGLTexture::kBottomUp_Orientation == orientation) {
368 values[1] = 1.0f - values[1];
369 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000370 // The top and bottom were just flipped, so correct the ordering
371 // of elements so that values = (l, t, r, b).
372 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000373 }
374
375 values[0] *= SkScalarToFloat(texture->contentScaleX());
376 values[2] *= SkScalarToFloat(texture->contentScaleX());
377 values[1] *= SkScalarToFloat(texture->contentScaleY());
378 values[3] *= SkScalarToFloat(texture->contentScaleY());
379
380 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000381 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000382 }
383}
384
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000385void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000386 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000387 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
388 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000389 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000390 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
391 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000392
bsalomon@google.com91961302011-05-09 18:39:58 +0000393 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000394
bsalomon@google.com91961302011-05-09 18:39:58 +0000395 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000396
bsalomon@google.com91961302011-05-09 18:39:58 +0000397 GrMatrix m = getSamplerMatrix(s);
398 GrSamplerState::SampleMode mode =
399 fCurrDrawState.fSamplerStates[s].getSampleMode();
400 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000401
bsalomon@google.com91961302011-05-09 18:39:58 +0000402 // ES doesn't allow you to pass true to the transpose param,
403 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000404 GrGLfloat mt[] = {
405 GrScalarToFloat(m[GrMatrix::kMScaleX]),
406 GrScalarToFloat(m[GrMatrix::kMSkewY]),
407 GrScalarToFloat(m[GrMatrix::kMPersp0]),
408 GrScalarToFloat(m[GrMatrix::kMSkewX]),
409 GrScalarToFloat(m[GrMatrix::kMScaleY]),
410 GrScalarToFloat(m[GrMatrix::kMPersp1]),
411 GrScalarToFloat(m[GrMatrix::kMTransX]),
412 GrScalarToFloat(m[GrMatrix::kMTransY]),
413 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000414 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000415
bsalomon@google.com91961302011-05-09 18:39:58 +0000416 if (GrGLProgram::kSetAsAttribute ==
417 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
418 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
419 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
420 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
421 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
422 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000423 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000424 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000425 recordHWSamplerMatrix(s, getSamplerMatrix(s));
426 }
427 }
junov@google.comf93e7172011-03-31 21:26:24 +0000428}
429
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000430void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000431
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000432 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
433 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000434 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000435 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
436 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
437 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000438
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 GrScalar centerX1 = sampler.getRadial2CenterX1();
440 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000441
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000442 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000443
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000444 float values[6] = {
445 GrScalarToFloat(a),
446 1 / (2.f * values[0]),
447 GrScalarToFloat(centerX1),
448 GrScalarToFloat(radius0),
449 GrScalarToFloat(GrMul(radius0, radius0)),
450 sampler.isRadial2PosRoot() ? 1.f : -1.f
451 };
452 GR_GL(Uniform1fv(uni, 6, values));
453 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
454 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
455 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
456 }
457}
458
459void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000460 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000461 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000462 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
463 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
464 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
465
466 float texelSize[] = {1.f / texture->allocWidth(),
467 1.f / texture->allocHeight()};
468 GR_GL(Uniform2fv(uni, 1, texelSize));
469 }
470 }
junov@google.comf93e7172011-03-31 21:26:24 +0000471}
472
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000473void GrGpuGLShaders::flushEdgeAAData() {
474 const int& uni = fProgramData->fUniLocations.fEdgesUni;
475 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000476 int count = fCurrDrawState.fEdgeAANumEdges;
477 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000478 // Flip the edges in Y
479 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000480 for (int i = 0; i < count; ++i) {
481 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
482 float b = edges[i].fY;
483 edges[i].fY = -b;
484 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000485 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000486 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000487 }
488}
489
Scroggo01b87ec2011-05-11 18:05:38 +0000490static const float ONE_OVER_255 = 1.f / 255.f;
491
492#define GR_COLOR_TO_VEC4(color) {\
493 GrColorUnpackR(color) * ONE_OVER_255,\
494 GrColorUnpackG(color) * ONE_OVER_255,\
495 GrColorUnpackB(color) * ONE_OVER_255,\
496 GrColorUnpackA(color) * ONE_OVER_255 \
497}
498
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000499void GrGpuGLShaders::flushColor() {
500 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000501 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000502 // color will be specified per-vertex as an attribute
503 // invalidate the const vertex attrib color
504 fHWDrawState.fColor = GrColor_ILLEGAL;
505 } else {
506 switch (desc.fColorType) {
507 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
508 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
509 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000510 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000511 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000512 fHWDrawState.fColor = fCurrDrawState.fColor;
513 }
514 break;
515 case GrGLProgram::ProgramDesc::kUniform_ColorType:
516 if (fProgramData->fColor != fCurrDrawState.fColor) {
517 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000518 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000519 GrAssert(GrGLProgram::kUnusedUniform !=
520 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000521 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
522 fProgramData->fColor = fCurrDrawState.fColor;
523 }
524 break;
525 case GrGLProgram::ProgramDesc::kNone_ColorType:
526 GrAssert(0xffffffff == fCurrDrawState.fColor);
527 break;
528 default:
529 GrCrash("Unknown color type.");
530 }
531 }
Scroggo97c88c22011-05-11 14:05:25 +0000532 if (fProgramData->fUniLocations.fColorFilterUni
533 != GrGLProgram::kUnusedUniform
534 && fProgramData->fColorFilterColor
535 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000536 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000537 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
538 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
539 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000540}
541
542
junov@google.comf93e7172011-03-31 21:26:24 +0000543bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
544 if (!flushGLStateCommon(type)) {
545 return false;
546 }
547
548 if (fDirtyFlags.fRenderTargetChanged) {
549 // our coords are in pixel space and the GL matrices map to NDC
550 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000551 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000552 // we assume all shader matrices may be wrong after viewport changes
553 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000554 }
555
junov@google.comf93e7172011-03-31 21:26:24 +0000556 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000557 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000558 if (NULL == fProgramData) {
559 GrAssert(!"Failed to create program!");
560 return false;
561 }
junov@google.comf93e7172011-03-31 21:26:24 +0000562
563 if (fHWProgramID != fProgramData->fProgramID) {
564 GR_GL(UseProgram(fProgramData->fProgramID));
565 fHWProgramID = fProgramData->fProgramID;
566 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000567 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
568 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
569
570 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
571 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000572
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000573 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000574
bsalomon@google.com91961302011-05-09 18:39:58 +0000575 GrMatrix* currViewMatrix;
576 if (GrGLProgram::kSetAsAttribute ==
577 fProgramData->fUniLocations.fViewMatrixUni) {
578 currViewMatrix = &fHWDrawState.fViewMatrix;
579 } else {
580 currViewMatrix = &fProgramData->fViewMatrix;
581 }
junov@google.comf93e7172011-03-31 21:26:24 +0000582
bsalomon@google.com91961302011-05-09 18:39:58 +0000583 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000584 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000585 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000586 }
587
588 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000589 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000590
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000591 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000592
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000593 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000594
595 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000596 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000597 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000598 resetDirtyFlags();
599 return true;
600}
601
602void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000603}
604
605void GrGpuGLShaders::setupGeometry(int* startVertex,
606 int* startIndex,
607 int vertexCount,
608 int indexCount) {
609
610 int newColorOffset;
611 int newTexCoordOffsets[kMaxTexCoords];
612
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000613 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
614 this->getGeomSrc().fVertexLayout,
615 newTexCoordOffsets,
616 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000617 int oldColorOffset;
618 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000619 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
620 fHWGeometryState.fVertexLayout,
621 oldTexCoordOffsets,
622 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000623 bool indexed = NULL != startIndex;
624
625 int extraVertexOffset;
626 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000627 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000628
629 GrGLenum scalarType;
630 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000631 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000632 scalarType = GrGLTextType;
633 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
634 } else {
635 scalarType = GrGLType;
636 texCoordNorm = false;
637 }
638
639 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
640 *startVertex = 0;
641 if (indexed) {
642 *startIndex += extraIndexOffset;
643 }
644
645 // all the Pointers must be set if any of these are true
646 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
647 vertexOffset != fHWGeometryState.fVertexOffset ||
648 newStride != oldStride;
649
650 // position and tex coord offsets change if above conditions are true
651 // or the type/normalization changed based on text vs nontext type coords.
652 bool posAndTexChange = allOffsetsChange ||
653 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
654 (kTextFormat_VertexLayoutBit &
655 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000656 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000657
658 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000659 int idx = GrGLProgram::PositionAttributeIdx();
660 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
661 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000662 fHWGeometryState.fVertexOffset = vertexOffset;
663 }
664
665 for (int t = 0; t < kMaxTexCoords; ++t) {
666 if (newTexCoordOffsets[t] > 0) {
667 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000668 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000669 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000670 GR_GL(EnableVertexAttribArray(idx));
671 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
672 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000673 } else if (posAndTexChange ||
674 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000675 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
676 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000677 }
678 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000679 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000680 }
681 }
682
683 if (newColorOffset > 0) {
684 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000685 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000686 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000687 GR_GL(EnableVertexAttribArray(idx));
688 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000689 true, newStride, colorOffset));
690 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000691 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000692 true, newStride, colorOffset));
693 }
694 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000695 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000696 }
697
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000698 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000699 fHWGeometryState.fArrayPtrsDirty = false;
700}
701
702void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000703 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000704
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000705 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000706 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000707
708 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
709
710 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
711 // fColorType records how colors are specified for the program. Strip
712 // the bit from the layout to avoid false negatives when searching for an
713 // existing program in the cache.
714 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
715
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000716 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
717
junov@google.comf93e7172011-03-31 21:26:24 +0000718#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000719 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000720 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000721 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000722#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000723#if GR_GL_NO_CONSTANT_ATTRIBUTES
724 if (!requiresAttributeColors) {
725 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
726 } else
727#endif
728 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000729 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000730 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
731 }
junov@google.comf93e7172011-03-31 21:26:24 +0000732
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000733 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000734 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000735
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000736 int lastEnabledStage = -1;
737
junov@google.comf93e7172011-03-31 21:26:24 +0000738 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000739 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000740
tomhudson@google.com0d831722011-06-02 15:37:14 +0000741 stage.fOptFlags = 0;
742 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000743
tomhudson@google.com0d831722011-06-02 15:37:14 +0000744 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000745 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000746 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
747 GrAssert(NULL != texture);
748 // we matrix to invert when orientation is TopDown, so make sure
749 // we aren't in that case before flagging as identity.
750 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000751 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000752 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000753 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000754 }
755 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000756 case GrSamplerState::kNormal_SampleMode:
757 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
758 break;
759 case GrSamplerState::kRadial_SampleMode:
760 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
761 break;
762 case GrSamplerState::kRadial2_SampleMode:
763 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
764 break;
765 case GrSamplerState::kSweep_SampleMode:
766 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
767 break;
768 default:
769 GrCrash("Unexpected sample mode!");
770 break;
771 }
772
773 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
774 // these both can use a regular texture2D()
775 case GrSamplerState::kNearest_Filter:
776 case GrSamplerState::kBilinear_Filter:
777 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
778 break;
779 // performs 4 texture2D()s
780 case GrSamplerState::k4x4Downsample_Filter:
781 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
782 break;
783 default:
784 GrCrash("Unexpected filter!");
785 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000786 }
787
junov@google.com6acc9b32011-05-16 18:32:07 +0000788 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000789 GrAssert(GrSamplerState::kClamp_WrapMode ==
790 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000791 GrSamplerState::kClamp_WrapMode ==
792 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000793 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000794 GrGLProgram::ProgramDesc::StageDesc::
795 kCustomTextureDomain_OptFlagBit;
796 }
797
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000798 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000799 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
800 } else {
801 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
802 }
junov@google.comf93e7172011-03-31 21:26:24 +0000803 } else {
804 stage.fOptFlags = 0;
805 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
806 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000807 }
808 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000809
810 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
811 // use canonical value when coverage/color distinction won't affect
812 // generated code to prevent duplicate programs.
813 desc.fFirstCoverageStage = kNumStages;
814 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
815 // color filter is applied between color/coverage computation
816 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
817 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
818 }
819
820 // We could consider cases where the final color is solid (0xff alpha)
821 // and the dst coeff can correctly be set to a non-dualsrc gl value.
822 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
823 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
824 // kOne).
825 if (fDualSourceBlendingSupport) {
826 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
827 // write the coverage value to second color
828 desc.fDualSrcOutput =
829 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
830 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
831 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
832 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
833 // cover
834 desc.fDualSrcOutput =
835 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
836 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
837 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
838 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
839 // cover
840 desc.fDualSrcOutput =
841 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
842 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
843 }
844 }
845 }
junov@google.comf93e7172011-03-31 21:26:24 +0000846}