blob: a56e511fcabb033402e1870f8f86e93cbaf8049e [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
twiz@google.com0f31ca72011-03-18 17:38:11 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
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
18#include "GrGLConfig.h"
19
reed@google.comac10a2d2010-12-22 21:39:39 +000020#include "GrGpuGLShaders2.h"
21#include "GrGpuVertex.h"
22#include "GrMemory.h"
23#include "GrStringBuilder.h"
24
25
26#define ATTRIBUTE_MATRIX 0
27
reed@google.comac10a2d2010-12-22 21:39:39 +000028#define PRINT_SHADERS 0
29
30#define SKIP_CACHE_CHECK true
31
reed@google.comac10a2d2010-12-22 21:39:39 +000032#define POS_ATTR_LOCATION 0
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000033#define TEX_ATTR_LOCATION(X) (1 + X)
34#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords)
reed@google.comac10a2d2010-12-22 21:39:39 +000035#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000036#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
37#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
reed@google.comac10a2d2010-12-22 21:39:39 +000038#define BOGUS_MATRIX_UNI_LOCATION 1000
39#endif
40
reed@google.comd2938db2011-01-28 20:54:15 +000041#define GR_UINT32_MAX static_cast<uint32_t>(-1)
42
twiz@google.comb65e0cb2011-03-18 20:41:44 +000043namespace {
44
45const char* GrPrecision() {
46 if (GR_GL_SUPPORT_ES2) {
47 return "mediump";
48 } else {
49 return "";
50 }
51}
52
53const char* GrShaderPrecision() {
54 if (GR_GL_SUPPORT_ES2) {
55 return "precision mediump float;\n";
56 } else {
57 return "";
58 }
59}
60
61} // namespace
62
reed@google.comac10a2d2010-12-22 21:39:39 +000063struct GrGpuGLShaders2::StageUniLocations {
twiz@google.com0f31ca72011-03-18 17:38:11 +000064 GrGLint fTextureMatrixUni;
65 GrGLint fSamplerUni;
66 GrGLint fRadial2Uni;
reed@google.comac10a2d2010-12-22 21:39:39 +000067};
68
69struct GrGpuGLShaders2::UniLocations {
twiz@google.com0f31ca72011-03-18 17:38:11 +000070 GrGLint fViewMatrixUni;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000071 StageUniLocations fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000072};
73
74// Records per-program information
75// we can specify the attribute locations so that they are constant
76// across our shaders. But the driver determines the uniform locations
77// at link time. We don't need to remember the sampler uniform location
78// because we will bind a texture slot to it and never change it
79// Uniforms are program-local so we can't rely on fHWState to hold the
80// previous uniform state after a program change.
81struct GrGpuGLShaders2::Program {
82 // IDs
twiz@google.com0f31ca72011-03-18 17:38:11 +000083 GrGLuint fVShaderID;
84 GrGLuint fFShaderID;
85 GrGLuint fProgramID;
reed@google.comac10a2d2010-12-22 21:39:39 +000086
87 // shader uniform locations (-1 if shader doesn't use them)
88 UniLocations fUniLocations;
89
90 // these reflect the current values of uniforms
91 // (GL uniform values travel with program)
92 GrMatrix fViewMatrix;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +000093 GrMatrix fTextureMatrices[kNumStages];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000094 GrScalar fRadial2CenterX1[kNumStages];
95 GrScalar fRadial2Radius0[kNumStages];
96 bool fRadial2PosRoot[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000097
98};
99
100// must be tightly packed
101struct GrGpuGLShaders2::StageDesc {
102 enum OptFlagBits {
103 kNoPerspective_OptFlagBit = 0x1,
104 kIdentityMatrix_OptFlagBit = 0x2,
105 };
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000106 unsigned fOptFlags : 8;
107
108 unsigned fEnabled : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000109
reed@google.comac10a2d2010-12-22 21:39:39 +0000110 enum Modulation {
111 kColor_Modulation,
112 kAlpha_Modulation,
113 } fModulation : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000114
reed@google.comac10a2d2010-12-22 21:39:39 +0000115 enum CoordMapping {
116 kIdentity_CoordMapping,
117 kRadialGradient_CoordMapping,
118 kSweepGradient_CoordMapping,
119 kRadial2Gradient_CoordMapping,
120 } fCoordMapping : 8;
121};
122
123// must be tightly packed
124struct GrGpuGLShaders2::ProgramDesc {
125 GrVertexLayout fVertexLayout;
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000126 GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field
127
reed@google.comac10a2d2010-12-22 21:39:39 +0000128 enum {
129 kNotPoints_OptFlagBit = 0x1,
130 kVertexColorAllOnes_OptFlagBit = 0x2,
131 };
132 // we're assuming optflags and layout pack into 32 bits
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000133 // VS 2010 seems to require short rather than just unsigned
134 // for this to pack
135 unsigned short fOptFlags : 16;
reed@google.comac10a2d2010-12-22 21:39:39 +0000136
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000137 StageDesc fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000138
139 bool operator == (const ProgramDesc& desc) const {
140 // keep 4-byte aligned and tightly packed
141 GR_STATIC_ASSERT(4 == sizeof(StageDesc));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000142 GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
144 }
145};
146
147#include "GrTHashCache.h"
148
149class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
150private:
151 struct Entry;
152 class HashKey {
153 public:
154 HashKey();
155 HashKey(const ProgramDesc& desc);
156 static const HashKey& GetKey(const Entry&);
157 static bool EQ(const Entry&, const HashKey&);
158 static bool LT(const Entry&, const HashKey&);
159 bool operator <(const HashKey& key) const;
160 bool operator ==(const HashKey& key) const;
161 uint32_t getHash() const;
162 private:
163 ProgramDesc fDesc;
164 uint32_t fHash;
165 };
166
167 struct Entry {
168 Program fProgram;
169 HashKey fKey;
170 uint32_t fLRUStamp;
171 };
172
173 // if hash bits is changed, need to change hash function
174 GrTHashTable<Entry, HashKey, 8> fHashCache;
175
176 static const int MAX_ENTRIES = 16;
177 Entry fEntries[MAX_ENTRIES];
178 int fCount;
179 uint32_t fCurrLRUStamp;
180
181public:
182 ProgramCache() {
183 fCount = 0;
184 fCurrLRUStamp = 0;
185 }
186
187 ~ProgramCache() {
188 for (int i = 0; i < fCount; ++i) {
189 GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
190 }
191 }
192
193 void abandon() {
194 fCount = 0;
195 }
196
197 void invalidateViewMatrices() {
198 for (int i = 0; i < fCount; ++i) {
199 // set to illegal matrix
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000200 fEntries[i].fProgram.fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000201 }
202 }
203
204 Program* getProgram(const ProgramDesc& desc) {
205 HashKey key(desc);
206 Entry* entry = fHashCache.find(key);
207 if (NULL == entry) {
208 if (fCount < MAX_ENTRIES) {
209 entry = fEntries + fCount;
210 ++fCount;
211 } else {
212 GrAssert(MAX_ENTRIES == fCount);
213 entry = fEntries;
214 for (int i = 1; i < MAX_ENTRIES; ++i) {
215 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
216 entry = fEntries + i;
217 }
218 }
219 fHashCache.remove(entry->fKey, entry);
220 GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
221 }
222 entry->fKey = key;
223 GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
224 fHashCache.insert(entry->fKey, entry);
225 }
226
227 entry->fLRUStamp = fCurrLRUStamp;
reed@google.comd2938db2011-01-28 20:54:15 +0000228 if (GR_UINT32_MAX == fCurrLRUStamp) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000229 // wrap around! just trash our LRU, one time hit.
230 for (int i = 0; i < fCount; ++i) {
231 fEntries[i].fLRUStamp = 0;
232 }
233 }
234 ++fCurrLRUStamp;
235 return &entry->fProgram;
236 }
237};
238
239GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
240}
241
242static uint32_t ror(uint32_t x) {
243 return (x >> 8) | (x << 24);
244}
245
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000246static uint32_t rol(uint32_t x) {
247 return (x << 8) | (x >> 24);
248}
249
reed@google.comac10a2d2010-12-22 21:39:39 +0000250GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
251 fDesc = desc;
252 // if you change the size of the desc, need to update the hash function
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000253 GR_STATIC_ASSERT(12 == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000254
reed@google.com38690072011-01-26 01:44:18 +0000255 uint32_t* d = GrTCast<uint32_t*>(&fDesc);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000256 fHash = d[0] ^ ror(d[1]) ^ rol(d[2]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000257}
258
259bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
260 const HashKey& key) {
261 return entry.fKey == key;
262}
263
264bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
265 const HashKey& key) {
266 return entry.fKey < key;
267}
268
269bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
270 return fDesc == key.fDesc;
271}
272
273bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
274 return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
275}
276
277uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
278 return fHash;
279}
280
reed@google.comac10a2d2010-12-22 21:39:39 +0000281struct GrGpuGLShaders2::ShaderCodeSegments {
282 GrSStringBuilder<256> fVSUnis;
283 GrSStringBuilder<256> fVSAttrs;
284 GrSStringBuilder<256> fVaryings;
285 GrSStringBuilder<256> fFSUnis;
286 GrSStringBuilder<512> fVSCode;
287 GrSStringBuilder<512> fFSCode;
288};
289// for variable names etc
290typedef GrSStringBuilder<16> GrTokenString;
291
292#if ATTRIBUTE_MATRIX
293 #define VIEW_MATRIX_NAME "aViewM"
294#else
295 #define VIEW_MATRIX_NAME "uViewM"
296#endif
297
298#define POS_ATTR_NAME "aPosition"
299#define COL_ATTR_NAME "aColor"
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000300
301static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
302 *s = "aTexCoord";
303 s->appendInt(coordIdx);
304}
reed@google.comac10a2d2010-12-22 21:39:39 +0000305
306static inline const char* float_vector_type(int count) {
307 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
reed@google.com38690072011-01-26 01:44:18 +0000308 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000309 return FLOAT_VECS[count];
310}
311
312static inline const char* vector_homog_coord(int count) {
313 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
reed@google.com38690072011-01-26 01:44:18 +0000314 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000315 return HOMOGS[count];
316}
317
318static inline const char* vector_nonhomog_coords(int count) {
319 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
reed@google.com38690072011-01-26 01:44:18 +0000320 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000321 return NONHOMOGS[count];
322}
323
324static inline const char* vector_all_coords(int count) {
325 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
reed@google.com38690072011-01-26 01:44:18 +0000326 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
reed@google.comac10a2d2010-12-22 21:39:39 +0000327 return ALL[count];
328}
329
330static void tex_matrix_name(int stage, GrStringBuilder* s) {
331#if ATTRIBUTE_MATRIX
332 *s = "aTexM";
333#else
334 *s = "uTexM";
335#endif
336 s->appendInt(stage);
337}
338
339static void sampler_name(int stage, GrStringBuilder* s) {
340 *s = "uSampler";
341 s->appendInt(stage);
342}
343
344static void stage_varying_name(int stage, GrStringBuilder* s) {
345 *s = "vStage";
346 s->appendInt(stage);
347}
348
349static void radial2_param_name(int stage, GrStringBuilder* s) {
350 *s = "uRadial2Params";
351 s->appendInt(stage);
352}
353
354static void radial2_varying_name(int stage, GrStringBuilder* s) {
355 *s = "vB";
356 s->appendInt(stage);
357}
358
359#include "GrRandom.h"
360
361void GrGpuGLShaders2::ProgramUnitTest() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 static const int PROG_OPTS[] = {
363 0,
364 ProgramDesc::kNotPoints_OptFlagBit,
365 ProgramDesc::kVertexColorAllOnes_OptFlagBit,
366 ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
367 };
368 static const int STAGE_OPTS[] = {
369 0,
370 StageDesc::kNoPerspective_OptFlagBit,
371 StageDesc::kIdentity_CoordMapping
372 };
373 static const int STAGE_MODULATES[] = {
374 StageDesc::kColor_Modulation,
375 StageDesc::kAlpha_Modulation
376 };
377 static const int STAGE_COORD_MAPPINGS[] = {
378 StageDesc::kIdentity_CoordMapping,
379 StageDesc::kRadialGradient_CoordMapping,
380 StageDesc::kSweepGradient_CoordMapping,
381 StageDesc::kRadial2Gradient_CoordMapping
382 };
383 ProgramDesc pdesc;
384 memset(&pdesc, 0, sizeof(pdesc));
385
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000386 static const int NUM_TESTS = 512;
reed@google.comac10a2d2010-12-22 21:39:39 +0000387
388 // GrRandoms nextU() values have patterns in the low bits
389 // So using nextU() % array_count might never take some values.
390 GrRandom random;
391 for (int t = 0; t < NUM_TESTS; ++t) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000392
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000393 pdesc.fVertexLayout = 0;
394 for (int s = 0; s < kNumStages; ++s) {
395 // enable the stage?
396 if (random.nextF() > .5f) {
397 // use separate tex coords?
398 if (random.nextF() > .5f) {
399 int t = (int)(random.nextF() * kMaxTexCoords);
400 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
401 } else {
402 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
403 }
404 }
405 // use text-formatted verts?
406 if (random.nextF() > .5f) {
407 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
408 }
409 }
410
411 int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 pdesc.fOptFlags = PROG_OPTS[x];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000413 for (int s = 0; s < kNumStages; ++s) {
414 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000415 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
416 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
417 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000418 pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000419 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000420 pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000421 }
422 Program program;
423 GenProgram(pdesc, &program);
424 DeleteProgram(&program);
425 }
426}
427
428void GrGpuGLShaders2::GenStageCode(int stageNum,
429 const StageDesc& desc,
430 const char* fsInColor, // NULL means no incoming color
431 const char* fsOutColor,
432 const char* vsInCoord,
433 ShaderCodeSegments* segments,
434 StageUniLocations* locations) {
435
436 GrAssert(stageNum >= 0 && stageNum <= 9);
437
438 GrTokenString varyingName;
439 stage_varying_name(stageNum, &varyingName);
440
441 // First decide how many coords are needed to access the texture
442 // Right now it's always 2 but we could start using 1D textures for
443 // gradients.
444 static const int coordDims = 2;
445 int varyingDims;
446 /// Vertex Shader Stuff
447
448 // decide whether we need a matrix to transform texture coords
449 // and whether the varying needs a perspective coord.
450 GrTokenString texMName;
451 tex_matrix_name(stageNum, &texMName);
452 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
453 varyingDims = coordDims;
454 } else {
455 #if ATTRIBUTE_MATRIX
456 segments->fVSAttrs += "attribute mat3 ";
457 segments->fVSAttrs += texMName;
458 segments->fVSAttrs += ";\n";
459 #else
460 segments->fVSUnis += "uniform mat3 ";
461 segments->fVSUnis += texMName;
462 segments->fVSUnis += ";\n";
463 locations->fTextureMatrixUni = 1;
464 #endif
465 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
466 varyingDims = coordDims;
467 } else {
468 varyingDims = coordDims + 1;
469 }
470 }
471
472 GrTokenString samplerName;
473 sampler_name(stageNum, &samplerName);
474 segments->fFSUnis += "uniform sampler2D ";
475 segments->fFSUnis += samplerName;
476 segments->fFSUnis += ";\n";
477 locations->fSamplerUni = 1;
478
479 segments->fVaryings += "varying ";
480 segments->fVaryings += float_vector_type(varyingDims);
481 segments->fVaryings += " ";
482 segments->fVaryings += varyingName;
483 segments->fVaryings += ";\n";
484
485 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
486 GrAssert(varyingDims == coordDims);
487 segments->fVSCode += "\t";
488 segments->fVSCode += varyingName;
489 segments->fVSCode += " = ";
490 segments->fVSCode += vsInCoord;
491 segments->fVSCode += ";\n";
492 } else {
493 segments->fVSCode += "\t";
494 segments->fVSCode += varyingName;
495 segments->fVSCode += " = (";
496 segments->fVSCode += texMName;
497 segments->fVSCode += " * vec3(";
498 segments->fVSCode += vsInCoord;
499 segments->fVSCode += ", 1))";
500 segments->fVSCode += vector_all_coords(varyingDims);
501 segments->fVSCode += ";\n";
502 }
503
504 GrTokenString radial2ParamsName;
505 radial2_param_name(stageNum, &radial2ParamsName);
506 // for radial grads without perspective we can pass the linear
507 // part of the quadratic as a varying.
508 GrTokenString radial2VaryingName;
509 radial2_varying_name(stageNum, &radial2VaryingName);
510
511 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
512
twiz@google.comb65e0cb2011-03-18 20:41:44 +0000513 segments->fVSUnis += "uniform ";
514 segments->fVSUnis += GrPrecision();
515 segments->fVSUnis += " float ";
reed@google.comac10a2d2010-12-22 21:39:39 +0000516 segments->fVSUnis += radial2ParamsName;
517 segments->fVSUnis += "[6];\n";
518
twiz@google.comb65e0cb2011-03-18 20:41:44 +0000519 segments->fFSUnis += "uniform ";
520 segments->fFSUnis += GrPrecision();
521 segments->fFSUnis += " float ";
reed@google.comac10a2d2010-12-22 21:39:39 +0000522 segments->fFSUnis += radial2ParamsName;
523 segments->fFSUnis += "[6];\n";
524 locations->fRadial2Uni = 1;
525
526 // if there is perspective we don't interpolate this
527 if (varyingDims == coordDims) {
528 GrAssert(2 == coordDims);
529 segments->fVaryings += "varying float ";
530 segments->fVaryings += radial2VaryingName;
531 segments->fVaryings += ";\n";
532
533 segments->fVSCode += "\t";
534 segments->fVSCode += radial2VaryingName;
535 segments->fVSCode += " = 2.0 * (";
536 segments->fVSCode += radial2ParamsName;
537 segments->fVSCode += "[2] * ";
538 segments->fVSCode += varyingName;
539 segments->fVSCode += ".x ";
540 segments->fVSCode += " - ";
541 segments->fVSCode += radial2ParamsName;
542 segments->fVSCode += "[3]);\n";
543 }
544 }
545
546 /// Fragment Shader Stuff
547 GrTokenString fsCoordName;
548 // function used to access the shader, may be made projective
549 GrTokenString texFunc("texture2D");
550 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
551 StageDesc::kNoPerspective_OptFlagBit)) {
552 GrAssert(varyingDims == coordDims);
553 fsCoordName = varyingName;
554 } else {
555 // if we have to do some non-matrix op on the varyings to get
556 // our final tex coords then when in perspective we have to
557 // do an explicit divide
558 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
559 texFunc += "Proj";
560 fsCoordName = varyingName;
561 } else {
562 fsCoordName = "tCoord";
563 fsCoordName.appendInt(stageNum);
564
565 segments->fFSCode += "\t";
566 segments->fFSCode += float_vector_type(coordDims);
567 segments->fFSCode += " ";
568 segments->fFSCode += fsCoordName;
569 segments->fFSCode += " = ";
570 segments->fFSCode += varyingName;
571 segments->fFSCode += vector_nonhomog_coords(varyingDims);
572 segments->fFSCode += " / ";
573 segments->fFSCode += varyingName;
574 segments->fFSCode += vector_homog_coord(varyingDims);
575 segments->fFSCode += ";\n";
576 }
577 }
578
579 GrSStringBuilder<96> sampleCoords;
580 switch (desc.fCoordMapping) {
581 case StageDesc::kIdentity_CoordMapping:
582 sampleCoords = fsCoordName;
583 break;
584 case StageDesc::kSweepGradient_CoordMapping:
585 sampleCoords = "vec2(atan(-";
586 sampleCoords += fsCoordName;
587 sampleCoords += ".y, -";
588 sampleCoords += fsCoordName;
589 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
590 break;
591 case StageDesc::kRadialGradient_CoordMapping:
592 sampleCoords = "vec2(length(";
593 sampleCoords += fsCoordName;
594 sampleCoords += ".xy), 0.5)";
595 break;
596 case StageDesc::kRadial2Gradient_CoordMapping: {
597 GrTokenString cName = "c";
598 GrTokenString ac4Name = "ac4";
599 GrTokenString rootName = "root";
600
601 cName.appendInt(stageNum);
602 ac4Name.appendInt(stageNum);
603 rootName.appendInt(stageNum);
604
605 GrTokenString bVar;
606 if (coordDims == varyingDims) {
607 bVar = radial2VaryingName;
608 GrAssert(2 == varyingDims);
609 } else {
610 GrAssert(3 == varyingDims);
611 bVar = "b";
612 bVar.appendInt(stageNum);
613 segments->fFSCode += "\tfloat ";
614 segments->fFSCode += bVar;
615 segments->fFSCode += " = 2.0 * (";
616 segments->fFSCode += radial2ParamsName;
617 segments->fFSCode += "[2] * ";
618 segments->fFSCode += fsCoordName;
619 segments->fFSCode += ".x ";
620 segments->fFSCode += " - ";
621 segments->fFSCode += radial2ParamsName;
622 segments->fFSCode += "[3]);\n";
623 }
624
625 segments->fFSCode += "\tfloat ";
626 segments->fFSCode += cName;
627 segments->fFSCode += " = dot(";
628 segments->fFSCode += fsCoordName;
629 segments->fFSCode += ", ";
630 segments->fFSCode += fsCoordName;
631 segments->fFSCode += ") + ";
632 segments->fFSCode += " - ";
633 segments->fFSCode += radial2ParamsName;
634 segments->fFSCode += "[4];\n";
635
636 segments->fFSCode += "\tfloat ";
637 segments->fFSCode += ac4Name;
638 segments->fFSCode += " = ";
639 segments->fFSCode += radial2ParamsName;
640 segments->fFSCode += "[0] * 4.0 * ";
641 segments->fFSCode += cName;
642 segments->fFSCode += ";\n";
643
644 segments->fFSCode += "\tfloat ";
645 segments->fFSCode += rootName;
646 segments->fFSCode += " = sqrt(abs(";
647 segments->fFSCode += bVar;
648 segments->fFSCode += " * ";
649 segments->fFSCode += bVar;
650 segments->fFSCode += " - ";
651 segments->fFSCode += ac4Name;
652 segments->fFSCode += "));\n";
653
654 sampleCoords = "vec2((-";
655 sampleCoords += bVar;
656 sampleCoords += " + ";
657 sampleCoords += radial2ParamsName;
658 sampleCoords += "[5] * ";
659 sampleCoords += rootName;
660 sampleCoords += ") * ";
661 sampleCoords += radial2ParamsName;
662 sampleCoords += "[1], 0.5)\n";
663 break;}
664 };
665
666 segments->fFSCode += "\t";
667 segments->fFSCode += fsOutColor;
668 segments->fFSCode += " = ";
669 if (NULL != fsInColor) {
670 segments->fFSCode += fsInColor;
671 segments->fFSCode += " * ";
672 }
673 segments->fFSCode += texFunc;
674 segments->fFSCode += "(";
675 segments->fFSCode += samplerName;
676 segments->fFSCode += ", ";
677 segments->fFSCode += sampleCoords;
678 segments->fFSCode += ")";
679 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
680 segments->fFSCode += ".aaaa";
681 }
682 segments->fFSCode += ";\n";
683
684}
685
686void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
687 Program* program) {
688
689 ShaderCodeSegments segments;
690 const uint32_t& layout = desc.fVertexLayout;
691
692 memset(&program->fUniLocations, 0, sizeof(UniLocations));
693
694 bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
695 desc.fOptFlags);
696
697#if ATTRIBUTE_MATRIX
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000698 segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n";
reed@google.comac10a2d2010-12-22 21:39:39 +0000699#else
700 segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
701 segments.fVSAttrs = "";
702#endif
703 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
704 if (haveColor) {
705 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
706 segments.fVaryings = "varying vec4 vColor;\n";
707 } else {
708 segments.fVaryings = "";
709 }
710
711 segments.fVSCode = "void main() {\n"
712 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
713 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
714 if (haveColor) {
715 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
716 }
717
718 if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
719 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
720 }
721 segments.fFSCode = "void main() {\n";
722
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000723 // add texture coordinates that are used to the list of vertex attr decls
724 GrTokenString texCoordAttrs[kMaxTexCoords];
725 for (int t = 0; t < kMaxTexCoords; ++t) {
726 if (VertexUsesTexCoordIdx(t, layout)) {
727 tex_attr_name(t, texCoordAttrs + t);
728
729 segments.fVSAttrs += "attribute vec2 ";
730 segments.fVSAttrs += texCoordAttrs[t];
731 segments.fVSAttrs += ";\n";
732 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000733 }
734
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000735 // for each enabled stage figure out what the input coordinates are
736 // and count the number of stages in use.
737 const char* stageInCoords[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000738 int numActiveStages = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000739
740 for (int s = 0; s < kNumStages; ++s) {
741 if (desc.fStages[s].fEnabled) {
742 if (StagePosAsTexCoordVertexLayoutBit(s) & layout) {
743 stageInCoords[s] = POS_ATTR_NAME;
744 } else {
745 int tcIdx = VertexTexCoordsForStage(s, layout);
746 // we better have input tex coordinates if stage is enabled.
747 GrAssert(tcIdx >= 0);
748 GrAssert(texCoordAttrs[tcIdx].length());
749 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
750 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000751 ++numActiveStages;
752 }
753 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000754
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000755 GrTokenString inColor = "vColor";
756
757 // if we have active stages string them together, feeding the output color
758 // of each to the next and generating code for each stage.
759 if (numActiveStages) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000760 int currActiveStage = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000761 for (int s = 0; s < kNumStages; ++s) {
762 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000763 GrTokenString outColor;
764 if (currActiveStage < (numActiveStages - 1)) {
765 outColor = "color";
766 outColor.appendInt(currActiveStage);
767 segments.fFSCode += "\tvec4 ";
768 segments.fFSCode += outColor;
769 segments.fFSCode += ";\n";
770 } else {
771 outColor = "gl_FragColor";
772 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000773 GenStageCode(s,
774 desc.fStages[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 haveColor ? inColor.cstr() : NULL,
776 outColor.cstr(),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000777 stageInCoords[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000778 &segments,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000779 &program->fUniLocations.fStages[s]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000780 ++currActiveStage;
781 inColor = outColor;
782 haveColor = true;
783 }
784 }
785 } else {
786 segments.fFSCode += "\tgl_FragColor = ";
787 if (haveColor) {
788 segments.fFSCode += inColor;
789 } else {
790 segments.fFSCode += "vec4(1,1,1,1)";
791 }
792 segments.fFSCode += ";\n";
793 }
794 segments.fFSCode += "}\n";
795 segments.fVSCode += "}\n";
796
797
798 const char* strings[4];
799 int lengths[4];
800 int stringCnt = 0;
801
802 if (segments.fVSUnis.length()) {
803 strings[stringCnt] = segments.fVSUnis.cstr();
804 lengths[stringCnt] = segments.fVSUnis.length();
805 ++stringCnt;
806 }
807 if (segments.fVSAttrs.length()) {
808 strings[stringCnt] = segments.fVSAttrs.cstr();
809 lengths[stringCnt] = segments.fVSAttrs.length();
810 ++stringCnt;
811 }
812 if (segments.fVaryings.length()) {
813 strings[stringCnt] = segments.fVaryings.cstr();
814 lengths[stringCnt] = segments.fVaryings.length();
815 ++stringCnt;
816 }
817
818 GrAssert(segments.fVSCode.length());
819 strings[stringCnt] = segments.fVSCode.cstr();
820 lengths[stringCnt] = segments.fVSCode.length();
821 ++stringCnt;
822
823#if PRINT_SHADERS
824 GrPrintf("%s%s%s%s\n",
825 segments.fVSUnis.cstr(),
826 segments.fVSAttrs.cstr(),
827 segments.fVaryings.cstr(),
828 segments.fVSCode.cstr());
829#endif
twiz@google.com0f31ca72011-03-18 17:38:11 +0000830 program->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 stringCnt,
832 strings,
833 lengths);
834
835 stringCnt = 0;
836
twiz@google.comb65e0cb2011-03-18 20:41:44 +0000837 if (strlen(GrShaderPrecision()) > 1) {
838 strings[stringCnt] = GrShaderPrecision();
839 lengths[stringCnt] = strlen(GrShaderPrecision());
reed@google.comac10a2d2010-12-22 21:39:39 +0000840 ++stringCnt;
841 }
842 if (segments.fFSUnis.length()) {
843 strings[stringCnt] = segments.fFSUnis.cstr();
844 lengths[stringCnt] = segments.fFSUnis.length();
845 ++stringCnt;
846 }
847 if (segments.fVaryings.length()) {
848 strings[stringCnt] = segments.fVaryings.cstr();
849 lengths[stringCnt] = segments.fVaryings.length();
850 ++stringCnt;
851 }
852
853 GrAssert(segments.fFSCode.length());
854 strings[stringCnt] = segments.fFSCode.cstr();
855 lengths[stringCnt] = segments.fFSCode.length();
856 ++stringCnt;
857
858#if PRINT_SHADERS
859 GrPrintf("%s%s%s%s\n",
twiz@google.comb65e0cb2011-03-18 20:41:44 +0000860 GrShaderPrecision(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000861 segments.fFSUnis.cstr(),
862 segments.fVaryings.cstr(),
863 segments.fFSCode.cstr());
864#endif
twiz@google.com0f31ca72011-03-18 17:38:11 +0000865 program->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
reed@google.comac10a2d2010-12-22 21:39:39 +0000866 stringCnt,
867 strings,
868 lengths);
869
870 program->fProgramID = GR_GL(CreateProgram());
twiz@google.com0f31ca72011-03-18 17:38:11 +0000871 const GrGLint& progID = program->fProgramID;
reed@google.comac10a2d2010-12-22 21:39:39 +0000872
873 GR_GL(AttachShader(progID, program->fVShaderID));
874 GR_GL(AttachShader(progID, program->fFShaderID));
875
876 // Bind the attrib locations to same values for all shaders
877 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000878 for (int t = 0; t < kMaxTexCoords; ++t) {
879 if (texCoordAttrs[t].length()) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000880 GR_GL(BindAttribLocation(progID,
881 TEX_ATTR_LOCATION(t),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000882 texCoordAttrs[t].cstr()));
883 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000884 }
885
886#if ATTRIBUTE_MATRIX
887 // set unis to a bogus value so that checks against -1 before
888 // flushing will pass.
889 GR_GL(BindAttribLocation(progID,
890 VIEWMAT_ATTR_LOCATION,
891 VIEW_MATRIX_NAME));
892
893 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
894
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000895 for (int s = 0; s < kNumStages; ++s) {
896 if (desc.fStages[s].fEnabled) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000897 GrStringBuilder matName;
898 tex_matrix_name(s, &matName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000899 GR_GL(BindAttribLocation(progID,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000900 TEXMAT_ATTR_LOCATION(s),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000901 matName.cstr()));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000902 program->fUniLocations.fStages[s].fTextureMatrixUni =
reed@google.comac10a2d2010-12-22 21:39:39 +0000903 BOGUS_MATRIX_UNI_LOCATION;
904 }
905 }
906#endif
907
908 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
909
910 GR_GL(LinkProgram(progID));
911
twiz@google.com0f31ca72011-03-18 17:38:11 +0000912 GrGLint linked = GR_GL_INIT_ZERO;
913 GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
reed@google.comac10a2d2010-12-22 21:39:39 +0000914 if (!linked) {
twiz@google.com0f31ca72011-03-18 17:38:11 +0000915 GrGLint infoLen = GR_GL_INIT_ZERO;
916 GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
reed@google.comac10a2d2010-12-22 21:39:39 +0000917 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
918 if (infoLen > 0) {
919 GR_GL(GetProgramInfoLog(progID,
920 infoLen+1,
921 NULL,
922 (char*)log.get()));
923 GrPrintf((char*)log.get());
924 }
925 GrAssert(!"Error linking program");
926 GR_GL(DeleteProgram(progID));
927 program->fProgramID = 0;
928 return;
929 }
930
931 // Get uniform locations
932#if !ATTRIBUTE_MATRIX
933 program->fUniLocations.fViewMatrixUni =
934 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
935 GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
936#endif
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000937 for (int s = 0; s < kNumStages; ++s) {
938 StageUniLocations& locations = program->fUniLocations.fStages[s];
939 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000940#if !ATTRIBUTE_MATRIX
941 if (locations.fTextureMatrixUni) {
942 GrTokenString texMName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000943 tex_matrix_name(s, &texMName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000944 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
945 progID,
946 texMName.cstr()));
947 GrAssert(-1 != locations.fTextureMatrixUni);
948 } else {
949 locations.fTextureMatrixUni = -1;
950
951 }
952#endif
953
954 if (locations.fSamplerUni) {
955 GrTokenString samplerName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000956 sampler_name(s, &samplerName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 locations.fSamplerUni = GR_GL(GetUniformLocation(
958 progID,
959 samplerName.cstr()));
960 GrAssert(-1 != locations.fSamplerUni);
961 } else {
962 locations.fSamplerUni = -1;
963 }
964
965 if (locations.fRadial2Uni) {
966 GrTokenString radial2ParamName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000967 radial2_param_name(s, &radial2ParamName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000968 locations.fRadial2Uni = GR_GL(GetUniformLocation(
969 progID,
970 radial2ParamName.cstr()));
971 GrAssert(-1 != locations.fRadial2Uni);
972 } else {
973 locations.fRadial2Uni = -1;
974 }
975 } else {
976 locations.fSamplerUni = -1;
977 locations.fRadial2Uni = -1;
978 locations.fTextureMatrixUni = -1;
979 }
980 }
981 GR_GL(UseProgram(progID));
982
983 // init sampler unis and set bogus values for state tracking
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000984 for (int s = 0; s < kNumStages; ++s) {
985 if (-1 != program->fUniLocations.fStages[s].fSamplerUni) {
986 GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s));
reed@google.comac10a2d2010-12-22 21:39:39 +0000987 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000988 program->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000989 program->fRadial2CenterX1[s] = GR_ScalarMax;
990 program->fRadial2Radius0[s] = -GR_ScalarMax;
reed@google.comac10a2d2010-12-22 21:39:39 +0000991 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000992 program->fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000993}
994
bsalomon@google.comffca4002011-02-22 20:34:01 +0000995void GrGpuGLShaders2::getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000996
997 // Must initialize all fields or cache will have false negatives!
998 desc->fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000999
bsalomon@google.comd16983b2011-02-02 22:42:20 +00001000 desc->fOptFlags = 0;
1001 if (kPoints_PrimitiveType != primType) {
1002 desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit;
1003 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001004#if GR_AGGRESSIVE_SHADER_OPTS
1005 if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
1006 (0xffffffff == fCurrDrawState.fColor)) {
1007 desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
1008 }
bsalomon@google.comd16983b2011-02-02 22:42:20 +00001009#endif
1010
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001011 for (int s = 0; s < kNumStages; ++s) {
1012 StageDesc& stage = desc->fStages[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001013
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001014 stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001015
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001016 if (stage.fEnabled) {
1017 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1018 GrAssert(NULL != texture);
1019 // we matrix to invert when orientation is TopDown, so make sure
1020 // we aren't in that case before flagging as identity.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001021 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001022 stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001023 } else if (!getSamplerMatrix(s).hasPerspective()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001024 stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
1025 } else {
1026 stage.fOptFlags = 0;
1027 }
1028 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
1029 case GrSamplerState::kNormal_SampleMode:
1030 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1031 break;
1032 case GrSamplerState::kRadial_SampleMode:
1033 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1034 break;
1035 case GrSamplerState::kRadial2_SampleMode:
1036 stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
1037 break;
1038 case GrSamplerState::kSweep_SampleMode:
1039 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1040 break;
1041 default:
1042 GrAssert(!"Unexpected sample mode!");
1043 break;
1044 }
1045 if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
1046 stage.fModulation = StageDesc::kAlpha_Modulation;
1047 } else {
1048 stage.fModulation = StageDesc::kColor_Modulation;
1049 }
1050 } else {
1051 stage.fOptFlags = 0;
1052 stage.fCoordMapping = (StageDesc::CoordMapping)0;
1053 stage.fModulation = (StageDesc::Modulation)0;
1054 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 }
1056}
1057
twiz@google.com0f31ca72011-03-18 17:38:11 +00001058GrGLuint GrGpuGLShaders2::CompileShader(GrGLenum type,
1059 int stringCnt,
1060 const char** strings,
1061 int* stringLengths) {
1062 GrGLuint shader = GR_GL(CreateShader(type));
reed@google.comac10a2d2010-12-22 21:39:39 +00001063 if (0 == shader) {
1064 return 0;
1065 }
1066
twiz@google.com0f31ca72011-03-18 17:38:11 +00001067 GrGLint compiled = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +00001068 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
1069 GR_GL(CompileShader(shader));
twiz@google.com0f31ca72011-03-18 17:38:11 +00001070 GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
reed@google.comac10a2d2010-12-22 21:39:39 +00001071
1072 if (!compiled) {
twiz@google.com0f31ca72011-03-18 17:38:11 +00001073 GrGLint infoLen = GR_GL_INIT_ZERO;
1074 GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
reed@google.comac10a2d2010-12-22 21:39:39 +00001075 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1076 if (infoLen > 0) {
1077 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
1078 for (int i = 0; i < stringCnt; ++i) {
1079 if (NULL == stringLengths || stringLengths[i] < 0) {
1080 GrPrintf(strings[i]);
1081 } else {
1082 GrPrintf("%.*s", stringLengths[i], strings[i]);
1083 }
1084 }
1085 GrPrintf("\n%s", log.get());
1086 }
1087 GrAssert(!"Shader compilation failed!");
1088 GR_GL(DeleteShader(shader));
1089 return 0;
1090 }
1091 return shader;
1092}
1093
1094void GrGpuGLShaders2::DeleteProgram(Program* program) {
1095 GR_GL(DeleteShader(program->fVShaderID));
1096 GR_GL(DeleteShader(program->fFShaderID));
1097 GR_GL(DeleteProgram(program->fProgramID));
1098 GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
1099}
1100
1101
1102GrGpuGLShaders2::GrGpuGLShaders2() {
1103
reed@google.comac10a2d2010-12-22 21:39:39 +00001104 fProgram = NULL;
1105 fProgramCache = new ProgramCache();
1106
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001107#if 0
reed@google.comac10a2d2010-12-22 21:39:39 +00001108 ProgramUnitTest();
1109#endif
1110}
1111
1112GrGpuGLShaders2::~GrGpuGLShaders2() {
1113 delete fProgramCache;
1114}
1115
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001116const GrMatrix& GrGpuGLShaders2::getHWSamplerMatrix(int stage) {
1117#if ATTRIBUTE_MATRIX
1118 return fHWDrawState.fSamplerStates[stage].getMatrix();
1119#else
1120 return fProgram->fTextureMatrices[stage];
1121#endif
1122}
1123
1124void GrGpuGLShaders2::recordHWSamplerMatrix(int stage, const GrMatrix& matrix){
1125#if ATTRIBUTE_MATRIX
1126 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
1127#else
1128 fProgram->fTextureMatrices[stage] = matrix;
1129#endif
1130}
1131
reed@google.comac10a2d2010-12-22 21:39:39 +00001132void GrGpuGLShaders2::resetContext() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001133
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001134 INHERITED::resetContext();
1135
reed@google.comac10a2d2010-12-22 21:39:39 +00001136 fHWGeometryState.fVertexLayout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001137 fHWGeometryState.fVertexOffset = ~0;
reed@google.comac10a2d2010-12-22 21:39:39 +00001138 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001139 for (int t = 0; t < kMaxTexCoords; ++t) {
1140 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1141 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001142 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1143
1144 fHWProgramID = 0;
1145}
1146
1147void GrGpuGLShaders2::flushViewMatrix() {
1148 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1149 GrMatrix m (
1150 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1151 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1152 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001153 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001154
1155 // ES doesn't allow you to pass true to the transpose param,
1156 // so do our own transpose
1157 GrScalar mt[] = {
1158 m[GrMatrix::kScaleX],
1159 m[GrMatrix::kSkewY],
1160 m[GrMatrix::kPersp0],
1161 m[GrMatrix::kSkewX],
1162 m[GrMatrix::kScaleY],
1163 m[GrMatrix::kPersp1],
1164 m[GrMatrix::kTransX],
1165 m[GrMatrix::kTransY],
1166 m[GrMatrix::kPersp2]
1167 };
1168#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001169 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1170 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1171 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001172#else
1173 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1174#endif
1175}
1176
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001177void GrGpuGLShaders2::flushTextureMatrix(int stage) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001178 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001179
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001180 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage];
1181
1182 GrMatrix m = getSamplerMatrix(stage);
1183 GrSamplerState::SampleMode mode =
1184 fCurrDrawState.fSamplerStates[0].getSampleMode();
1185 AdjustTextureMatrix(texture, mode, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001186
1187 // ES doesn't allow you to pass true to the transpose param,
1188 // so do our own transpose
1189 GrScalar mt[] = {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001190 m[GrMatrix::kScaleX],
1191 m[GrMatrix::kSkewY],
1192 m[GrMatrix::kPersp0],
1193 m[GrMatrix::kSkewX],
1194 m[GrMatrix::kScaleY],
1195 m[GrMatrix::kPersp1],
1196 m[GrMatrix::kTransX],
1197 m[GrMatrix::kTransY],
1198 m[GrMatrix::kPersp2]
reed@google.comac10a2d2010-12-22 21:39:39 +00001199 };
1200#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001201 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
1202 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
1203 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001204#else
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001205 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001206 1, false, mt));
reed@google.comac10a2d2010-12-22 21:39:39 +00001207#endif
1208}
1209
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001210void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001211
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001212 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001213
1214 GrScalar centerX1 = sampler.getRadial2CenterX1();
1215 GrScalar radius0 = sampler.getRadial2Radius0();
1216
1217 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1218
1219 float unis[6] = {
1220 GrScalarToFloat(a),
1221 1 / (2.f * unis[0]),
1222 GrScalarToFloat(centerX1),
1223 GrScalarToFloat(radius0),
1224 GrScalarToFloat(GrMul(radius0, radius0)),
1225 sampler.isRadial2PosRoot() ? 1.f : -1.f
1226 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001227 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1228 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001229 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001230}
1231
bsalomon@google.comffca4002011-02-22 20:34:01 +00001232void GrGpuGLShaders2::flushProgram(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001233 ProgramDesc desc;
1234 getProgramDesc(type, &desc);
1235 fProgram = fProgramCache->getProgram(desc);
1236
1237 if (fHWProgramID != fProgram->fProgramID) {
1238 GR_GL(UseProgram(fProgram->fProgramID));
1239 fHWProgramID = fProgram->fProgramID;
1240#if GR_COLLECT_STATS
1241 ++fStats.fProgChngCnt;
1242#endif
1243 }
1244}
1245
bsalomon@google.comffca4002011-02-22 20:34:01 +00001246bool GrGpuGLShaders2::flushGraphicsState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001247
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001248 if (!flushGLStateCommon(type)) {
1249 return false;
1250 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001251
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001252 if (fDirtyFlags.fRenderTargetChanged) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001253 // our coords are in pixel space and the GL matrices map to NDC
1254 // so if the viewport changed, our matrix is now wrong.
1255#if ATTRIBUTE_MATRIX
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001256 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001257#else
1258 // we assume all shader matrices may be wrong after viewport changes
1259 fProgramCache->invalidateViewMatrices();
1260#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001261 }
1262
1263 flushProgram(type);
1264
1265 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1266 // invalidate the immediate mode color
1267 fHWDrawState.fColor = GrColor_ILLEGAL;
1268 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001269 if (fHWDrawState.fColor != fCurrDrawState.fColor &&
1270 (!GR_AGGRESSIVE_SHADER_OPTS || 0xffffffff != fCurrDrawState.fColor)) {
1271 // avoid pushing the color attrib if the shader will optimize it out
1272
reed@google.comac10a2d2010-12-22 21:39:39 +00001273 // OpenGL ES only supports the float varities of glVertexAttrib
1274 float c[] = {
1275 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1276 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1277 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1278 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1279 };
1280 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1281 fHWDrawState.fColor = fCurrDrawState.fColor;
1282 }
1283 }
1284
1285#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001286 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001287#else
1288 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001289#endif
1290
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001291 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001292 flushViewMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001293 currViewMatrix = fCurrDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001294 }
1295
bsalomon@google.com316f99232011-01-13 21:28:12 +00001296 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001297 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1298 if (NULL != texture) {
1299 if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni &&
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001300 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
1301 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001302 flushTextureMatrix(s);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001303 recordHWSamplerMatrix(s, getSamplerMatrix(s));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001304 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001305 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001306
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001307 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1308 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1309 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1310 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1311 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001312
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001313 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001314
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001315 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1316 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1317 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1318 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001319 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001320 resetDirtyFlags();
reed@google.comac10a2d2010-12-22 21:39:39 +00001321 return true;
1322}
1323
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001324void GrGpuGLShaders2::setupGeometry(int* startVertex,
1325 int* startIndex,
1326 int vertexCount,
1327 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001328
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001329 int newColorOffset;
1330 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001331
twiz@google.com0f31ca72011-03-18 17:38:11 +00001332 GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1333 newTexCoordOffsets,
1334 &newColorOffset);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001335 int oldColorOffset;
1336 int oldTexCoordOffsets[kMaxTexCoords];
twiz@google.com0f31ca72011-03-18 17:38:11 +00001337 GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1338 oldTexCoordOffsets,
1339 &oldColorOffset);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001340 bool indexed = NULL != startIndex;
reed@google.comac10a2d2010-12-22 21:39:39 +00001341
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001342 int extraVertexOffset;
1343 int extraIndexOffset;
1344 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001345
twiz@google.com0f31ca72011-03-18 17:38:11 +00001346 GrGLenum scalarType;
reed@google.comac10a2d2010-12-22 21:39:39 +00001347 bool texCoordNorm;
1348 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1349 scalarType = GrGLTextType;
1350 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1351 } else {
1352 scalarType = GrGLType;
1353 texCoordNorm = false;
1354 }
1355
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001356 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
1357 *startVertex = 0;
1358 if (indexed) {
1359 *startIndex += extraIndexOffset;
1360 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001361
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001362 // all the Pointers must be set if any of these are true
1363 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
1364 vertexOffset != fHWGeometryState.fVertexOffset ||
1365 newStride != oldStride;
1366
1367 // position and tex coord offsets change if above conditions are true
1368 // or the type/normalization changed based on text vs nontext type coords.
1369 bool posAndTexChange = allOffsetsChange ||
1370 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
1371 (kTextFormat_VertexLayoutBit &
1372 (fHWGeometryState.fVertexLayout ^
1373 fGeometrySrc.fVertexLayout)));
1374
1375 if (posAndTexChange) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001376 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
twiz@google.com0f31ca72011-03-18 17:38:11 +00001377 false, newStride, (GrGLvoid*)vertexOffset));
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001378 fHWGeometryState.fVertexOffset = vertexOffset;
reed@google.comac10a2d2010-12-22 21:39:39 +00001379 }
1380
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001381 for (int t = 0; t < kMaxTexCoords; ++t) {
1382 if (newTexCoordOffsets[t] > 0) {
twiz@google.com0f31ca72011-03-18 17:38:11 +00001383 GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001384 if (oldTexCoordOffsets[t] <= 0) {
1385 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001386 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001387 texCoordNorm, newStride, texCoordOffset));
1388 } else if (posAndTexChange ||
1389 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001390 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001391 texCoordNorm, newStride, texCoordOffset));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001392 }
1393 } else if (oldTexCoordOffsets[t] > 0) {
1394 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001395 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001396 }
1397
1398 if (newColorOffset > 0) {
twiz@google.com0f31ca72011-03-18 17:38:11 +00001399 GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001400 if (oldColorOffset <= 0) {
1401 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001402 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
twiz@google.com0f31ca72011-03-18 17:38:11 +00001403 GR_GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001404 true, newStride, colorOffset));
1405 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001406 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
twiz@google.com0f31ca72011-03-18 17:38:11 +00001407 GR_GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001408 true, newStride, colorOffset));
reed@google.comac10a2d2010-12-22 21:39:39 +00001409 }
1410 } else if (oldColorOffset > 0) {
1411 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1412 }
1413
1414 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001415 fHWGeometryState.fArrayPtrsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001416}