blob: bbf9719cf9586c818982f5fd5d5473cd88696c94 [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
133void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
134 GR_GL(DeleteShader(programData->fVShaderID));
135 GR_GL(DeleteShader(programData->fFShaderID));
136 GR_GL(DeleteProgram(programData->fProgramID));
137 GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
138}
139
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000140void GrGpuGLShaders::ProgramUnitTest() {
141
142 static const int STAGE_OPTS[] = {
143 0,
144 GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
145 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
146 };
147 static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
148 GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
149 GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
150 };
151 static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
152 GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
153 GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
154 GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
155 GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
156 };
157 static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
158 GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
159 GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
160 };
161 GrGLProgram program;
162 GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
163
164 static const int NUM_TESTS = 512;
165
166 // GrRandoms nextU() values have patterns in the low bits
167 // So using nextU() % array_count might never take some values.
168 GrRandom random;
169 for (int t = 0; t < NUM_TESTS; ++t) {
170
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000171#if 0
172 GrPrintf("\nTest Program %d\n-------------\n", t);
173 static const int stop = -1;
174 if (t == stop) {
175 int breakpointhere = 9;
176 }
177#endif
178
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000179 pdesc.fVertexLayout = 0;
180 pdesc.fEmitsPointSize = random.nextF() > .5f;
181 float colorType = random.nextF();
182 if (colorType < 1.f / 3.f) {
183 pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
184 } else if (colorType < 2.f / 3.f) {
185 pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
186 } else {
187 pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
188 }
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000189
190 int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
191 pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
192
193 idx = (int)(random.nextF() * (kNumStages+1));
194 pdesc.fFirstCoverageStage = idx;
195
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000196 pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000197
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000198 for (int s = 0; s < kNumStages; ++s) {
199 // enable the stage?
200 if (random.nextF() > .5f) {
201 // use separate tex coords?
202 if (random.nextF() > .5f) {
203 int t = (int)(random.nextF() * kMaxTexCoords);
204 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
205 } else {
206 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
207 }
208 }
209 // use text-formatted verts?
210 if (random.nextF() > .5f) {
211 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
212 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000213 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000214 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
215 pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
216 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
217 pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
218 idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
219 pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
220 idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
221 pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000222 }
223 GrGLProgram::CachedData cachedData;
224 program.genProgram(&cachedData);
225 DeleteProgram(&cachedData);
226 bool again = false;
227 if (again) {
228 program.genProgram(&cachedData);
229 DeleteProgram(&cachedData);
230 }
231 }
232}
233
junov@google.comf93e7172011-03-31 21:26:24 +0000234GrGpuGLShaders::GrGpuGLShaders() {
235
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000236 resetContext();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 f4X4DownsampleFilterSupport = true;
junov@google.comf93e7172011-03-31 21:26:24 +0000238
239 fProgramData = NULL;
240 fProgramCache = new ProgramCache();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000241
242#if 0
243 ProgramUnitTest();
244#endif
junov@google.comf93e7172011-03-31 21:26:24 +0000245}
246
247GrGpuGLShaders::~GrGpuGLShaders() {
248 delete fProgramCache;
249}
250
251const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
junov@google.comf93e7172011-03-31 21:26:24 +0000252 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000253
254 if (GrGLProgram::kSetAsAttribute ==
255 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
256 return fHWDrawState.fSamplerStates[stage].getMatrix();
257 } else {
258 return fProgramData->fTextureMatrices[stage];
259 }
junov@google.comf93e7172011-03-31 21:26:24 +0000260}
261
262void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000263 GrAssert(fProgramData);
bsalomon@google.com91961302011-05-09 18:39:58 +0000264 if (GrGLProgram::kSetAsAttribute ==
265 fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
266 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
267 } else {
268 fProgramData->fTextureMatrices[stage] = matrix;
269 }
junov@google.comf93e7172011-03-31 21:26:24 +0000270}
271
272void GrGpuGLShaders::resetContext() {
273 INHERITED::resetContext();
junov@google.comf93e7172011-03-31 21:26:24 +0000274
junov@google.comf93e7172011-03-31 21:26:24 +0000275 fHWGeometryState.fVertexLayout = 0;
276 fHWGeometryState.fVertexOffset = ~0;
bsalomon@google.com91961302011-05-09 18:39:58 +0000277 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000278 for (int t = 0; t < kMaxTexCoords; ++t) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000279 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000280 }
bsalomon@google.com91961302011-05-09 18:39:58 +0000281 GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000282
283 fHWProgramID = 0;
284}
285
286void GrGpuGLShaders::flushViewMatrix() {
287 GrAssert(NULL != fCurrDrawState.fRenderTarget);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000288 GrMatrix m;
289 m.setAll(
junov@google.comf93e7172011-03-31 21:26:24 +0000290 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
291 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
292 0, 0, GrMatrix::I()[8]);
293 m.setConcat(m, fCurrDrawState.fViewMatrix);
294
295 // ES doesn't allow you to pass true to the transpose param,
296 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000297 GrGLfloat mt[] = {
298 GrScalarToFloat(m[GrMatrix::kMScaleX]),
299 GrScalarToFloat(m[GrMatrix::kMSkewY]),
300 GrScalarToFloat(m[GrMatrix::kMPersp0]),
301 GrScalarToFloat(m[GrMatrix::kMSkewX]),
302 GrScalarToFloat(m[GrMatrix::kMScaleY]),
303 GrScalarToFloat(m[GrMatrix::kMPersp1]),
304 GrScalarToFloat(m[GrMatrix::kMTransX]),
305 GrScalarToFloat(m[GrMatrix::kMTransY]),
306 GrScalarToFloat(m[GrMatrix::kMPersp2])
junov@google.comf93e7172011-03-31 21:26:24 +0000307 };
bsalomon@google.com91961302011-05-09 18:39:58 +0000308
309 if (GrGLProgram::kSetAsAttribute ==
310 fProgramData->fUniLocations.fViewMatrixUni) {
311 int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
312 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
313 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
314 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
315 } else {
316 GrAssert(GrGLProgram::kUnusedUniform !=
317 fProgramData->fUniLocations.fViewMatrixUni);
318 GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
319 1, false, mt));
320 }
junov@google.comf93e7172011-03-31 21:26:24 +0000321}
322
junov@google.com6acc9b32011-05-16 18:32:07 +0000323void GrGpuGLShaders::flushTextureDomain(int s) {
324 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
325 if (GrGLProgram::kUnusedUniform != uni) {
326 const GrRect &texDom =
327 fCurrDrawState.fSamplerStates[s].getTextureDomain();
328
329 float values[4] = {
330 GrScalarToFloat(texDom.left()),
331 GrScalarToFloat(texDom.top()),
332 GrScalarToFloat(texDom.right()),
333 GrScalarToFloat(texDom.bottom())
334 };
335
336 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
337 GrGLTexture::Orientation orientation = texture->orientation();
338
339 // vertical flip if necessary
340 if (GrGLTexture::kBottomUp_Orientation == orientation) {
341 values[1] = 1.0f - values[1];
342 values[3] = 1.0f - values[3];
343 }
344
345 values[0] *= SkScalarToFloat(texture->contentScaleX());
346 values[2] *= SkScalarToFloat(texture->contentScaleX());
347 values[1] *= SkScalarToFloat(texture->contentScaleY());
348 values[3] *= SkScalarToFloat(texture->contentScaleY());
349
350 GR_GL(Uniform4fv(uni, 1, values));
351 }
352}
353
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000354void GrGpuGLShaders::flushTextureMatrix(int s) {
junov@google.com6acc9b32011-05-16 18:32:07 +0000355 const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
357 if (NULL != texture) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000358 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
360 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
junov@google.comf93e7172011-03-31 21:26:24 +0000361
bsalomon@google.com91961302011-05-09 18:39:58 +0000362 GrAssert(NULL != fCurrDrawState.fTextures[s]);
junov@google.comf93e7172011-03-31 21:26:24 +0000363
bsalomon@google.com91961302011-05-09 18:39:58 +0000364 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000365
bsalomon@google.com91961302011-05-09 18:39:58 +0000366 GrMatrix m = getSamplerMatrix(s);
367 GrSamplerState::SampleMode mode =
368 fCurrDrawState.fSamplerStates[s].getSampleMode();
369 AdjustTextureMatrix(texture, mode, &m);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000370
bsalomon@google.com91961302011-05-09 18:39:58 +0000371 // ES doesn't allow you to pass true to the transpose param,
372 // so do our own transpose
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000373 GrGLfloat mt[] = {
374 GrScalarToFloat(m[GrMatrix::kMScaleX]),
375 GrScalarToFloat(m[GrMatrix::kMSkewY]),
376 GrScalarToFloat(m[GrMatrix::kMPersp0]),
377 GrScalarToFloat(m[GrMatrix::kMSkewX]),
378 GrScalarToFloat(m[GrMatrix::kMScaleY]),
379 GrScalarToFloat(m[GrMatrix::kMPersp1]),
380 GrScalarToFloat(m[GrMatrix::kMTransX]),
381 GrScalarToFloat(m[GrMatrix::kMTransY]),
382 GrScalarToFloat(m[GrMatrix::kMPersp2])
bsalomon@google.com91961302011-05-09 18:39:58 +0000383 };
bsalomon@google.com27a4dc42011-05-16 13:14:03 +0000384
bsalomon@google.com91961302011-05-09 18:39:58 +0000385 if (GrGLProgram::kSetAsAttribute ==
386 fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
387 int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
388 GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
389 GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
390 GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
391 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000392 GR_GL(UniformMatrix3fv(uni, 1, false, mt));
bsalomon@google.com91961302011-05-09 18:39:58 +0000393 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000394 recordHWSamplerMatrix(s, getSamplerMatrix(s));
395 }
396 }
junov@google.comf93e7172011-03-31 21:26:24 +0000397}
398
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000399void GrGpuGLShaders::flushRadial2(int s) {
junov@google.comf93e7172011-03-31 21:26:24 +0000400
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000401 const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
402 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
bsalomon@google.com91961302011-05-09 18:39:58 +0000403 if (GrGLProgram::kUnusedUniform != uni &&
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000404 (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
405 fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
406 fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000407
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000408 GrScalar centerX1 = sampler.getRadial2CenterX1();
409 GrScalar radius0 = sampler.getRadial2Radius0();
junov@google.comf93e7172011-03-31 21:26:24 +0000410
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000411 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
junov@google.comf93e7172011-03-31 21:26:24 +0000412
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000413 float values[6] = {
414 GrScalarToFloat(a),
415 1 / (2.f * values[0]),
416 GrScalarToFloat(centerX1),
417 GrScalarToFloat(radius0),
418 GrScalarToFloat(GrMul(radius0, radius0)),
419 sampler.isRadial2PosRoot() ? 1.f : -1.f
420 };
421 GR_GL(Uniform1fv(uni, 6, values));
422 fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
423 fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
424 fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
425 }
426}
427
428void GrGpuGLShaders::flushTexelSize(int s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000429 const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
bsalomon@google.com91961302011-05-09 18:39:58 +0000430 if (GrGLProgram::kUnusedUniform != uni) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000431 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
432 if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
433 texture->allocHeight() != fProgramData->fTextureWidth[s]) {
434
435 float texelSize[] = {1.f / texture->allocWidth(),
436 1.f / texture->allocHeight()};
437 GR_GL(Uniform2fv(uni, 1, texelSize));
438 }
439 }
junov@google.comf93e7172011-03-31 21:26:24 +0000440}
441
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000442void GrGpuGLShaders::flushEdgeAAData() {
443 const int& uni = fProgramData->fUniLocations.fEdgesUni;
444 if (GrGLProgram::kUnusedUniform != uni) {
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000445 int count = fCurrDrawState.fEdgeAANumEdges;
446 Edge edges[kMaxEdges];
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000447 // Flip the edges in Y
448 float height = fCurrDrawState.fRenderTarget->height();
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000449 for (int i = 0; i < count; ++i) {
450 edges[i] = fCurrDrawState.fEdgeAAEdges[i];
451 float b = edges[i].fY;
452 edges[i].fY = -b;
453 edges[i].fZ += b * height;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000454 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000455 GR_GL(Uniform3fv(uni, count, &edges[0].fX));
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000456 }
457}
458
Scroggo01b87ec2011-05-11 18:05:38 +0000459static const float ONE_OVER_255 = 1.f / 255.f;
460
461#define GR_COLOR_TO_VEC4(color) {\
462 GrColorUnpackR(color) * ONE_OVER_255,\
463 GrColorUnpackG(color) * ONE_OVER_255,\
464 GrColorUnpackB(color) * ONE_OVER_255,\
465 GrColorUnpackA(color) * ONE_OVER_255 \
466}
467
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000468void GrGpuGLShaders::flushColor() {
469 const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
470 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
471 // color will be specified per-vertex as an attribute
472 // invalidate the const vertex attrib color
473 fHWDrawState.fColor = GrColor_ILLEGAL;
474 } else {
475 switch (desc.fColorType) {
476 case GrGLProgram::ProgramDesc::kAttribute_ColorType:
477 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
478 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000479 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000480 GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000481 fHWDrawState.fColor = fCurrDrawState.fColor;
482 }
483 break;
484 case GrGLProgram::ProgramDesc::kUniform_ColorType:
485 if (fProgramData->fColor != fCurrDrawState.fColor) {
486 // OpenGL ES only supports the float varities of glVertexAttrib
Scroggo01b87ec2011-05-11 18:05:38 +0000487 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
bsalomon@google.com91961302011-05-09 18:39:58 +0000488 GrAssert(GrGLProgram::kUnusedUniform !=
489 fProgramData->fUniLocations.fColorUni);
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000490 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
491 fProgramData->fColor = fCurrDrawState.fColor;
492 }
493 break;
494 case GrGLProgram::ProgramDesc::kNone_ColorType:
495 GrAssert(0xffffffff == fCurrDrawState.fColor);
496 break;
497 default:
498 GrCrash("Unknown color type.");
499 }
500 }
Scroggo97c88c22011-05-11 14:05:25 +0000501 if (fProgramData->fUniLocations.fColorFilterUni
502 != GrGLProgram::kUnusedUniform
503 && fProgramData->fColorFilterColor
504 != fCurrDrawState.fColorFilterColor) {
Scroggo01b87ec2011-05-11 18:05:38 +0000505 float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
Scroggo97c88c22011-05-11 14:05:25 +0000506 GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
507 fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
508 }
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000509}
510
511
junov@google.comf93e7172011-03-31 21:26:24 +0000512bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
513 if (!flushGLStateCommon(type)) {
514 return false;
515 }
516
517 if (fDirtyFlags.fRenderTargetChanged) {
518 // our coords are in pixel space and the GL matrices map to NDC
519 // so if the viewport changed, our matrix is now wrong.
junov@google.comf93e7172011-03-31 21:26:24 +0000520 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
junov@google.comf93e7172011-03-31 21:26:24 +0000521 // we assume all shader matrices may be wrong after viewport changes
522 fProgramCache->invalidateViewMatrices();
junov@google.comf93e7172011-03-31 21:26:24 +0000523 }
524
junov@google.comf93e7172011-03-31 21:26:24 +0000525 buildProgram(type);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000526 fProgramData = fProgramCache->getProgramData(fCurrentProgram);
bsalomon@google.com91961302011-05-09 18:39:58 +0000527 if (NULL == fProgramData) {
528 GrAssert(!"Failed to create program!");
529 return false;
530 }
junov@google.comf93e7172011-03-31 21:26:24 +0000531
532 if (fHWProgramID != fProgramData->fProgramID) {
533 GR_GL(UseProgram(fProgramData->fProgramID));
534 fHWProgramID = fProgramData->fProgramID;
535 }
536
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000537 this->flushColor();
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000538
bsalomon@google.com91961302011-05-09 18:39:58 +0000539 GrMatrix* currViewMatrix;
540 if (GrGLProgram::kSetAsAttribute ==
541 fProgramData->fUniLocations.fViewMatrixUni) {
542 currViewMatrix = &fHWDrawState.fViewMatrix;
543 } else {
544 currViewMatrix = &fProgramData->fViewMatrix;
545 }
junov@google.comf93e7172011-03-31 21:26:24 +0000546
bsalomon@google.com91961302011-05-09 18:39:58 +0000547 if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
junov@google.comf93e7172011-03-31 21:26:24 +0000548 flushViewMatrix();
bsalomon@google.com91961302011-05-09 18:39:58 +0000549 *currViewMatrix = fCurrDrawState.fViewMatrix;
junov@google.comf93e7172011-03-31 21:26:24 +0000550 }
551
552 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000553 this->flushTextureMatrix(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000554
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000555 this->flushRadial2(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000556
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000557 this->flushTexelSize(s);
junov@google.com6acc9b32011-05-16 18:32:07 +0000558
559 this->flushTextureDomain(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000560 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000561 this->flushEdgeAAData();
junov@google.comf93e7172011-03-31 21:26:24 +0000562 resetDirtyFlags();
563 return true;
564}
565
566void GrGpuGLShaders::postDraw() {
junov@google.comf93e7172011-03-31 21:26:24 +0000567}
568
569void GrGpuGLShaders::setupGeometry(int* startVertex,
570 int* startIndex,
571 int vertexCount,
572 int indexCount) {
573
574 int newColorOffset;
575 int newTexCoordOffsets[kMaxTexCoords];
576
577 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
578 newTexCoordOffsets,
579 &newColorOffset);
580 int oldColorOffset;
581 int oldTexCoordOffsets[kMaxTexCoords];
582 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
583 oldTexCoordOffsets,
584 &oldColorOffset);
585 bool indexed = NULL != startIndex;
586
587 int extraVertexOffset;
588 int extraIndexOffset;
589 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
590
591 GrGLenum scalarType;
592 bool texCoordNorm;
593 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
594 scalarType = GrGLTextType;
595 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
596 } else {
597 scalarType = GrGLType;
598 texCoordNorm = false;
599 }
600
601 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
602 *startVertex = 0;
603 if (indexed) {
604 *startIndex += extraIndexOffset;
605 }
606
607 // all the Pointers must be set if any of these are true
608 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
609 vertexOffset != fHWGeometryState.fVertexOffset ||
610 newStride != oldStride;
611
612 // position and tex coord offsets change if above conditions are true
613 // or the type/normalization changed based on text vs nontext type coords.
614 bool posAndTexChange = allOffsetsChange ||
615 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
616 (kTextFormat_VertexLayoutBit &
617 (fHWGeometryState.fVertexLayout ^
618 fGeometrySrc.fVertexLayout)));
619
620 if (posAndTexChange) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000621 int idx = GrGLProgram::PositionAttributeIdx();
622 GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
623 (GrGLvoid*)vertexOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000624 fHWGeometryState.fVertexOffset = vertexOffset;
625 }
626
627 for (int t = 0; t < kMaxTexCoords; ++t) {
628 if (newTexCoordOffsets[t] > 0) {
629 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com91961302011-05-09 18:39:58 +0000630 int idx = GrGLProgram::TexCoordAttributeIdx(t);
junov@google.comf93e7172011-03-31 21:26:24 +0000631 if (oldTexCoordOffsets[t] <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000632 GR_GL(EnableVertexAttribArray(idx));
633 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
634 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000635 } else if (posAndTexChange ||
636 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000637 GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
638 newStride, texCoordOffset));
junov@google.comf93e7172011-03-31 21:26:24 +0000639 }
640 } else if (oldTexCoordOffsets[t] > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000641 GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
junov@google.comf93e7172011-03-31 21:26:24 +0000642 }
643 }
644
645 if (newColorOffset > 0) {
646 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
bsalomon@google.com91961302011-05-09 18:39:58 +0000647 int idx = GrGLProgram::ColorAttributeIdx();
junov@google.comf93e7172011-03-31 21:26:24 +0000648 if (oldColorOffset <= 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000649 GR_GL(EnableVertexAttribArray(idx));
650 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000651 true, newStride, colorOffset));
652 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000653 GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
junov@google.comf93e7172011-03-31 21:26:24 +0000654 true, newStride, colorOffset));
655 }
656 } else if (oldColorOffset > 0) {
bsalomon@google.com91961302011-05-09 18:39:58 +0000657 GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
junov@google.comf93e7172011-03-31 21:26:24 +0000658 }
659
660 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
661 fHWGeometryState.fArrayPtrsDirty = false;
662}
663
664void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000665 GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
junov@google.comf93e7172011-03-31 21:26:24 +0000666
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000667 // Must initialize all fields or cache will have false negatives!
668 desc.fVertexLayout = fGeometrySrc.fVertexLayout;
669
670 desc.fEmitsPointSize = kPoints_PrimitiveType == type;
671
672 bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
673 // fColorType records how colors are specified for the program. Strip
674 // the bit from the layout to avoid false negatives when searching for an
675 // existing program in the cache.
676 desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
677
bsalomon@google.comf2d91552011-05-16 20:56:06 +0000678 desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
679
680 // coverage vs. color only applies when there is a color filter
681 // (currently)
682 if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
683 desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
684 } else {
685 // use canonical value when this won't affect generated
686 // code to prevent duplicate programs.
687 desc.fFirstCoverageStage = kNumStages;
688 }
689
junov@google.comf93e7172011-03-31 21:26:24 +0000690#if GR_AGGRESSIVE_SHADER_OPTS
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000691 if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
junov@google.comc97db4c2011-04-29 17:25:42 +0000692 desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000693 } else
junov@google.comf93e7172011-03-31 21:26:24 +0000694#endif
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000695#if GR_GL_NO_CONSTANT_ATTRIBUTES
696 if (!requiresAttributeColors) {
697 desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
698 } else
699#endif
700 {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000701 if (requiresAttributeColors) {} // suppress unused var warning
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000702 desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
703 }
junov@google.comf93e7172011-03-31 21:26:24 +0000704
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000705 desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000706
junov@google.comf93e7172011-03-31 21:26:24 +0000707 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com4be283f2011-04-19 21:15:09 +0000708 GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
junov@google.comf93e7172011-03-31 21:26:24 +0000709
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000710 stage.fEnabled = this->isStageEnabled(s);
junov@google.comf93e7172011-03-31 21:26:24 +0000711
712 if (stage.fEnabled) {
713 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
714 GrAssert(NULL != texture);
715 // we matrix to invert when orientation is TopDown, so make sure
716 // we aren't in that case before flagging as identity.
717 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
718 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
719 } else if (!getSamplerMatrix(s).hasPerspective()) {
720 stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
721 } else {
722 stage.fOptFlags = 0;
723 }
724 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000725 case GrSamplerState::kNormal_SampleMode:
726 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
727 break;
728 case GrSamplerState::kRadial_SampleMode:
729 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
730 break;
731 case GrSamplerState::kRadial2_SampleMode:
732 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
733 break;
734 case GrSamplerState::kSweep_SampleMode:
735 stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
736 break;
737 default:
738 GrCrash("Unexpected sample mode!");
739 break;
740 }
741
742 switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
743 // these both can use a regular texture2D()
744 case GrSamplerState::kNearest_Filter:
745 case GrSamplerState::kBilinear_Filter:
746 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
747 break;
748 // performs 4 texture2D()s
749 case GrSamplerState::k4x4Downsample_Filter:
750 stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
751 break;
752 default:
753 GrCrash("Unexpected filter!");
754 break;
junov@google.comf93e7172011-03-31 21:26:24 +0000755 }
756
junov@google.com6acc9b32011-05-16 18:32:07 +0000757 if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
758 GrAssert(GrSamplerState::kClamp_WrapMode ==
759 fCurrDrawState.fSamplerStates[s].getWrapX() &&
760 GrSamplerState::kClamp_WrapMode ==
761 fCurrDrawState.fSamplerStates[s].getWrapY());
762 stage.fOptFlags |=
763 GrGLProgram::ProgramDesc::StageDesc::
764 kCustomTextureDomain_OptFlagBit;
765 }
766
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000767 if (GrPixelConfigIsAlphaOnly(texture->config())) {
junov@google.comf93e7172011-03-31 21:26:24 +0000768 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
769 } else {
770 stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
771 }
junov@google.comf93e7172011-03-31 21:26:24 +0000772 } else {
773 stage.fOptFlags = 0;
774 stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
775 stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
junov@google.comf93e7172011-03-31 21:26:24 +0000776 }
777 }
junov@google.comf93e7172011-03-31 21:26:24 +0000778}
779
780