blob: 1309802f818eaf452509f7b5d5e3f6f930be1010 [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
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000137void GrGpuGLShaders::DeleteProgram(CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000138 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.com1e257a52011-07-06 19:52:16 +0000144////////////////////////////////////////////////////////////////////////////////
145
146namespace {
147 template <typename T>
148 T random_val(GrRandom* r, T count) {
149 return (T)(int)(r->nextF() * count);
150 }
151};
152
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000153void GrGpuGLShaders::ProgramUnitTest() {
154
155 static const int STAGE_OPTS[] = {
156 0,
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000157 StageDesc::kNoPerspective_OptFlagBit,
158 StageDesc::kIdentity_CoordMapping
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000159 };
160 GrGLProgram program;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000161 ProgramDesc& pdesc = program.fProgramDesc;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000162
163 static const int NUM_TESTS = 512;
164
165 // GrRandoms nextU() values have patterns in the low bits
166 // So using nextU() % array_count might never take some values.
167 GrRandom random;
168 for (int t = 0; t < NUM_TESTS; ++t) {
169
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000170#if 0
171 GrPrintf("\nTest Program %d\n-------------\n", t);
172 static const int stop = -1;
173 if (t == stop) {
174 int breakpointhere = 9;
175 }
176#endif
177
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000178 pdesc.fVertexLayout = 0;
179 pdesc.fEmitsPointSize = random.nextF() > .5f;
180 float colorType = random.nextF();
181 if (colorType < 1.f / 3.f) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000182 pdesc.fColorType = ProgramDesc::kAttribute_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000183 } else if (colorType < 2.f / 3.f) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000184 pdesc.fColorType = ProgramDesc::kUniform_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000185 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000186 pdesc.fColorType = ProgramDesc::kNone_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000187 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000188
189 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
190 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
191
192 idx = (int)(random.nextF() * (kNumStages+1));
193 pdesc.fFirstCoverageStage = idx;
194
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000195 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000196 pdesc.fEdgeAAConcave = random.nextF() > .5f;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000197
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000198 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000199 pdesc.fDualSrcOutput =
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000200 (ProgramDesc::DualSrcOutput)
201 (int)(random.nextF() * ProgramDesc::kDualSrcOutputCnt);
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000202 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000203 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000204 }
205
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000206 for (int s = 0; s < kNumStages; ++s) {
207 // enable the stage?
208 if (random.nextF() > .5f) {
209 // use separate tex coords?
210 if (random.nextF() > .5f) {
211 int t = (int)(random.nextF() * kMaxTexCoords);
212 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
213 } else {
214 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
215 }
216 }
217 // use text-formatted verts?
218 if (random.nextF() > .5f) {
219 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
220 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000221 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000222 StageDesc& stage = pdesc.fStages[s];
223 stage.fOptFlags = STAGE_OPTS[idx];
224 stage.fModulation = random_val(&random, StageDesc::kModulationCnt);
225 stage.fCoordMapping = random_val(&random, StageDesc::kCoordMappingCnt);
226 stage.fFetchMode = random_val(&random, StageDesc::kFetchModeCnt);
227 stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000228 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000229 CachedData cachedData;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000230 program.genProgram(&cachedData);
231 DeleteProgram(&cachedData);
232 bool again = false;
233 if (again) {
234 program.genProgram(&cachedData);
235 DeleteProgram(&cachedData);
236 }
237 }
238}
239
junov@google.comf93e7172011-03-31 21:26:24 +0000240GrGpuGLShaders::GrGpuGLShaders() {
241
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000242 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000243
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000244 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000245 if (GR_GL_SUPPORT_DESKTOP) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000246 fDualSourceBlendingSupport =
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000247 fGLVersion >= 3.3f ||
248 this->hasExtension("GL_ARB_blend_func_extended");
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000249 } else {
250 fDualSourceBlendingSupport = false;
251 }
junov@google.comf93e7172011-03-31 21:26:24 +0000252
253 fProgramData = NULL;
254 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000255
256#if 0
257 ProgramUnitTest();
258#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000259}
260
261GrGpuGLShaders::~GrGpuGLShaders() {
262 delete fProgramCache;
263}
264
265const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000266 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000267
268 if (GrGLProgram::kSetAsAttribute ==
269 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
270 return fHWDrawState.fSamplerStates[stage].getMatrix();
271 } else {
272 return fProgramData->fTextureMatrices[stage];
273 }
junov@google.comf93e7172011-03-31 21:26:24 +0000274}
275
276void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000277 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000278 if (GrGLProgram::kSetAsAttribute ==
279 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
280 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
281 } else {
282 fProgramData->fTextureMatrices[stage] = matrix;
283 }
junov@google.comf93e7172011-03-31 21:26:24 +0000284}
285
286void GrGpuGLShaders::resetContext() {
287 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000288
junov@google.comf93e7172011-03-31 21:26:24 +0000289 fHWGeometryState.fVertexLayout = 0;
290 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000291 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000292 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000293 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000294 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000295 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000296
297 fHWProgramID = 0;
298}
299
300void GrGpuGLShaders::flushViewMatrix() {
301 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000302 GrMatrix m;
303 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000304 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
305 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
306 0, 0, GrMatrix::I()[8]);
307 m.setConcat(m, fCurrDrawState.fViewMatrix);
308
309 // ES doesn't allow you to pass true to the transpose param,
310 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000311 GrGLfloat mt[] = {
312 GrScalarToFloat(m[GrMatrix::kMScaleX]),
313 GrScalarToFloat(m[GrMatrix::kMSkewY]),
314 GrScalarToFloat(m[GrMatrix::kMPersp0]),
315 GrScalarToFloat(m[GrMatrix::kMSkewX]),
316 GrScalarToFloat(m[GrMatrix::kMScaleY]),
317 GrScalarToFloat(m[GrMatrix::kMPersp1]),
318 GrScalarToFloat(m[GrMatrix::kMTransX]),
319 GrScalarToFloat(m[GrMatrix::kMTransY]),
320 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000321 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000322
323 if (GrGLProgram::kSetAsAttribute ==
324 fProgramData->fUniLocations.fViewMatrixUni) {
325 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
326 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
327 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
328 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
329 } else {
330 GrAssert(GrGLProgram::kUnusedUniform !=
331 fProgramData->fUniLocations.fViewMatrixUni);
332 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
333 1, false, mt));
334 }
junov@google.comf93e7172011-03-31 21:26:24 +0000335}
336
junov@google.com6acc9b32011-05-16 18:32:07 +0000337void GrGpuGLShaders::flushTextureDomain(int s) {
338 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
339 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000340 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000341 fCurrDrawState.fSamplerStates[s].getTextureDomain();
342
twiz@google.com76b82742011-06-02 20:30:02 +0000343 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
344 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000345
junov@google.com2f839402011-05-24 15:13:01 +0000346 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000347
junov@google.com2f839402011-05-24 15:13:01 +0000348 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000349 GrScalarToFloat(texDom.left()),
350 GrScalarToFloat(texDom.top()),
351 GrScalarToFloat(texDom.right()),
352 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000353 };
354
355 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
356 GrGLTexture::Orientation orientation = texture->orientation();
357
358 // vertical flip if necessary
359 if (GrGLTexture::kBottomUp_Orientation == orientation) {
360 values[1] = 1.0f - values[1];
361 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000362 // The top and bottom were just flipped, so correct the ordering
363 // of elements so that values = (l, t, r, b).
364 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000365 }
366
367 values[0] *= SkScalarToFloat(texture->contentScaleX());
368 values[2] *= SkScalarToFloat(texture->contentScaleX());
369 values[1] *= SkScalarToFloat(texture->contentScaleY());
370 values[3] *= SkScalarToFloat(texture->contentScaleY());
371
372 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000373 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000374 }
375}
376
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000377void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000378 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000379 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
380 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000381 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000382 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
383 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000384
bsalomon@google.com91961302011-05-09 18:39:58 +0000385 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000386
bsalomon@google.com91961302011-05-09 18:39:58 +0000387 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000388
bsalomon@google.com91961302011-05-09 18:39:58 +0000389 GrMatrix m = getSamplerMatrix(s);
390 GrSamplerState::SampleMode mode =
391 fCurrDrawState.fSamplerStates[s].getSampleMode();
392 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000393
bsalomon@google.com91961302011-05-09 18:39:58 +0000394 // ES doesn't allow you to pass true to the transpose param,
395 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000396 GrGLfloat mt[] = {
397 GrScalarToFloat(m[GrMatrix::kMScaleX]),
398 GrScalarToFloat(m[GrMatrix::kMSkewY]),
399 GrScalarToFloat(m[GrMatrix::kMPersp0]),
400 GrScalarToFloat(m[GrMatrix::kMSkewX]),
401 GrScalarToFloat(m[GrMatrix::kMScaleY]),
402 GrScalarToFloat(m[GrMatrix::kMPersp1]),
403 GrScalarToFloat(m[GrMatrix::kMTransX]),
404 GrScalarToFloat(m[GrMatrix::kMTransY]),
405 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000406 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000407
bsalomon@google.com91961302011-05-09 18:39:58 +0000408 if (GrGLProgram::kSetAsAttribute ==
409 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
410 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
411 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
412 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
413 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
414 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000415 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000416 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000417 recordHWSamplerMatrix(s, getSamplerMatrix(s));
418 }
419 }
junov@google.comf93e7172011-03-31 21:26:24 +0000420}
421
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000422void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000423
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000424 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
425 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000426 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000427 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
428 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
429 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000430
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000431 GrScalar centerX1 = sampler.getRadial2CenterX1();
432 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000435
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000436 // when were in the degenerate (linear) case the second
437 // value will be INF but the program doesn't read it. (We
438 // use the same 6 uniforms even though we don't need them
439 // all in the linear case just to keep the code complexity
440 // down).
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 float values[6] = {
442 GrScalarToFloat(a),
443 1 / (2.f * values[0]),
444 GrScalarToFloat(centerX1),
445 GrScalarToFloat(radius0),
446 GrScalarToFloat(GrMul(radius0, radius0)),
447 sampler.isRadial2PosRoot() ? 1.f : -1.f
448 };
449 GR_GL(Uniform1fv(uni, 6, values));
450 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
451 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
452 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
453 }
454}
455
456void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000457 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000458 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000459 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
460 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
461 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
462
463 float texelSize[] = {1.f / texture->allocWidth(),
464 1.f / texture->allocHeight()};
465 GR_GL(Uniform2fv(uni, 1, texelSize));
466 }
467 }
junov@google.comf93e7172011-03-31 21:26:24 +0000468}
469
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000470void GrGpuGLShaders::flushEdgeAAData() {
471 const int& uni = fProgramData->fUniLocations.fEdgesUni;
472 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000473 int count = fCurrDrawState.fEdgeAANumEdges;
474 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000475 // Flip the edges in Y
476 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000477 for (int i = 0; i < count; ++i) {
478 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
479 float b = edges[i].fY;
480 edges[i].fY = -b;
481 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000482 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000483 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000484 }
485}
486
Scroggo01b87ec2011-05-11 18:05:38 +0000487static const float ONE_OVER_255 = 1.f / 255.f;
488
489#define GR_COLOR_TO_VEC4(color) {\
490 GrColorUnpackR(color) * ONE_OVER_255,\
491 GrColorUnpackG(color) * ONE_OVER_255,\
492 GrColorUnpackB(color) * ONE_OVER_255,\
493 GrColorUnpackA(color) * ONE_OVER_255 \
494}
495
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000496void GrGpuGLShaders::flushColor() {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000497 const ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000498 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000499 // color will be specified per-vertex as an attribute
500 // invalidate the const vertex attrib color
501 fHWDrawState.fColor = GrColor_ILLEGAL;
502 } else {
503 switch (desc.fColorType) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000504 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000505 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
506 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000507 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000508 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000509 fHWDrawState.fColor = fCurrDrawState.fColor;
510 }
511 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000512 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000513 if (fProgramData->fColor != fCurrDrawState.fColor) {
514 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000515 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000516 GrAssert(GrGLProgram::kUnusedUniform !=
517 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000518 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
519 fProgramData->fColor = fCurrDrawState.fColor;
520 }
521 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000522 case ProgramDesc::kNone_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000523 GrAssert(0xffffffff == fCurrDrawState.fColor);
524 break;
525 default:
526 GrCrash("Unknown color type.");
527 }
528 }
Scroggo97c88c22011-05-11 14:05:25 +0000529 if (fProgramData->fUniLocations.fColorFilterUni
530 != GrGLProgram::kUnusedUniform
531 && fProgramData->fColorFilterColor
532 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000533 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000534 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
535 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
536 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000537}
538
539
junov@google.comf93e7172011-03-31 21:26:24 +0000540bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
541 if (!flushGLStateCommon(type)) {
542 return false;
543 }
544
545 if (fDirtyFlags.fRenderTargetChanged) {
546 // our coords are in pixel space and the GL matrices map to NDC
547 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000548 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000549 // we assume all shader matrices may be wrong after viewport changes
550 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000551 }
552
junov@google.comf93e7172011-03-31 21:26:24 +0000553 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000554 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000555 if (NULL == fProgramData) {
556 GrAssert(!"Failed to create program!");
557 return false;
558 }
junov@google.comf93e7172011-03-31 21:26:24 +0000559
560 if (fHWProgramID != fProgramData->fProgramID) {
561 GR_GL(UseProgram(fProgramData->fProgramID));
562 fHWProgramID = fProgramData->fProgramID;
563 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000564 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
565 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
566
567 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
568 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000569
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000570 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000571
bsalomon@google.com91961302011-05-09 18:39:58 +0000572 GrMatrix* currViewMatrix;
573 if (GrGLProgram::kSetAsAttribute ==
574 fProgramData->fUniLocations.fViewMatrixUni) {
575 currViewMatrix = &fHWDrawState.fViewMatrix;
576 } else {
577 currViewMatrix = &fProgramData->fViewMatrix;
578 }
junov@google.comf93e7172011-03-31 21:26:24 +0000579
bsalomon@google.com91961302011-05-09 18:39:58 +0000580 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000581 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000582 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000583 }
584
585 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000586 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000587
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000588 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000589
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000590 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000591
592 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000593 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000594 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000595 resetDirtyFlags();
596 return true;
597}
598
599void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000600}
601
602void GrGpuGLShaders::setupGeometry(int* startVertex,
603 int* startIndex,
604 int vertexCount,
605 int indexCount) {
606
607 int newColorOffset;
608 int newTexCoordOffsets[kMaxTexCoords];
609
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000610 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
611 this->getGeomSrc().fVertexLayout,
612 newTexCoordOffsets,
613 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000614 int oldColorOffset;
615 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000616 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
617 fHWGeometryState.fVertexLayout,
618 oldTexCoordOffsets,
619 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000620 bool indexed = NULL != startIndex;
621
622 int extraVertexOffset;
623 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000624 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000625
626 GrGLenum scalarType;
627 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000628 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000629 scalarType = GrGLTextType;
630 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
631 } else {
632 scalarType = GrGLType;
633 texCoordNorm = false;
634 }
635
636 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
637 *startVertex = 0;
638 if (indexed) {
639 *startIndex += extraIndexOffset;
640 }
641
642 // all the Pointers must be set if any of these are true
643 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
644 vertexOffset != fHWGeometryState.fVertexOffset ||
645 newStride != oldStride;
646
647 // position and tex coord offsets change if above conditions are true
648 // or the type/normalization changed based on text vs nontext type coords.
649 bool posAndTexChange = allOffsetsChange ||
650 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
651 (kTextFormat_VertexLayoutBit &
652 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000653 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000654
655 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000656 int idx = GrGLProgram::PositionAttributeIdx();
657 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
658 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000659 fHWGeometryState.fVertexOffset = vertexOffset;
660 }
661
662 for (int t = 0; t < kMaxTexCoords; ++t) {
663 if (newTexCoordOffsets[t] > 0) {
664 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000665 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000666 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000667 GR_GL(EnableVertexAttribArray(idx));
668 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
669 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000670 } else if (posAndTexChange ||
671 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000672 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
673 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000674 }
675 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000676 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000677 }
678 }
679
680 if (newColorOffset > 0) {
681 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000682 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000683 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000684 GR_GL(EnableVertexAttribArray(idx));
685 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000686 true, newStride, colorOffset));
687 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000688 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000689 true, newStride, colorOffset));
690 }
691 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000692 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000693 }
694
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000695 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000696 fHWGeometryState.fArrayPtrsDirty = false;
697}
698
699void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000700 ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000701
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000702 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000703 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000704
705 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
706
707 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
708 // fColorType records how colors are specified for the program. Strip
709 // the bit from the layout to avoid false negatives when searching for an
710 // existing program in the cache.
711 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
712
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000713 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
714
junov@google.comf93e7172011-03-31 21:26:24 +0000715#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000716 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000717 desc.fColorType = ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000718 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000719#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000720#if GR_GL_NO_CONSTANT_ATTRIBUTES
721 if (!requiresAttributeColors) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000722 desc.fColorType = ProgramDesc::kUniform_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000723 } else
724#endif
725 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000726 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000727 desc.fColorType = ProgramDesc::kAttribute_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000728 }
junov@google.comf93e7172011-03-31 21:26:24 +0000729
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000730 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000731 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000732
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000733 int lastEnabledStage = -1;
734
junov@google.comf93e7172011-03-31 21:26:24 +0000735 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000736 StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000737
tomhudson@google.com0d831722011-06-02 15:37:14 +0000738 stage.fOptFlags = 0;
739 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000740
tomhudson@google.com0d831722011-06-02 15:37:14 +0000741 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000742 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000743 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
744 GrAssert(NULL != texture);
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000745 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000746 // we matrix to invert when orientation is TopDown, so make sure
747 // we aren't in that case before flagging as identity.
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000748 if (TextureMatrixIsIdentity(texture, sampler)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000749 stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000750 } else if (!getSamplerMatrix(s).hasPerspective()) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000751 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000752 }
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000753 switch (sampler.getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000754 case GrSamplerState::kNormal_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000755 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000756 break;
757 case GrSamplerState::kRadial_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000758 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000759 break;
760 case GrSamplerState::kRadial2_SampleMode:
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000761 if (sampler.radial2IsDegenerate()) {
762 stage.fCoordMapping =
763 StageDesc::kRadial2GradientDegenerate_CoordMapping;
764 } else {
765 stage.fCoordMapping =
766 StageDesc::kRadial2Gradient_CoordMapping;
767 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000768 break;
769 case GrSamplerState::kSweep_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000770 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000771 break;
772 default:
773 GrCrash("Unexpected sample mode!");
774 break;
775 }
776
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000777 switch (sampler.getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000778 // these both can use a regular texture2D()
779 case GrSamplerState::kNearest_Filter:
780 case GrSamplerState::kBilinear_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000781 stage.fFetchMode = StageDesc::kSingle_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000782 break;
783 // performs 4 texture2D()s
784 case GrSamplerState::k4x4Downsample_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000785 stage.fFetchMode = StageDesc::k2x2_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000786 break;
787 default:
788 GrCrash("Unexpected filter!");
789 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000790 }
791
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000792 if (sampler.hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000793 GrAssert(GrSamplerState::kClamp_WrapMode ==
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000794 sampler.getWrapX() &&
795 GrSamplerState::kClamp_WrapMode ==
796 sampler.getWrapY());
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000797 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
junov@google.com6acc9b32011-05-16 18:32:07 +0000798 }
799
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000800 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000801 stage.fModulation = StageDesc::kAlpha_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000802 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000803 stage.fModulation = StageDesc::kColor_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000804 }
junov@google.comf93e7172011-03-31 21:26:24 +0000805 } else {
806 stage.fOptFlags = 0;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000807 stage.fCoordMapping = (StageDesc::CoordMapping)0;
808 stage.fModulation = (StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000809 }
810 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000811
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000812 desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000813 // 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
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000830 desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000831 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
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000835 desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000836 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
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000840 desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000841 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
842 }
843 }
844 }
junov@google.comf93e7172011-03-31 21:26:24 +0000845}