blob: 96b03dab05559d78f7242f8aa0b9eb4aceb80201 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
junov@google.comf93e7172011-03-31 21:26:24 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
junov@google.comf93e7172011-03-31 21:26:24 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
junov@google.comf93e7172011-03-31 21:26:24 +000010#include "GrBinHashKey.h"
junov@google.comf93e7172011-03-31 21:26:24 +000011#include "GrGLProgram.h"
12#include "GrGpuGLShaders.h"
13#include "GrGpuVertex.h"
junov@google.comf93e7172011-03-31 21:26:24 +000014#include "GrNoncopyable.h"
15#include "GrStringBuilder.h"
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000016#include "GrRandom.h"
junov@google.comf93e7172011-03-31 21:26:24 +000017
junov@google.comf93e7172011-03-31 21:26:24 +000018#define SKIP_CACHE_CHECK true
19#define GR_UINT32_MAX static_cast<uint32_t>(-1)
20
junov@google.comf93e7172011-03-31 21:26:24 +000021#include "GrTHashCache.h"
22
23class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
24private:
25 class Entry;
26
junov@google.comf7c00f62011-08-18 18:15:16 +000027 typedef GrBinHashKey<Entry, GrGLProgram::kProgramKeySize> ProgramHashKey;
junov@google.comf93e7172011-03-31 21:26:24 +000028
29 class Entry : public ::GrNoncopyable {
30 public:
31 Entry() {}
junov@google.comf93e7172011-03-31 21:26:24 +000032 void copyAndTakeOwnership(Entry& entry) {
33 fProgramData.copyAndTakeOwnership(entry.fProgramData);
junov@google.comf7c00f62011-08-18 18:15:16 +000034 fKey = entry.fKey; // ownership transfer
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000035 fLRUStamp = entry.fLRUStamp;
junov@google.comf93e7172011-03-31 21:26:24 +000036 }
37
38 public:
39 int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
40
41 public:
42 GrGLProgram::CachedData fProgramData;
43 ProgramHashKey fKey;
44 unsigned int fLRUStamp;
45 };
46
47 GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
48
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000049 // We may have kMaxEntries+1 shaders in the GL context because
50 // we create a new shader before evicting from the cache.
junov@google.comf93e7172011-03-31 21:26:24 +000051 enum {
52 kMaxEntries = 32
53 };
54 Entry fEntries[kMaxEntries];
55 int fCount;
56 unsigned int fCurrLRUStamp;
57
58public:
59 ProgramCache()
60 : fCount(0)
61 , fCurrLRUStamp(0) {
62 }
63
64 ~ProgramCache() {
65 for (int i = 0; i < fCount; ++i) {
66 GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
67 }
68 }
69
70 void abandon() {
71 fCount = 0;
72 }
73
74 void invalidateViewMatrices() {
75 for (int i = 0; i < fCount; ++i) {
76 // set to illegal matrix
77 fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
78 }
79 }
80
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +000081 GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000082 Entry newEntry;
junov@google.comf7c00f62011-08-18 18:15:16 +000083 newEntry.fKey.setKeyData(desc.keyData());
84
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000085 Entry* entry = fHashCache.find(newEntry.fKey);
junov@google.comf93e7172011-03-31 21:26:24 +000086 if (NULL == entry) {
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +000087 if (!desc.genProgram(&newEntry.fProgramData)) {
88 return NULL;
89 }
junov@google.comf93e7172011-03-31 21:26:24 +000090 if (fCount < kMaxEntries) {
91 entry = fEntries + fCount;
92 ++fCount;
93 } else {
94 GrAssert(kMaxEntries == fCount);
95 entry = fEntries;
96 for (int i = 1; i < kMaxEntries; ++i) {
97 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
98 entry = fEntries + i;
99 }
100 }
101 fHashCache.remove(entry->fKey, entry);
102 GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
103 }
bsalomon@google.com2d9ddf92011-05-11 16:52:59 +0000104 entry->copyAndTakeOwnership(newEntry);
junov@google.comf93e7172011-03-31 21:26:24 +0000105 fHashCache.insert(entry->fKey, entry);
106 }
107
108 entry->fLRUStamp = fCurrLRUStamp;
109 if (GR_UINT32_MAX == fCurrLRUStamp) {
110 // wrap around! just trash our LRU, one time hit.
111 for (int i = 0; i < fCount; ++i) {
112 fEntries[i].fLRUStamp = 0;
113 }
114 }
115 ++fCurrLRUStamp;
116 return &entry->fProgramData;
117 }
118};
119
junov@google.com53a55842011-06-08 22:55:10 +0000120void GrGpuGLShaders::abandonResources(){
121 INHERITED::abandonResources();
122 fProgramCache->abandon();
123}
124
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000125void GrGpuGLShaders::DeleteProgram(CachedData* programData) {
junov@google.comf93e7172011-03-31 21:26:24 +0000126 GR_GL(DeleteShader(programData->fVShaderID));
127 GR_GL(DeleteShader(programData->fFShaderID));
128 GR_GL(DeleteProgram(programData->fProgramID));
129 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
130}
131
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000132////////////////////////////////////////////////////////////////////////////////
133
134namespace {
135 template <typename T>
136 T random_val(GrRandom* r, T count) {
137 return (T)(int)(r->nextF() * count);
138 }
139};
140
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000141bool GrGpuGLShaders::programUnitTest() {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000142
143 static const int STAGE_OPTS[] = {
144 0,
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000145 StageDesc::kNoPerspective_OptFlagBit,
146 StageDesc::kIdentity_CoordMapping
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000147 };
148 GrGLProgram program;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000149 ProgramDesc& pdesc = program.fProgramDesc;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000150
151 static const int NUM_TESTS = 512;
152
153 // GrRandoms nextU() values have patterns in the low bits
154 // So using nextU() % array_count might never take some values.
155 GrRandom random;
156 for (int t = 0; t < NUM_TESTS; ++t) {
157
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000158#if 0
159 GrPrintf("\nTest Program %d\n-------------\n", t);
160 static const int stop = -1;
161 if (t == stop) {
162 int breakpointhere = 9;
163 }
164#endif
165
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000166 pdesc.fVertexLayout = 0;
167 pdesc.fEmitsPointSize = random.nextF() > .5f;
168 float colorType = random.nextF();
169 if (colorType < 1.f / 3.f) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000170 pdesc.fColorType = ProgramDesc::kAttribute_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000171 } else if (colorType < 2.f / 3.f) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000172 pdesc.fColorType = ProgramDesc::kUniform_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000173 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000174 pdesc.fColorType = ProgramDesc::kNone_ColorType;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000175 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000176
177 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
178 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
179
180 idx = (int)(random.nextF() * (kNumStages+1));
181 pdesc.fFirstCoverageStage = idx;
182
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000183 bool edgeAA = random.nextF() > .5f;
184 if (edgeAA) {
185 pdesc.fEdgeAANumEdges = random.nextF() * this->getMaxEdges() + 1;
186 pdesc.fEdgeAAConcave = random.nextF() > .5f;
187 } else {
188 pdesc.fEdgeAANumEdges = 0;
189 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000190
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000191 if (fDualSourceBlendingSupport) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000192 pdesc.fDualSrcOutput =
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000193 (ProgramDesc::DualSrcOutput)
194 (int)(random.nextF() * ProgramDesc::kDualSrcOutputCnt);
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000195 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000196 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000197 }
198
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000199 for (int s = 0; s < kNumStages; ++s) {
200 // enable the stage?
201 if (random.nextF() > .5f) {
202 // use separate tex coords?
203 if (random.nextF() > .5f) {
204 int t = (int)(random.nextF() * kMaxTexCoords);
205 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
206 } else {
207 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
208 }
209 }
210 // use text-formatted verts?
211 if (random.nextF() > .5f) {
212 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
213 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000214 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000215 StageDesc& stage = pdesc.fStages[s];
216 stage.fOptFlags = STAGE_OPTS[idx];
217 stage.fModulation = random_val(&random, StageDesc::kModulationCnt);
218 stage.fCoordMapping = random_val(&random, StageDesc::kCoordMappingCnt);
219 stage.fFetchMode = random_val(&random, StageDesc::kFetchModeCnt);
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000220 // convolution shaders don't work with persp tex matrix
221 if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
222 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
223 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000224 stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000225 stage.fKernelWidth = 4 * random.nextF() + 2;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000226 }
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000227 CachedData cachedData;
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000228 if (!program.genProgram(&cachedData)) {
229 return false;
230 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000231 DeleteProgram(&cachedData);
232 bool again = false;
233 if (again) {
234 program.genProgram(&cachedData);
235 DeleteProgram(&cachedData);
236 }
237 }
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000238 return true;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000239}
240
junov@google.comf93e7172011-03-31 21:26:24 +0000241GrGpuGLShaders::GrGpuGLShaders() {
242
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000243 resetContext();
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000244
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000245 f4X4DownsampleFilterSupport = true;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000246 if (GR_GL_SUPPORT_DESKTOP) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000247 fDualSourceBlendingSupport =
bsalomon@google.com2c17fcd2011-07-06 17:47:02 +0000248 fGLVersion >= 3.3f ||
249 this->hasExtension("GL_ARB_blend_func_extended");
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000250 } else {
251 fDualSourceBlendingSupport = false;
252 }
junov@google.comf93e7172011-03-31 21:26:24 +0000253
254 fProgramData = NULL;
255 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000256
257#if 0
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000258 this->programUnitTest();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000259#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000260}
261
262GrGpuGLShaders::~GrGpuGLShaders() {
263 delete fProgramCache;
264}
265
266const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000267 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000268
269 if (GrGLProgram::kSetAsAttribute ==
270 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
271 return fHWDrawState.fSamplerStates[stage].getMatrix();
272 } else {
273 return fProgramData->fTextureMatrices[stage];
274 }
junov@google.comf93e7172011-03-31 21:26:24 +0000275}
276
277void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000278 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000279 if (GrGLProgram::kSetAsAttribute ==
280 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
281 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
282 } else {
283 fProgramData->fTextureMatrices[stage] = matrix;
284 }
junov@google.comf93e7172011-03-31 21:26:24 +0000285}
286
287void GrGpuGLShaders::resetContext() {
288 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000289
junov@google.comf93e7172011-03-31 21:26:24 +0000290 fHWGeometryState.fVertexLayout = 0;
291 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000292 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000293 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000294 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000295 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000296 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000297
298 fHWProgramID = 0;
299}
300
301void GrGpuGLShaders::flushViewMatrix() {
302 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000303 GrMatrix m;
304 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000305 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
306 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
307 0, 0, GrMatrix::I()[8]);
308 m.setConcat(m, fCurrDrawState.fViewMatrix);
309
310 // ES doesn't allow you to pass true to the transpose param,
311 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000312 GrGLfloat mt[] = {
313 GrScalarToFloat(m[GrMatrix::kMScaleX]),
314 GrScalarToFloat(m[GrMatrix::kMSkewY]),
315 GrScalarToFloat(m[GrMatrix::kMPersp0]),
316 GrScalarToFloat(m[GrMatrix::kMSkewX]),
317 GrScalarToFloat(m[GrMatrix::kMScaleY]),
318 GrScalarToFloat(m[GrMatrix::kMPersp1]),
319 GrScalarToFloat(m[GrMatrix::kMTransX]),
320 GrScalarToFloat(m[GrMatrix::kMTransY]),
321 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000322 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000323
324 if (GrGLProgram::kSetAsAttribute ==
325 fProgramData->fUniLocations.fViewMatrixUni) {
326 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
327 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
328 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
329 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
330 } else {
331 GrAssert(GrGLProgram::kUnusedUniform !=
332 fProgramData->fUniLocations.fViewMatrixUni);
333 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
334 1, false, mt));
335 }
junov@google.comf93e7172011-03-31 21:26:24 +0000336}
337
junov@google.com6acc9b32011-05-16 18:32:07 +0000338void GrGpuGLShaders::flushTextureDomain(int s) {
339 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
340 if (GrGLProgram::kUnusedUniform != uni) {
twiz@google.com76b82742011-06-02 20:30:02 +0000341 const GrRect &texDom =
junov@google.com6acc9b32011-05-16 18:32:07 +0000342 fCurrDrawState.fSamplerStates[s].getTextureDomain();
343
twiz@google.com76b82742011-06-02 20:30:02 +0000344 if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
345 fProgramData->fTextureDomain[s] != texDom) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000346
junov@google.com2f839402011-05-24 15:13:01 +0000347 fProgramData->fTextureDomain[s] = texDom;
junov@google.com6acc9b32011-05-16 18:32:07 +0000348
junov@google.com2f839402011-05-24 15:13:01 +0000349 float values[4] = {
twiz@google.com76b82742011-06-02 20:30:02 +0000350 GrScalarToFloat(texDom.left()),
351 GrScalarToFloat(texDom.top()),
352 GrScalarToFloat(texDom.right()),
353 GrScalarToFloat(texDom.bottom())
junov@google.com2f839402011-05-24 15:13:01 +0000354 };
355
356 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
357 GrGLTexture::Orientation orientation = texture->orientation();
358
359 // vertical flip if necessary
360 if (GrGLTexture::kBottomUp_Orientation == orientation) {
361 values[1] = 1.0f - values[1];
362 values[3] = 1.0f - values[3];
twiz@google.com76b82742011-06-02 20:30:02 +0000363 // The top and bottom were just flipped, so correct the ordering
364 // of elements so that values = (l, t, r, b).
365 SkTSwap(values[1], values[3]);
junov@google.com2f839402011-05-24 15:13:01 +0000366 }
367
368 values[0] *= SkScalarToFloat(texture->contentScaleX());
369 values[2] *= SkScalarToFloat(texture->contentScaleX());
370 values[1] *= SkScalarToFloat(texture->contentScaleY());
371 values[3] *= SkScalarToFloat(texture->contentScaleY());
372
373 GR_GL(Uniform4fv(uni, 1, values));
junov@google.com6acc9b32011-05-16 18:32:07 +0000374 }
junov@google.com6acc9b32011-05-16 18:32:07 +0000375 }
376}
377
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000378void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000379 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000380 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
381 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000382 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000383 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
384 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000385
bsalomon@google.com91961302011-05-09 18:39:58 +0000386 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000387
bsalomon@google.com91961302011-05-09 18:39:58 +0000388 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000389
bsalomon@google.com91961302011-05-09 18:39:58 +0000390 GrMatrix m = getSamplerMatrix(s);
391 GrSamplerState::SampleMode mode =
392 fCurrDrawState.fSamplerStates[s].getSampleMode();
393 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000394
bsalomon@google.com91961302011-05-09 18:39:58 +0000395 // ES doesn't allow you to pass true to the transpose param,
396 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000397 GrGLfloat mt[] = {
398 GrScalarToFloat(m[GrMatrix::kMScaleX]),
399 GrScalarToFloat(m[GrMatrix::kMSkewY]),
400 GrScalarToFloat(m[GrMatrix::kMPersp0]),
401 GrScalarToFloat(m[GrMatrix::kMSkewX]),
402 GrScalarToFloat(m[GrMatrix::kMScaleY]),
403 GrScalarToFloat(m[GrMatrix::kMPersp1]),
404 GrScalarToFloat(m[GrMatrix::kMTransX]),
405 GrScalarToFloat(m[GrMatrix::kMTransY]),
406 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000407 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000408
bsalomon@google.com91961302011-05-09 18:39:58 +0000409 if (GrGLProgram::kSetAsAttribute ==
410 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
411 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
412 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
413 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
414 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
415 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000416 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000417 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000418 recordHWSamplerMatrix(s, getSamplerMatrix(s));
419 }
420 }
junov@google.comf93e7172011-03-31 21:26:24 +0000421}
422
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000423void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000424
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000425 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
426 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000427 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000428 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
429 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
430 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000431
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000432 GrScalar centerX1 = sampler.getRadial2CenterX1();
433 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000434
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000435 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000436
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000437 // when were in the degenerate (linear) case the second
438 // value will be INF but the program doesn't read it. (We
439 // use the same 6 uniforms even though we don't need them
440 // all in the linear case just to keep the code complexity
441 // down).
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000442 float values[6] = {
443 GrScalarToFloat(a),
444 1 / (2.f * values[0]),
445 GrScalarToFloat(centerX1),
446 GrScalarToFloat(radius0),
447 GrScalarToFloat(GrMul(radius0, radius0)),
448 sampler.isRadial2PosRoot() ? 1.f : -1.f
449 };
450 GR_GL(Uniform1fv(uni, 6, values));
451 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
452 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
453 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
454 }
455}
456
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000457void GrGpuGLShaders::flushConvolution(int s) {
458 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
459 int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
460 if (GrGLProgram::kUnusedUniform != kernelUni) {
461 GR_GL(Uniform1fv(kernelUni, sampler.getKernelWidth(), sampler.getKernel()));
462 }
463 int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
464 if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
465 GR_GL(Uniform2fv(imageIncrementUni, 1, sampler.getImageIncrement()));
466 }
467}
468
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000469void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000470 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000471 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000472 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
bsalomon@google.com0168afc2011-08-08 13:21:05 +0000473 if (texture->allocatedWidth() != fProgramData->fTextureWidth[s] ||
474 texture->allocatedHeight() != fProgramData->fTextureWidth[s]) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000475
bsalomon@google.com0168afc2011-08-08 13:21:05 +0000476 float texelSize[] = {1.f / texture->allocatedWidth(),
477 1.f / texture->allocatedHeight()};
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000478 GR_GL(Uniform2fv(uni, 1, texelSize));
479 }
480 }
junov@google.comf93e7172011-03-31 21:26:24 +0000481}
482
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000483void GrGpuGLShaders::flushEdgeAAData() {
484 const int& uni = fProgramData->fUniLocations.fEdgesUni;
485 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000486 int count = fCurrDrawState.fEdgeAANumEdges;
487 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000488 // Flip the edges in Y
489 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000490 for (int i = 0; i < count; ++i) {
491 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
492 float b = edges[i].fY;
493 edges[i].fY = -b;
494 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000495 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000496 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000497 }
498}
499
Scroggo01b87ec2011-05-11 18:05:38 +0000500static const float ONE_OVER_255 = 1.f / 255.f;
501
502#define GR_COLOR_TO_VEC4(color) {\
503 GrColorUnpackR(color) * ONE_OVER_255,\
504 GrColorUnpackG(color) * ONE_OVER_255,\
505 GrColorUnpackB(color) * ONE_OVER_255,\
506 GrColorUnpackA(color) * ONE_OVER_255 \
507}
508
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000509void GrGpuGLShaders::flushColor() {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000510 const ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000511 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000512 // color will be specified per-vertex as an attribute
513 // invalidate the const vertex attrib color
514 fHWDrawState.fColor = GrColor_ILLEGAL;
515 } else {
516 switch (desc.fColorType) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000517 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000518 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
519 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000520 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000521 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000522 fHWDrawState.fColor = fCurrDrawState.fColor;
523 }
524 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000525 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000526 if (fProgramData->fColor != fCurrDrawState.fColor) {
527 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000528 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000529 GrAssert(GrGLProgram::kUnusedUniform !=
530 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000531 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
532 fProgramData->fColor = fCurrDrawState.fColor;
533 }
534 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000535 case ProgramDesc::kNone_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000536 GrAssert(0xffffffff == fCurrDrawState.fColor);
537 break;
538 default:
539 GrCrash("Unknown color type.");
540 }
541 }
Scroggo97c88c22011-05-11 14:05:25 +0000542 if (fProgramData->fUniLocations.fColorFilterUni
543 != GrGLProgram::kUnusedUniform
544 && fProgramData->fColorFilterColor
545 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000546 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000547 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
548 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
549 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000550}
551
552
junov@google.comf93e7172011-03-31 21:26:24 +0000553bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
554 if (!flushGLStateCommon(type)) {
555 return false;
556 }
557
558 if (fDirtyFlags.fRenderTargetChanged) {
559 // our coords are in pixel space and the GL matrices map to NDC
560 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000561 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000562 // we assume all shader matrices may be wrong after viewport changes
563 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000564 }
565
junov@google.comf93e7172011-03-31 21:26:24 +0000566 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000567 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000568 if (NULL == fProgramData) {
569 GrAssert(!"Failed to create program!");
570 return false;
571 }
junov@google.comf93e7172011-03-31 21:26:24 +0000572
573 if (fHWProgramID != fProgramData->fProgramID) {
574 GR_GL(UseProgram(fProgramData->fProgramID));
575 fHWProgramID = fProgramData->fProgramID;
576 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000577 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
578 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
579
580 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
581 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000582
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000583 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000584
bsalomon@google.com91961302011-05-09 18:39:58 +0000585 GrMatrix* currViewMatrix;
586 if (GrGLProgram::kSetAsAttribute ==
587 fProgramData->fUniLocations.fViewMatrixUni) {
588 currViewMatrix = &fHWDrawState.fViewMatrix;
589 } else {
590 currViewMatrix = &fProgramData->fViewMatrix;
591 }
junov@google.comf93e7172011-03-31 21:26:24 +0000592
bsalomon@google.com91961302011-05-09 18:39:58 +0000593 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000594 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000595 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000596 }
597
598 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000599 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000600
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000601 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000602
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000603 this->flushConvolution(s);
604
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000605 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000606
607 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000608 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000609 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000610 resetDirtyFlags();
611 return true;
612}
613
614void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000615}
616
617void GrGpuGLShaders::setupGeometry(int* startVertex,
618 int* startIndex,
619 int vertexCount,
620 int indexCount) {
621
622 int newColorOffset;
623 int newTexCoordOffsets[kMaxTexCoords];
624
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000625 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
626 this->getGeomSrc().fVertexLayout,
627 newTexCoordOffsets,
628 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000629 int oldColorOffset;
630 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000631 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
632 fHWGeometryState.fVertexLayout,
633 oldTexCoordOffsets,
634 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000635 bool indexed = NULL != startIndex;
636
637 int extraVertexOffset;
638 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000639 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000640
641 GrGLenum scalarType;
642 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000643 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000644 scalarType = GrGLTextType;
645 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
646 } else {
647 scalarType = GrGLType;
648 texCoordNorm = false;
649 }
650
651 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
652 *startVertex = 0;
653 if (indexed) {
654 *startIndex += extraIndexOffset;
655 }
656
657 // all the Pointers must be set if any of these are true
658 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
659 vertexOffset != fHWGeometryState.fVertexOffset ||
660 newStride != oldStride;
661
662 // position and tex coord offsets change if above conditions are true
663 // or the type/normalization changed based on text vs nontext type coords.
664 bool posAndTexChange = allOffsetsChange ||
665 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
666 (kTextFormat_VertexLayoutBit &
667 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000668 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000669
670 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000671 int idx = GrGLProgram::PositionAttributeIdx();
672 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
673 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000674 fHWGeometryState.fVertexOffset = vertexOffset;
675 }
676
677 for (int t = 0; t < kMaxTexCoords; ++t) {
678 if (newTexCoordOffsets[t] > 0) {
679 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000680 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000681 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000682 GR_GL(EnableVertexAttribArray(idx));
683 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
684 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000685 } else if (posAndTexChange ||
686 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000687 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
688 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000689 }
690 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000691 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000692 }
693 }
694
695 if (newColorOffset > 0) {
696 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000697 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000698 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000699 GR_GL(EnableVertexAttribArray(idx));
700 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000701 true, newStride, colorOffset));
702 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000703 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000704 true, newStride, colorOffset));
705 }
706 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000707 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000708 }
709
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000710 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000711 fHWGeometryState.fArrayPtrsDirty = false;
712}
713
714void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000715 ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000716
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000717 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000718 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000719
720 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
721
722 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
723 // fColorType records how colors are specified for the program. Strip
724 // the bit from the layout to avoid false negatives when searching for an
725 // existing program in the cache.
726 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
727
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000728 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
729
junov@google.comf93e7172011-03-31 21:26:24 +0000730#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000731 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000732 desc.fColorType = ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000733 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000734#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000735#if GR_GL_NO_CONSTANT_ATTRIBUTES
736 if (!requiresAttributeColors) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000737 desc.fColorType = ProgramDesc::kUniform_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000738 } else
739#endif
740 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000741 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000742 desc.fColorType = ProgramDesc::kAttribute_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000743 }
junov@google.comf93e7172011-03-31 21:26:24 +0000744
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000745 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000746 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000747
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000748 int lastEnabledStage = -1;
749
junov@google.comf93e7172011-03-31 21:26:24 +0000750 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000751 StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000752
tomhudson@google.com0d831722011-06-02 15:37:14 +0000753 stage.fOptFlags = 0;
754 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000755
tomhudson@google.com0d831722011-06-02 15:37:14 +0000756 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000757 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000758 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
759 GrAssert(NULL != texture);
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000760 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000761 // we matrix to invert when orientation is TopDown, so make sure
762 // we aren't in that case before flagging as identity.
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000763 if (TextureMatrixIsIdentity(texture, sampler)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000764 stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000765 } else if (!getSamplerMatrix(s).hasPerspective()) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000766 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000767 }
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000768 switch (sampler.getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000769 case GrSamplerState::kNormal_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000770 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000771 break;
772 case GrSamplerState::kRadial_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000773 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000774 break;
775 case GrSamplerState::kRadial2_SampleMode:
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000776 if (sampler.radial2IsDegenerate()) {
777 stage.fCoordMapping =
778 StageDesc::kRadial2GradientDegenerate_CoordMapping;
779 } else {
780 stage.fCoordMapping =
781 StageDesc::kRadial2Gradient_CoordMapping;
782 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000783 break;
784 case GrSamplerState::kSweep_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000785 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000786 break;
787 default:
788 GrCrash("Unexpected sample mode!");
789 break;
790 }
791
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000792 switch (sampler.getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000793 // these both can use a regular texture2D()
794 case GrSamplerState::kNearest_Filter:
795 case GrSamplerState::kBilinear_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000796 stage.fFetchMode = StageDesc::kSingle_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000797 break;
798 // performs 4 texture2D()s
799 case GrSamplerState::k4x4Downsample_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000800 stage.fFetchMode = StageDesc::k2x2_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000801 break;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000802 // performs fKernelWidth texture2D()s
803 case GrSamplerState::kConvolution_Filter:
804 stage.fFetchMode = StageDesc::kConvolution_FetchMode;
805 break;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000806 default:
807 GrCrash("Unexpected filter!");
808 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000809 }
810
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000811 if (sampler.hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000812 GrAssert(GrSamplerState::kClamp_WrapMode ==
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000813 sampler.getWrapX() &&
814 GrSamplerState::kClamp_WrapMode ==
815 sampler.getWrapY());
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000816 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
junov@google.com6acc9b32011-05-16 18:32:07 +0000817 }
818
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000819 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000820 stage.fModulation = StageDesc::kAlpha_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000821 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000822 stage.fModulation = StageDesc::kColor_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000823 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000824 if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
825 stage.fKernelWidth = sampler.getKernelWidth();
826 } else {
827 stage.fKernelWidth = 0;
828 }
junov@google.comf93e7172011-03-31 21:26:24 +0000829 } else {
830 stage.fOptFlags = 0;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000831 stage.fCoordMapping = (StageDesc::CoordMapping)0;
832 stage.fModulation = (StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000833 }
834 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000835
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000836 desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000837 // use canonical value when coverage/color distinction won't affect
838 // generated code to prevent duplicate programs.
839 desc.fFirstCoverageStage = kNumStages;
840 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
841 // color filter is applied between color/coverage computation
842 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
843 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
844 }
845
846 // We could consider cases where the final color is solid (0xff alpha)
847 // and the dst coeff can correctly be set to a non-dualsrc gl value.
848 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
849 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
850 // kOne).
851 if (fDualSourceBlendingSupport) {
852 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
853 // write the coverage value to second color
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000854 desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000855 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
856 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
857 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
858 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000859 desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000860 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
861 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
862 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
863 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000864 desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000865 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
866 }
867 }
868 }
junov@google.comf93e7172011-03-31 21:26:24 +0000869}