blob: 0b8aad7655689f39e32547ecb44022e2cc5891b3 [file] [log] [blame]
junov@google.comf93e7172011-03-31 21:26:24 +00001/*
2 Copyright 2011 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrBinHashKey.h"
junov@google.comf93e7172011-03-31 21:26:24 +000018#include "GrGLProgram.h"
19#include "GrGpuGLShaders.h"
20#include "GrGpuVertex.h"
21#include "GrMemory.h"
22#include "GrNoncopyable.h"
23#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000024#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000025
junov@google.comf93e7172011-03-31 21:26:24 +000026#define SKIP_CACHE_CHECK true
27#define GR_UINT32_MAX static_cast<uint32_t>(-1)
28
junov@google.comf93e7172011-03-31 21:26:24 +000029#include "GrTHashCache.h"
30
31class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
32private:
33 class Entry;
34
35#if GR_DEBUG
36 typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
37#else
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +000038 typedef GrBinHashKey<Entry, 64> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000039#endif
40
41 class Entry : public ::GrNoncopyable {
42 public:
43 Entry() {}
junov@google.comf93e7172011-03-31 21:26:24 +000044 void copyAndTakeOwnership(Entry& entry) {
45 fProgramData.copyAndTakeOwnership(entry.fProgramData);
46 fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000047 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000048 }
49
50 public:
51 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
52
53 public:
54 GrGLProgram::CachedData fProgramData;
55 ProgramHashKey fKey;
56 unsigned int fLRUStamp;
57 };
58
59 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
60
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000061 // We may have kMaxEntries+1 shaders in the GL context because
62 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000063 enum {
64 kMaxEntries = 32
65 };
66 Entry fEntries[kMaxEntries];
67 int fCount;
68 unsigned int fCurrLRUStamp;
69
70public:
71 ProgramCache()
72 : fCount(0)
73 , fCurrLRUStamp(0) {
74 }
75
76 ~ProgramCache() {
77 for (int i = 0; i < fCount; ++i) {
78 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
79 }
80 }
81
82 void abandon() {
83 fCount = 0;
84 }
85
86 void invalidateViewMatrices() {
87 for (int i = 0; i < fCount; ++i) {
88 // set to illegal matrix
89 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
90 }
91 }
92
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000093 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000094 Entry newEntry;
95 while (newEntry.fKey.doPass()) {
96 desc.buildKey(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000097 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000098 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000099 if (NULL == entry) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000100 if (!desc.genProgram(&newEntry.fProgramData)) {
101 return NULL;
102 }
junov@google.comf93e7172011-03-31 21:26:24 +0000103 if (fCount < kMaxEntries) {
104 entry = fEntries + fCount;
105 ++fCount;
106 } else {
107 GrAssert(kMaxEntries == fCount);
108 entry = fEntries;
109 for (int i = 1; i < kMaxEntries; ++i) {
110 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
111 entry = fEntries + i;
112 }
113 }
114 fHashCache.remove(entry->fKey, entry);
115 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
116 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000117 entry->copyAndTakeOwnership(newEntry);
junov@google.comf93e7172011-03-31 21:26:24 +0000118 fHashCache.insert(entry->fKey, entry);
119 }
120
121 entry->fLRUStamp = fCurrLRUStamp;
122 if (GR_UINT32_MAX == fCurrLRUStamp) {
123 // wrap around! just trash our LRU, one time hit.
124 for (int i = 0; i < fCount; ++i) {
125 fEntries[i].fLRUStamp = 0;
126 }
127 }
128 ++fCurrLRUStamp;
129 return &entry->fProgramData;
130 }
131};
132
junov@google.com53a55842011-06-08 22:55:10 +0000133void GrGpuGLShaders::abandonResources(){
134 INHERITED::abandonResources();
135 fProgramCache->abandon();
136}
137
junov@google.comf93e7172011-03-31 21:26:24 +0000138void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
139 GR_GL(DeleteShader(programData->fVShaderID));
140 GR_GL(DeleteShader(programData->fFShaderID));
141 GR_GL(DeleteProgram(programData->fProgramID));
142 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
143}
144
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000145void GrGpuGLShaders::ProgramUnitTest() {
146
147 static const int STAGE_OPTS[] = {
148 0,
149 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
150 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
151 };
152 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
153 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
154 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
155 };
156 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
157 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
158 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
159 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
160 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
161 };
162 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
163 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
164 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
165 };
166 GrGLProgram program;
167 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
168
169 static const int NUM_TESTS = 512;
170
171 // GrRandoms nextU() values have patterns in the low bits
172 // So using nextU() % array_count might never take some values.
173 GrRandom random;
174 for (int t = 0; t < NUM_TESTS; ++t) {
175
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000176#if 0
177 GrPrintf("\nTest Program %d\n-------------\n", t);
178 static const int stop = -1;
179 if (t == stop) {
180 int breakpointhere = 9;
181 }
182#endif
183
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000184 pdesc.fVertexLayout = 0;
185 pdesc.fEmitsPointSize = random.nextF() > .5f;
186 float colorType = random.nextF();
187 if (colorType < 1.f / 3.f) {
188 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
189 } else if (colorType < 2.f / 3.f) {
190 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
191 } else {
192 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
193 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000194
195 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
196 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
197
198 idx = (int)(random.nextF() * (kNumStages+1));
199 pdesc.fFirstCoverageStage = idx;
200
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000201 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000202 pdesc.fEdgeAAConcave = random.nextF() > .5f;
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000203
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000204 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000205 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000206 (GrGLProgram::ProgramDesc::DualSrcOutput)
207 (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
208 } else {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000209 pdesc.fDualSrcOutput =
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000210 GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
211 }
212
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000213 for (int s = 0; s < kNumStages; ++s) {
214 // enable the stage?
215 if (random.nextF() > .5f) {
216 // use separate tex coords?
217 if (random.nextF() > .5f) {
218 int t = (int)(random.nextF() * kMaxTexCoords);
219 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
220 } else {
221 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
222 }
223 }
224 // use text-formatted verts?
225 if (random.nextF() > .5f) {
226 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
227 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000228 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
229 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
230 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
231 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
232 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
233 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
234 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
235 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
tomhudson@google.com0d831722011-06-02 15:37:14 +0000236 pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 }
238 GrGLProgram::CachedData cachedData;
239 program.genProgram(&cachedData);
240 DeleteProgram(&cachedData);
241 bool again = false;
242 if (again) {
243 program.genProgram(&cachedData);
244 DeleteProgram(&cachedData);
245 }
246 }
247}
248
junov@google.comf93e7172011-03-31 21:26:24 +0000249GrGpuGLShaders::GrGpuGLShaders() {
250
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000251 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000252 int major, minor;
253 gl_version(&major, &minor);
254
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000255 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000256 if (GR_GL_SUPPORT_DESKTOP) {
257 fDualSourceBlendingSupport =
258 major > 3 ||(3 == major && 3 <= minor) ||
259 has_gl_extension("GL_ARB_blend_func_extended");
260 } else {
261 fDualSourceBlendingSupport = false;
262 }
junov@google.comf93e7172011-03-31 21:26:24 +0000263
264 fProgramData = NULL;
265 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000266
267#if 0
268 ProgramUnitTest();
269#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000270}
271
272GrGpuGLShaders::~GrGpuGLShaders() {
273 delete fProgramCache;
274}
275
276const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000277 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000278
279 if (GrGLProgram::kSetAsAttribute ==
280 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
281 return fHWDrawState.fSamplerStates[stage].getMatrix();
282 } else {
283 return fProgramData->fTextureMatrices[stage];
284 }
junov@google.comf93e7172011-03-31 21:26:24 +0000285}
286
287void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000288 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000289 if (GrGLProgram::kSetAsAttribute ==
290 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
291 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
292 } else {
293 fProgramData->fTextureMatrices[stage] = matrix;
294 }
junov@google.comf93e7172011-03-31 21:26:24 +0000295}
296
297void GrGpuGLShaders::resetContext() {
298 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000299
junov@google.comf93e7172011-03-31 21:26:24 +0000300 fHWGeometryState.fVertexLayout = 0;
301 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000302 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000303 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000304 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000305 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000306 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000307
308 fHWProgramID = 0;
309}
310
311void GrGpuGLShaders::flushViewMatrix() {
312 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000313 GrMatrix m;
314 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000315 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
316 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
317 0, 0, GrMatrix::I()[8]);
318 m.setConcat(m, fCurrDrawState.fViewMatrix);
319
320 // ES doesn't allow you to pass true to the transpose param,
321 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000322 GrGLfloat mt[] = {
323 GrScalarToFloat(m[GrMatrix::kMScaleX]),
324 GrScalarToFloat(m[GrMatrix::kMSkewY]),
325 GrScalarToFloat(m[GrMatrix::kMPersp0]),
326 GrScalarToFloat(m[GrMatrix::kMSkewX]),
327 GrScalarToFloat(m[GrMatrix::kMScaleY]),
328 GrScalarToFloat(m[GrMatrix::kMPersp1]),
329 GrScalarToFloat(m[GrMatrix::kMTransX]),
330 GrScalarToFloat(m[GrMatrix::kMTransY]),
331 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000332 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000333
334 if (GrGLProgram::kSetAsAttribute ==
335 fProgramData->fUniLocations.fViewMatrixUni) {
336 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
337 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
338 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
339 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
340 } else {
341 GrAssert(GrGLProgram::kUnusedUniform !=
342 fProgramData->fUniLocations.fViewMatrixUni);
343 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
344 1, false, mt));
345 }
junov@google.comf93e7172011-03-31 21:26:24 +0000346}
347
junov@google.com6acc9b32011-05-16 18:32:07 +0000348void GrGpuGLShaders::flushTextureDomain(int s) {
349 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
350 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000351 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000352 fCurrDrawState.fSamplerStates[s].getTextureDomain();
353
twiz@google.com76b82742011-06-02 20:30:02 +0000354 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
355 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000356
junov@google.com2f839402011-05-24 15:13:01 +0000357 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000358
junov@google.com2f839402011-05-24 15:13:01 +0000359 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000360 GrScalarToFloat(texDom.left()),
361 GrScalarToFloat(texDom.top()),
362 GrScalarToFloat(texDom.right()),
363 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000364 };
365
366 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
367 GrGLTexture::Orientation orientation = texture->orientation();
368
369 // vertical flip if necessary
370 if (GrGLTexture::kBottomUp_Orientation == orientation) {
371 values[1] = 1.0f - values[1];
372 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000373 // The top and bottom were just flipped, so correct the ordering
374 // of elements so that values = (l, t, r, b).
375 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000376 }
377
378 values[0] *= SkScalarToFloat(texture->contentScaleX());
379 values[2] *= SkScalarToFloat(texture->contentScaleX());
380 values[1] *= SkScalarToFloat(texture->contentScaleY());
381 values[3] *= SkScalarToFloat(texture->contentScaleY());
382
383 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000384 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000385 }
386}
387
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000388void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000389 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000390 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
391 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000392 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000393 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
394 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000395
bsalomon@google.com91961302011-05-09 18:39:58 +0000396 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000397
bsalomon@google.com91961302011-05-09 18:39:58 +0000398 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000399
bsalomon@google.com91961302011-05-09 18:39:58 +0000400 GrMatrix m = getSamplerMatrix(s);
401 GrSamplerState::SampleMode mode =
402 fCurrDrawState.fSamplerStates[s].getSampleMode();
403 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000404
bsalomon@google.com91961302011-05-09 18:39:58 +0000405 // ES doesn't allow you to pass true to the transpose param,
406 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000407 GrGLfloat mt[] = {
408 GrScalarToFloat(m[GrMatrix::kMScaleX]),
409 GrScalarToFloat(m[GrMatrix::kMSkewY]),
410 GrScalarToFloat(m[GrMatrix::kMPersp0]),
411 GrScalarToFloat(m[GrMatrix::kMSkewX]),
412 GrScalarToFloat(m[GrMatrix::kMScaleY]),
413 GrScalarToFloat(m[GrMatrix::kMPersp1]),
414 GrScalarToFloat(m[GrMatrix::kMTransX]),
415 GrScalarToFloat(m[GrMatrix::kMTransY]),
416 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000417 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000418
bsalomon@google.com91961302011-05-09 18:39:58 +0000419 if (GrGLProgram::kSetAsAttribute ==
420 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
421 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
422 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
423 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
424 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
425 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000426 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000427 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000428 recordHWSamplerMatrix(s, getSamplerMatrix(s));
429 }
430 }
junov@google.comf93e7172011-03-31 21:26:24 +0000431}
432
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000433void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000434
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000435 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
436 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000437 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000438 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
439 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
440 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000441
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000442 GrScalar centerX1 = sampler.getRadial2CenterX1();
443 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000444
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000445 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000446
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000447 float values[6] = {
448 GrScalarToFloat(a),
449 1 / (2.f * values[0]),
450 GrScalarToFloat(centerX1),
451 GrScalarToFloat(radius0),
452 GrScalarToFloat(GrMul(radius0, radius0)),
453 sampler.isRadial2PosRoot() ? 1.f : -1.f
454 };
455 GR_GL(Uniform1fv(uni, 6, values));
456 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
457 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
458 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
459 }
460}
461
462void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000463 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000464 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000465 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
466 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
467 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
468
469 float texelSize[] = {1.f / texture->allocWidth(),
470 1.f / texture->allocHeight()};
471 GR_GL(Uniform2fv(uni, 1, texelSize));
472 }
473 }
junov@google.comf93e7172011-03-31 21:26:24 +0000474}
475
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000476void GrGpuGLShaders::flushEdgeAAData() {
477 const int& uni = fProgramData->fUniLocations.fEdgesUni;
478 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000479 int count = fCurrDrawState.fEdgeAANumEdges;
480 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000481 // Flip the edges in Y
482 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000483 for (int i = 0; i < count; ++i) {
484 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
485 float b = edges[i].fY;
486 edges[i].fY = -b;
487 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000488 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000489 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000490 }
491}
492
Scroggo01b87ec2011-05-11 18:05:38 +0000493static const float ONE_OVER_255 = 1.f / 255.f;
494
495#define GR_COLOR_TO_VEC4(color) {\
496 GrColorUnpackR(color) * ONE_OVER_255,\
497 GrColorUnpackG(color) * ONE_OVER_255,\
498 GrColorUnpackB(color) * ONE_OVER_255,\
499 GrColorUnpackA(color) * ONE_OVER_255 \
500}
501
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000502void GrGpuGLShaders::flushColor() {
503 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000504 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000505 // color will be specified per-vertex as an attribute
506 // invalidate the const vertex attrib color
507 fHWDrawState.fColor = GrColor_ILLEGAL;
508 } else {
509 switch (desc.fColorType) {
510 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
511 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
512 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000513 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000514 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000515 fHWDrawState.fColor = fCurrDrawState.fColor;
516 }
517 break;
518 case GrGLProgram::ProgramDesc::kUniform_ColorType:
519 if (fProgramData->fColor != fCurrDrawState.fColor) {
520 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000521 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000522 GrAssert(GrGLProgram::kUnusedUniform !=
523 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000524 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
525 fProgramData->fColor = fCurrDrawState.fColor;
526 }
527 break;
528 case GrGLProgram::ProgramDesc::kNone_ColorType:
529 GrAssert(0xffffffff == fCurrDrawState.fColor);
530 break;
531 default:
532 GrCrash("Unknown color type.");
533 }
534 }
Scroggo97c88c22011-05-11 14:05:25 +0000535 if (fProgramData->fUniLocations.fColorFilterUni
536 != GrGLProgram::kUnusedUniform
537 && fProgramData->fColorFilterColor
538 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000539 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000540 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
541 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
542 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000543}
544
545
junov@google.comf93e7172011-03-31 21:26:24 +0000546bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
547 if (!flushGLStateCommon(type)) {
548 return false;
549 }
550
551 if (fDirtyFlags.fRenderTargetChanged) {
552 // our coords are in pixel space and the GL matrices map to NDC
553 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000554 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000555 // we assume all shader matrices may be wrong after viewport changes
556 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000557 }
558
junov@google.comf93e7172011-03-31 21:26:24 +0000559 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000560 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000561 if (NULL == fProgramData) {
562 GrAssert(!"Failed to create program!");
563 return false;
564 }
junov@google.comf93e7172011-03-31 21:26:24 +0000565
566 if (fHWProgramID != fProgramData->fProgramID) {
567 GR_GL(UseProgram(fProgramData->fProgramID));
568 fHWProgramID = fProgramData->fProgramID;
569 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000570 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
571 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
572
573 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
574 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000575
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000576 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000577
bsalomon@google.com91961302011-05-09 18:39:58 +0000578 GrMatrix* currViewMatrix;
579 if (GrGLProgram::kSetAsAttribute ==
580 fProgramData->fUniLocations.fViewMatrixUni) {
581 currViewMatrix = &fHWDrawState.fViewMatrix;
582 } else {
583 currViewMatrix = &fProgramData->fViewMatrix;
584 }
junov@google.comf93e7172011-03-31 21:26:24 +0000585
bsalomon@google.com91961302011-05-09 18:39:58 +0000586 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000587 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000588 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000589 }
590
591 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000592 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000593
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000594 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000595
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000596 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000597
598 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000599 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000600 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000601 resetDirtyFlags();
602 return true;
603}
604
605void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000606}
607
608void GrGpuGLShaders::setupGeometry(int* startVertex,
609 int* startIndex,
610 int vertexCount,
611 int indexCount) {
612
613 int newColorOffset;
614 int newTexCoordOffsets[kMaxTexCoords];
615
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000616 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
617 this->getGeomSrc().fVertexLayout,
618 newTexCoordOffsets,
619 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000620 int oldColorOffset;
621 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000622 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
623 fHWGeometryState.fVertexLayout,
624 oldTexCoordOffsets,
625 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000626 bool indexed = NULL != startIndex;
627
628 int extraVertexOffset;
629 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000630 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000631
632 GrGLenum scalarType;
633 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000634 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000635 scalarType = GrGLTextType;
636 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
637 } else {
638 scalarType = GrGLType;
639 texCoordNorm = false;
640 }
641
642 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
643 *startVertex = 0;
644 if (indexed) {
645 *startIndex += extraIndexOffset;
646 }
647
648 // all the Pointers must be set if any of these are true
649 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
650 vertexOffset != fHWGeometryState.fVertexOffset ||
651 newStride != oldStride;
652
653 // position and tex coord offsets change if above conditions are true
654 // or the type/normalization changed based on text vs nontext type coords.
655 bool posAndTexChange = allOffsetsChange ||
656 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
657 (kTextFormat_VertexLayoutBit &
658 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000659 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000660
661 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000662 int idx = GrGLProgram::PositionAttributeIdx();
663 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
664 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000665 fHWGeometryState.fVertexOffset = vertexOffset;
666 }
667
668 for (int t = 0; t < kMaxTexCoords; ++t) {
669 if (newTexCoordOffsets[t] > 0) {
670 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000671 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000672 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000673 GR_GL(EnableVertexAttribArray(idx));
674 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
675 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000676 } else if (posAndTexChange ||
677 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000678 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
679 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000680 }
681 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000682 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000683 }
684 }
685
686 if (newColorOffset > 0) {
687 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000688 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000689 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000690 GR_GL(EnableVertexAttribArray(idx));
691 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000692 true, newStride, colorOffset));
693 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000694 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000695 true, newStride, colorOffset));
696 }
697 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000698 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000699 }
700
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000701 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000702 fHWGeometryState.fArrayPtrsDirty = false;
703}
704
705void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000706 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000707
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000708 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000709 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000710
711 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
712
713 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
714 // fColorType records how colors are specified for the program. Strip
715 // the bit from the layout to avoid false negatives when searching for an
716 // existing program in the cache.
717 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
718
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000719 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
720
junov@google.comf93e7172011-03-31 21:26:24 +0000721#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000722 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000723 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000724 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000725#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000726#if GR_GL_NO_CONSTANT_ATTRIBUTES
727 if (!requiresAttributeColors) {
728 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
729 } else
730#endif
731 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000732 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000733 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
734 }
junov@google.comf93e7172011-03-31 21:26:24 +0000735
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000736 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000737 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000738
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000739 int lastEnabledStage = -1;
740
junov@google.comf93e7172011-03-31 21:26:24 +0000741 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000742 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000743
tomhudson@google.com0d831722011-06-02 15:37:14 +0000744 stage.fOptFlags = 0;
745 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000746
tomhudson@google.com0d831722011-06-02 15:37:14 +0000747 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000748 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000749 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
750 GrAssert(NULL != texture);
751 // we matrix to invert when orientation is TopDown, so make sure
752 // we aren't in that case before flagging as identity.
753 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000754 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000755 } else if (!getSamplerMatrix(s).hasPerspective()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000756 stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000757 }
758 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000759 case GrSamplerState::kNormal_SampleMode:
760 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
761 break;
762 case GrSamplerState::kRadial_SampleMode:
763 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
764 break;
765 case GrSamplerState::kRadial2_SampleMode:
766 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
767 break;
768 case GrSamplerState::kSweep_SampleMode:
769 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
770 break;
771 default:
772 GrCrash("Unexpected sample mode!");
773 break;
774 }
775
776 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
777 // these both can use a regular texture2D()
778 case GrSamplerState::kNearest_Filter:
779 case GrSamplerState::kBilinear_Filter:
780 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
781 break;
782 // performs 4 texture2D()s
783 case GrSamplerState::k4x4Downsample_Filter:
784 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
785 break;
786 default:
787 GrCrash("Unexpected filter!");
788 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000789 }
790
junov@google.com6acc9b32011-05-16 18:32:07 +0000791 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000792 GrAssert(GrSamplerState::kClamp_WrapMode ==
793 fCurrDrawState.fSamplerStates[s].getWrapX() &&
junov@google.com6acc9b32011-05-16 18:32:07 +0000794 GrSamplerState::kClamp_WrapMode ==
795 fCurrDrawState.fSamplerStates[s].getWrapY());
tomhudson@google.com0d831722011-06-02 15:37:14 +0000796 stage.fOptFlags |=
junov@google.com6acc9b32011-05-16 18:32:07 +0000797 GrGLProgram::ProgramDesc::StageDesc::
798 kCustomTextureDomain_OptFlagBit;
799 }
800
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000801 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000802 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
803 } else {
804 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
805 }
junov@google.comf93e7172011-03-31 21:26:24 +0000806 } else {
807 stage.fOptFlags = 0;
808 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
809 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000810 }
811 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000812
813 desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
814 // use canonical value when coverage/color distinction won't affect
815 // generated code to prevent duplicate programs.
816 desc.fFirstCoverageStage = kNumStages;
817 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
818 // color filter is applied between color/coverage computation
819 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
820 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
821 }
822
823 // We could consider cases where the final color is solid (0xff alpha)
824 // and the dst coeff can correctly be set to a non-dualsrc gl value.
825 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
826 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
827 // kOne).
828 if (fDualSourceBlendingSupport) {
829 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
830 // write the coverage value to second color
831 desc.fDualSrcOutput =
832 GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
833 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
834 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
835 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
836 // cover
837 desc.fDualSrcOutput =
838 GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
839 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
840 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
841 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
842 // cover
843 desc.fDualSrcOutput =
844 GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
845 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
846 }
847 }
848 }
junov@google.comf93e7172011-03-31 21:26:24 +0000849}