blob: a52501bfe8032cc54943ebbbdf0903ed3dae8a2b [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
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000456void GrGpuGLShaders::flushConvolution(int s) {
457 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
458 int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
459 if (GrGLProgram::kUnusedUniform != kernelUni) {
460 GR_GL(Uniform1fv(kernelUni, sampler.getKernelWidth(), sampler.getKernel()));
461 }
462 int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
463 if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
464 GR_GL(Uniform2fv(imageIncrementUni, 1, sampler.getImageIncrement()));
465 }
466}
467
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000468void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000469 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000470 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000471 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
472 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
473 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
474
475 float texelSize[] = {1.f / texture->allocWidth(),
476 1.f / texture->allocHeight()};
477 GR_GL(Uniform2fv(uni, 1, texelSize));
478 }
479 }
junov@google.comf93e7172011-03-31 21:26:24 +0000480}
481
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000482void GrGpuGLShaders::flushEdgeAAData() {
483 const int& uni = fProgramData->fUniLocations.fEdgesUni;
484 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000485 int count = fCurrDrawState.fEdgeAANumEdges;
486 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000487 // Flip the edges in Y
488 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000489 for (int i = 0; i < count; ++i) {
490 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
491 float b = edges[i].fY;
492 edges[i].fY = -b;
493 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000494 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000495 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000496 }
497}
498
Scroggo01b87ec2011-05-11 18:05:38 +0000499static const float ONE_OVER_255 = 1.f / 255.f;
500
501#define GR_COLOR_TO_VEC4(color) {\
502 GrColorUnpackR(color) * ONE_OVER_255,\
503 GrColorUnpackG(color) * ONE_OVER_255,\
504 GrColorUnpackB(color) * ONE_OVER_255,\
505 GrColorUnpackA(color) * ONE_OVER_255 \
506}
507
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000508void GrGpuGLShaders::flushColor() {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000509 const ProgramDesc& desc = fCurrentProgram.getDesc();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000510 if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000511 // color will be specified per-vertex as an attribute
512 // invalidate the const vertex attrib color
513 fHWDrawState.fColor = GrColor_ILLEGAL;
514 } else {
515 switch (desc.fColorType) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000516 case ProgramDesc::kAttribute_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000517 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
518 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000519 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000520 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000521 fHWDrawState.fColor = fCurrDrawState.fColor;
522 }
523 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000524 case ProgramDesc::kUniform_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000525 if (fProgramData->fColor != fCurrDrawState.fColor) {
526 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000527 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000528 GrAssert(GrGLProgram::kUnusedUniform !=
529 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000530 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
531 fProgramData->fColor = fCurrDrawState.fColor;
532 }
533 break;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000534 case ProgramDesc::kNone_ColorType:
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000535 GrAssert(0xffffffff == fCurrDrawState.fColor);
536 break;
537 default:
538 GrCrash("Unknown color type.");
539 }
540 }
Scroggo97c88c22011-05-11 14:05:25 +0000541 if (fProgramData->fUniLocations.fColorFilterUni
542 != GrGLProgram::kUnusedUniform
543 && fProgramData->fColorFilterColor
544 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000545 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000546 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
547 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
548 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000549}
550
551
junov@google.comf93e7172011-03-31 21:26:24 +0000552bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
553 if (!flushGLStateCommon(type)) {
554 return false;
555 }
556
557 if (fDirtyFlags.fRenderTargetChanged) {
558 // our coords are in pixel space and the GL matrices map to NDC
559 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000560 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000561 // we assume all shader matrices may be wrong after viewport changes
562 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000563 }
564
junov@google.comf93e7172011-03-31 21:26:24 +0000565 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000566 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000567 if (NULL == fProgramData) {
568 GrAssert(!"Failed to create program!");
569 return false;
570 }
junov@google.comf93e7172011-03-31 21:26:24 +0000571
572 if (fHWProgramID != fProgramData->fProgramID) {
573 GR_GL(UseProgram(fProgramData->fProgramID));
574 fHWProgramID = fProgramData->fProgramID;
575 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000576 GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
577 GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
578
579 fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
580 this->flushBlend(type, srcCoeff, dstCoeff);
junov@google.comf93e7172011-03-31 21:26:24 +0000581
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000582 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000583
bsalomon@google.com91961302011-05-09 18:39:58 +0000584 GrMatrix* currViewMatrix;
585 if (GrGLProgram::kSetAsAttribute ==
586 fProgramData->fUniLocations.fViewMatrixUni) {
587 currViewMatrix = &fHWDrawState.fViewMatrix;
588 } else {
589 currViewMatrix = &fProgramData->fViewMatrix;
590 }
junov@google.comf93e7172011-03-31 21:26:24 +0000591
bsalomon@google.com91961302011-05-09 18:39:58 +0000592 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000593 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000594 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000595 }
596
597 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000598 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000599
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000600 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000601
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000602 this->flushConvolution(s);
603
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000604 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000605
606 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000607 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000608 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000609 resetDirtyFlags();
610 return true;
611}
612
613void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000614}
615
616void GrGpuGLShaders::setupGeometry(int* startVertex,
617 int* startIndex,
618 int vertexCount,
619 int indexCount) {
620
621 int newColorOffset;
622 int newTexCoordOffsets[kMaxTexCoords];
623
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000624 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
625 this->getGeomSrc().fVertexLayout,
626 newTexCoordOffsets,
627 &newColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000628 int oldColorOffset;
629 int oldTexCoordOffsets[kMaxTexCoords];
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000630 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
631 fHWGeometryState.fVertexLayout,
632 oldTexCoordOffsets,
633 &oldColorOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000634 bool indexed = NULL != startIndex;
635
636 int extraVertexOffset;
637 int extraIndexOffset;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000638 this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
junov@google.comf93e7172011-03-31 21:26:24 +0000639
640 GrGLenum scalarType;
641 bool texCoordNorm;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000642 if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
junov@google.comf93e7172011-03-31 21:26:24 +0000643 scalarType = GrGLTextType;
644 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
645 } else {
646 scalarType = GrGLType;
647 texCoordNorm = false;
648 }
649
650 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
651 *startVertex = 0;
652 if (indexed) {
653 *startIndex += extraIndexOffset;
654 }
655
656 // all the Pointers must be set if any of these are true
657 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
658 vertexOffset != fHWGeometryState.fVertexOffset ||
659 newStride != oldStride;
660
661 // position and tex coord offsets change if above conditions are true
662 // or the type/normalization changed based on text vs nontext type coords.
663 bool posAndTexChange = allOffsetsChange ||
664 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
665 (kTextFormat_VertexLayoutBit &
666 (fHWGeometryState.fVertexLayout ^
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000667 this->getGeomSrc().fVertexLayout)));
junov@google.comf93e7172011-03-31 21:26:24 +0000668
669 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000670 int idx = GrGLProgram::PositionAttributeIdx();
671 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
672 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000673 fHWGeometryState.fVertexOffset = vertexOffset;
674 }
675
676 for (int t = 0; t < kMaxTexCoords; ++t) {
677 if (newTexCoordOffsets[t] > 0) {
678 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000679 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000680 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000681 GR_GL(EnableVertexAttribArray(idx));
682 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
683 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000684 } else if (posAndTexChange ||
685 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000686 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
687 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000688 }
689 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000690 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000691 }
692 }
693
694 if (newColorOffset > 0) {
695 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000696 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000697 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000698 GR_GL(EnableVertexAttribArray(idx));
699 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000700 true, newStride, colorOffset));
701 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000702 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000703 true, newStride, colorOffset));
704 }
705 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000706 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000707 }
708
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000709 fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
junov@google.comf93e7172011-03-31 21:26:24 +0000710 fHWGeometryState.fArrayPtrsDirty = false;
711}
712
713void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000714 ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000715
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000716 // Must initialize all fields or cache will have false negatives!
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000717 desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000718
719 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
720
721 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
722 // fColorType records how colors are specified for the program. Strip
723 // the bit from the layout to avoid false negatives when searching for an
724 // existing program in the cache.
725 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
726
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000727 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
728
junov@google.comf93e7172011-03-31 21:26:24 +0000729#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000730 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000731 desc.fColorType = ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000732 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000733#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000734#if GR_GL_NO_CONSTANT_ATTRIBUTES
735 if (!requiresAttributeColors) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000736 desc.fColorType = ProgramDesc::kUniform_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000737 } else
738#endif
739 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000740 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000741 desc.fColorType = ProgramDesc::kAttribute_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000742 }
junov@google.comf93e7172011-03-31 21:26:24 +0000743
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000744 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000745 desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000746
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000747 int lastEnabledStage = -1;
748
junov@google.comf93e7172011-03-31 21:26:24 +0000749 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000750 StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000751
tomhudson@google.com0d831722011-06-02 15:37:14 +0000752 stage.fOptFlags = 0;
753 stage.setEnabled(this->isStageEnabled(s));
junov@google.comf93e7172011-03-31 21:26:24 +0000754
tomhudson@google.com0d831722011-06-02 15:37:14 +0000755 if (stage.isEnabled()) {
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000756 lastEnabledStage = s;
junov@google.comf93e7172011-03-31 21:26:24 +0000757 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
758 GrAssert(NULL != texture);
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000759 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000760 // we matrix to invert when orientation is TopDown, so make sure
761 // we aren't in that case before flagging as identity.
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000762 if (TextureMatrixIsIdentity(texture, sampler)) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000763 stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000764 } else if (!getSamplerMatrix(s).hasPerspective()) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000765 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
junov@google.comf93e7172011-03-31 21:26:24 +0000766 }
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000767 switch (sampler.getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000768 case GrSamplerState::kNormal_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000769 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000770 break;
771 case GrSamplerState::kRadial_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000772 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000773 break;
774 case GrSamplerState::kRadial2_SampleMode:
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000775 if (sampler.radial2IsDegenerate()) {
776 stage.fCoordMapping =
777 StageDesc::kRadial2GradientDegenerate_CoordMapping;
778 } else {
779 stage.fCoordMapping =
780 StageDesc::kRadial2Gradient_CoordMapping;
781 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000782 break;
783 case GrSamplerState::kSweep_SampleMode:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000784 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000785 break;
786 default:
787 GrCrash("Unexpected sample mode!");
788 break;
789 }
790
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000791 switch (sampler.getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000792 // these both can use a regular texture2D()
793 case GrSamplerState::kNearest_Filter:
794 case GrSamplerState::kBilinear_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000795 stage.fFetchMode = StageDesc::kSingle_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000796 break;
797 // performs 4 texture2D()s
798 case GrSamplerState::k4x4Downsample_Filter:
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000799 stage.fFetchMode = StageDesc::k2x2_FetchMode;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000800 break;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000801 // performs fKernelWidth texture2D()s
802 case GrSamplerState::kConvolution_Filter:
803 stage.fFetchMode = StageDesc::kConvolution_FetchMode;
804 break;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000805 default:
806 GrCrash("Unexpected filter!");
807 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000808 }
809
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000810 if (sampler.hasTextureDomain()) {
tomhudson@google.com0d831722011-06-02 15:37:14 +0000811 GrAssert(GrSamplerState::kClamp_WrapMode ==
bsalomon@google.com22c5dea2011-07-07 14:38:03 +0000812 sampler.getWrapX() &&
813 GrSamplerState::kClamp_WrapMode ==
814 sampler.getWrapY());
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000815 stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
junov@google.com6acc9b32011-05-16 18:32:07 +0000816 }
817
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000818 if (GrPixelConfigIsAlphaOnly(texture->config())) {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000819 stage.fModulation = StageDesc::kAlpha_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000820 } else {
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000821 stage.fModulation = StageDesc::kColor_Modulation;
junov@google.comf93e7172011-03-31 21:26:24 +0000822 }
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +0000823 if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
824 stage.fKernelWidth = sampler.getKernelWidth();
825 } else {
826 stage.fKernelWidth = 0;
827 }
junov@google.comf93e7172011-03-31 21:26:24 +0000828 } else {
829 stage.fOptFlags = 0;
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000830 stage.fCoordMapping = (StageDesc::CoordMapping)0;
831 stage.fModulation = (StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000832 }
833 }
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000834
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000835 desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000836 // use canonical value when coverage/color distinction won't affect
837 // generated code to prevent duplicate programs.
838 desc.fFirstCoverageStage = kNumStages;
839 if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
840 // color filter is applied between color/coverage computation
841 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
842 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
843 }
844
845 // We could consider cases where the final color is solid (0xff alpha)
846 // and the dst coeff can correctly be set to a non-dualsrc gl value.
847 // (e.g. solid draw, and dst coeff is kZero. It's correct to make
848 // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
849 // kOne).
850 if (fDualSourceBlendingSupport) {
851 if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
852 // write the coverage value to second color
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000853 desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000854 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
855 } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
856 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
857 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000858 desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000859 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
860 } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
861 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
862 // cover
bsalomon@google.com1e257a52011-07-06 19:52:16 +0000863 desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
bsalomon@google.com271cffc2011-05-20 14:13:56 +0000864 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
865 }
866 }
867 }
junov@google.comf93e7172011-03-31 21:26:24 +0000868}