blob: d423ee27408b13afafb62a716a9b2f30bb81641c [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 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
18#include "GrGLConfig.h"
19
20#if GR_SUPPORT_GLES2 || GR_SUPPORT_GLDESKTOP
21
22#include "GrGpuGLShaders2.h"
23#include "GrGpuVertex.h"
24#include "GrMemory.h"
25#include "GrStringBuilder.h"
26
27
28#define ATTRIBUTE_MATRIX 0
29
reed@google.comac10a2d2010-12-22 21:39:39 +000030#define PRINT_SHADERS 0
31
32#define SKIP_CACHE_CHECK true
33
34#if GR_SUPPORT_GLES2
35 #define GR_PRECISION "mediump"
36 const char GR_SHADER_PRECISION[] = "precision mediump float;\n";
37#else
38 #define GR_PRECISION ""
39 const char GR_SHADER_PRECISION[] = "";
40#endif
41
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000042
reed@google.comac10a2d2010-12-22 21:39:39 +000043#define POS_ATTR_LOCATION 0
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000044#define TEX_ATTR_LOCATION(X) (1 + X)
45#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords)
reed@google.comac10a2d2010-12-22 21:39:39 +000046#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000047#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
48#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
reed@google.comac10a2d2010-12-22 21:39:39 +000049#define BOGUS_MATRIX_UNI_LOCATION 1000
50#endif
51
reed@google.comd2938db2011-01-28 20:54:15 +000052#define GR_UINT32_MAX static_cast<uint32_t>(-1)
53
reed@google.comac10a2d2010-12-22 21:39:39 +000054struct GrGpuGLShaders2::StageUniLocations {
55 GLint fTextureMatrixUni;
56 GLint fSamplerUni;
57 GLint fRadial2Uni;
58};
59
60struct GrGpuGLShaders2::UniLocations {
61 GLint fViewMatrixUni;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000062 StageUniLocations fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000063};
64
65// Records per-program information
66// we can specify the attribute locations so that they are constant
67// across our shaders. But the driver determines the uniform locations
68// at link time. We don't need to remember the sampler uniform location
69// because we will bind a texture slot to it and never change it
70// Uniforms are program-local so we can't rely on fHWState to hold the
71// previous uniform state after a program change.
72struct GrGpuGLShaders2::Program {
73 // IDs
74 GLuint fVShaderID;
75 GLuint fFShaderID;
76 GLuint fProgramID;
77
78 // shader uniform locations (-1 if shader doesn't use them)
79 UniLocations fUniLocations;
80
81 // these reflect the current values of uniforms
82 // (GL uniform values travel with program)
83 GrMatrix fViewMatrix;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000084 GrMatrix fTextureMatrix[kNumStages];
85 GrGLTexture::Orientation fTextureOrientation[kNumStages];
86 GrScalar fRadial2CenterX1[kNumStages];
87 GrScalar fRadial2Radius0[kNumStages];
88 bool fRadial2PosRoot[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000089
90};
91
92// must be tightly packed
93struct GrGpuGLShaders2::StageDesc {
94 enum OptFlagBits {
95 kNoPerspective_OptFlagBit = 0x1,
96 kIdentityMatrix_OptFlagBit = 0x2,
97 };
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000098 unsigned fOptFlags : 8;
99
100 unsigned fEnabled : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000101
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 enum Modulation {
103 kColor_Modulation,
104 kAlpha_Modulation,
105 } fModulation : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000106
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 enum CoordMapping {
108 kIdentity_CoordMapping,
109 kRadialGradient_CoordMapping,
110 kSweepGradient_CoordMapping,
111 kRadial2Gradient_CoordMapping,
112 } fCoordMapping : 8;
113};
114
115// must be tightly packed
116struct GrGpuGLShaders2::ProgramDesc {
117 GrVertexLayout fVertexLayout;
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000118 GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field
119
reed@google.comac10a2d2010-12-22 21:39:39 +0000120 enum {
121 kNotPoints_OptFlagBit = 0x1,
122 kVertexColorAllOnes_OptFlagBit = 0x2,
123 };
124 // we're assuming optflags and layout pack into 32 bits
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000125 // VS 2010 seems to require short rather than just unsigned
126 // for this to pack
127 unsigned short fOptFlags : 16;
reed@google.comac10a2d2010-12-22 21:39:39 +0000128
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000129 StageDesc fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000130
131 bool operator == (const ProgramDesc& desc) const {
132 // keep 4-byte aligned and tightly packed
133 GR_STATIC_ASSERT(4 == sizeof(StageDesc));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000134 GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000135 return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
136 }
137};
138
139#include "GrTHashCache.h"
140
141class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
142private:
143 struct Entry;
144 class HashKey {
145 public:
146 HashKey();
147 HashKey(const ProgramDesc& desc);
148 static const HashKey& GetKey(const Entry&);
149 static bool EQ(const Entry&, const HashKey&);
150 static bool LT(const Entry&, const HashKey&);
151 bool operator <(const HashKey& key) const;
152 bool operator ==(const HashKey& key) const;
153 uint32_t getHash() const;
154 private:
155 ProgramDesc fDesc;
156 uint32_t fHash;
157 };
158
159 struct Entry {
160 Program fProgram;
161 HashKey fKey;
162 uint32_t fLRUStamp;
163 };
164
165 // if hash bits is changed, need to change hash function
166 GrTHashTable<Entry, HashKey, 8> fHashCache;
167
168 static const int MAX_ENTRIES = 16;
169 Entry fEntries[MAX_ENTRIES];
170 int fCount;
171 uint32_t fCurrLRUStamp;
172
173public:
174 ProgramCache() {
175 fCount = 0;
176 fCurrLRUStamp = 0;
177 }
178
179 ~ProgramCache() {
180 for (int i = 0; i < fCount; ++i) {
181 GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
182 }
183 }
184
185 void abandon() {
186 fCount = 0;
187 }
188
189 void invalidateViewMatrices() {
190 for (int i = 0; i < fCount; ++i) {
191 // set to illegal matrix
192 fEntries[i].fProgram.fViewMatrix.setScale(GR_ScalarMax,
193 GR_ScalarMax);
194 }
195 }
196
197 Program* getProgram(const ProgramDesc& desc) {
198 HashKey key(desc);
199 Entry* entry = fHashCache.find(key);
200 if (NULL == entry) {
201 if (fCount < MAX_ENTRIES) {
202 entry = fEntries + fCount;
203 ++fCount;
204 } else {
205 GrAssert(MAX_ENTRIES == fCount);
206 entry = fEntries;
207 for (int i = 1; i < MAX_ENTRIES; ++i) {
208 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
209 entry = fEntries + i;
210 }
211 }
212 fHashCache.remove(entry->fKey, entry);
213 GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
214 }
215 entry->fKey = key;
216 GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
217 fHashCache.insert(entry->fKey, entry);
218 }
219
220 entry->fLRUStamp = fCurrLRUStamp;
reed@google.comd2938db2011-01-28 20:54:15 +0000221 if (GR_UINT32_MAX == fCurrLRUStamp) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 // wrap around! just trash our LRU, one time hit.
223 for (int i = 0; i < fCount; ++i) {
224 fEntries[i].fLRUStamp = 0;
225 }
226 }
227 ++fCurrLRUStamp;
228 return &entry->fProgram;
229 }
230};
231
232GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
233}
234
235static uint32_t ror(uint32_t x) {
236 return (x >> 8) | (x << 24);
237}
238
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000239static uint32_t rol(uint32_t x) {
240 return (x << 8) | (x >> 24);
241}
242
reed@google.comac10a2d2010-12-22 21:39:39 +0000243GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
244 fDesc = desc;
245 // if you change the size of the desc, need to update the hash function
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000246 GR_STATIC_ASSERT(12 == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000247
reed@google.com38690072011-01-26 01:44:18 +0000248 uint32_t* d = GrTCast<uint32_t*>(&fDesc);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000249 fHash = d[0] ^ ror(d[1]) ^ rol(d[2]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000250}
251
252bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
253 const HashKey& key) {
254 return entry.fKey == key;
255}
256
257bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
258 const HashKey& key) {
259 return entry.fKey < key;
260}
261
262bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
263 return fDesc == key.fDesc;
264}
265
266bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
267 return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
268}
269
270uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
271 return fHash;
272}
273
reed@google.comac10a2d2010-12-22 21:39:39 +0000274struct GrGpuGLShaders2::ShaderCodeSegments {
275 GrSStringBuilder<256> fVSUnis;
276 GrSStringBuilder<256> fVSAttrs;
277 GrSStringBuilder<256> fVaryings;
278 GrSStringBuilder<256> fFSUnis;
279 GrSStringBuilder<512> fVSCode;
280 GrSStringBuilder<512> fFSCode;
281};
282// for variable names etc
283typedef GrSStringBuilder<16> GrTokenString;
284
285#if ATTRIBUTE_MATRIX
286 #define VIEW_MATRIX_NAME "aViewM"
287#else
288 #define VIEW_MATRIX_NAME "uViewM"
289#endif
290
291#define POS_ATTR_NAME "aPosition"
292#define COL_ATTR_NAME "aColor"
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000293
294static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
295 *s = "aTexCoord";
296 s->appendInt(coordIdx);
297}
reed@google.comac10a2d2010-12-22 21:39:39 +0000298
299static inline const char* float_vector_type(int count) {
300 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
reed@google.com38690072011-01-26 01:44:18 +0000301 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 return FLOAT_VECS[count];
303}
304
305static inline const char* vector_homog_coord(int count) {
306 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
reed@google.com38690072011-01-26 01:44:18 +0000307 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000308 return HOMOGS[count];
309}
310
311static inline const char* vector_nonhomog_coords(int count) {
312 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
reed@google.com38690072011-01-26 01:44:18 +0000313 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000314 return NONHOMOGS[count];
315}
316
317static inline const char* vector_all_coords(int count) {
318 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
reed@google.com38690072011-01-26 01:44:18 +0000319 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
reed@google.comac10a2d2010-12-22 21:39:39 +0000320 return ALL[count];
321}
322
323static void tex_matrix_name(int stage, GrStringBuilder* s) {
324#if ATTRIBUTE_MATRIX
325 *s = "aTexM";
326#else
327 *s = "uTexM";
328#endif
329 s->appendInt(stage);
330}
331
332static void sampler_name(int stage, GrStringBuilder* s) {
333 *s = "uSampler";
334 s->appendInt(stage);
335}
336
337static void stage_varying_name(int stage, GrStringBuilder* s) {
338 *s = "vStage";
339 s->appendInt(stage);
340}
341
342static void radial2_param_name(int stage, GrStringBuilder* s) {
343 *s = "uRadial2Params";
344 s->appendInt(stage);
345}
346
347static void radial2_varying_name(int stage, GrStringBuilder* s) {
348 *s = "vB";
349 s->appendInt(stage);
350}
351
352#include "GrRandom.h"
353
354void GrGpuGLShaders2::ProgramUnitTest() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000355 static const int PROG_OPTS[] = {
356 0,
357 ProgramDesc::kNotPoints_OptFlagBit,
358 ProgramDesc::kVertexColorAllOnes_OptFlagBit,
359 ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
360 };
361 static const int STAGE_OPTS[] = {
362 0,
363 StageDesc::kNoPerspective_OptFlagBit,
364 StageDesc::kIdentity_CoordMapping
365 };
366 static const int STAGE_MODULATES[] = {
367 StageDesc::kColor_Modulation,
368 StageDesc::kAlpha_Modulation
369 };
370 static const int STAGE_COORD_MAPPINGS[] = {
371 StageDesc::kIdentity_CoordMapping,
372 StageDesc::kRadialGradient_CoordMapping,
373 StageDesc::kSweepGradient_CoordMapping,
374 StageDesc::kRadial2Gradient_CoordMapping
375 };
376 ProgramDesc pdesc;
377 memset(&pdesc, 0, sizeof(pdesc));
378
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000379 static const int NUM_TESTS = 512;
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
381 // GrRandoms nextU() values have patterns in the low bits
382 // So using nextU() % array_count might never take some values.
383 GrRandom random;
384 for (int t = 0; t < NUM_TESTS; ++t) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000385
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000386 pdesc.fVertexLayout = 0;
387 for (int s = 0; s < kNumStages; ++s) {
388 // enable the stage?
389 if (random.nextF() > .5f) {
390 // use separate tex coords?
391 if (random.nextF() > .5f) {
392 int t = (int)(random.nextF() * kMaxTexCoords);
393 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
394 } else {
395 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
396 }
397 }
398 // use text-formatted verts?
399 if (random.nextF() > .5f) {
400 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
401 }
402 }
403
404 int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 pdesc.fOptFlags = PROG_OPTS[x];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000406 for (int s = 0; s < kNumStages; ++s) {
407 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000408 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
409 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
410 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000411 pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000413 pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 }
415 Program program;
416 GenProgram(pdesc, &program);
417 DeleteProgram(&program);
418 }
419}
420
421void GrGpuGLShaders2::GenStageCode(int stageNum,
422 const StageDesc& desc,
423 const char* fsInColor, // NULL means no incoming color
424 const char* fsOutColor,
425 const char* vsInCoord,
426 ShaderCodeSegments* segments,
427 StageUniLocations* locations) {
428
429 GrAssert(stageNum >= 0 && stageNum <= 9);
430
431 GrTokenString varyingName;
432 stage_varying_name(stageNum, &varyingName);
433
434 // First decide how many coords are needed to access the texture
435 // Right now it's always 2 but we could start using 1D textures for
436 // gradients.
437 static const int coordDims = 2;
438 int varyingDims;
439 /// Vertex Shader Stuff
440
441 // decide whether we need a matrix to transform texture coords
442 // and whether the varying needs a perspective coord.
443 GrTokenString texMName;
444 tex_matrix_name(stageNum, &texMName);
445 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
446 varyingDims = coordDims;
447 } else {
448 #if ATTRIBUTE_MATRIX
449 segments->fVSAttrs += "attribute mat3 ";
450 segments->fVSAttrs += texMName;
451 segments->fVSAttrs += ";\n";
452 #else
453 segments->fVSUnis += "uniform mat3 ";
454 segments->fVSUnis += texMName;
455 segments->fVSUnis += ";\n";
456 locations->fTextureMatrixUni = 1;
457 #endif
458 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
459 varyingDims = coordDims;
460 } else {
461 varyingDims = coordDims + 1;
462 }
463 }
464
465 GrTokenString samplerName;
466 sampler_name(stageNum, &samplerName);
467 segments->fFSUnis += "uniform sampler2D ";
468 segments->fFSUnis += samplerName;
469 segments->fFSUnis += ";\n";
470 locations->fSamplerUni = 1;
471
472 segments->fVaryings += "varying ";
473 segments->fVaryings += float_vector_type(varyingDims);
474 segments->fVaryings += " ";
475 segments->fVaryings += varyingName;
476 segments->fVaryings += ";\n";
477
478 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
479 GrAssert(varyingDims == coordDims);
480 segments->fVSCode += "\t";
481 segments->fVSCode += varyingName;
482 segments->fVSCode += " = ";
483 segments->fVSCode += vsInCoord;
484 segments->fVSCode += ";\n";
485 } else {
486 segments->fVSCode += "\t";
487 segments->fVSCode += varyingName;
488 segments->fVSCode += " = (";
489 segments->fVSCode += texMName;
490 segments->fVSCode += " * vec3(";
491 segments->fVSCode += vsInCoord;
492 segments->fVSCode += ", 1))";
493 segments->fVSCode += vector_all_coords(varyingDims);
494 segments->fVSCode += ";\n";
495 }
496
497 GrTokenString radial2ParamsName;
498 radial2_param_name(stageNum, &radial2ParamsName);
499 // for radial grads without perspective we can pass the linear
500 // part of the quadratic as a varying.
501 GrTokenString radial2VaryingName;
502 radial2_varying_name(stageNum, &radial2VaryingName);
503
504 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
505
506 segments->fVSUnis += "uniform " GR_PRECISION " float ";
507 segments->fVSUnis += radial2ParamsName;
508 segments->fVSUnis += "[6];\n";
509
510 segments->fFSUnis += "uniform " GR_PRECISION " float ";
511 segments->fFSUnis += radial2ParamsName;
512 segments->fFSUnis += "[6];\n";
513 locations->fRadial2Uni = 1;
514
515 // if there is perspective we don't interpolate this
516 if (varyingDims == coordDims) {
517 GrAssert(2 == coordDims);
518 segments->fVaryings += "varying float ";
519 segments->fVaryings += radial2VaryingName;
520 segments->fVaryings += ";\n";
521
522 segments->fVSCode += "\t";
523 segments->fVSCode += radial2VaryingName;
524 segments->fVSCode += " = 2.0 * (";
525 segments->fVSCode += radial2ParamsName;
526 segments->fVSCode += "[2] * ";
527 segments->fVSCode += varyingName;
528 segments->fVSCode += ".x ";
529 segments->fVSCode += " - ";
530 segments->fVSCode += radial2ParamsName;
531 segments->fVSCode += "[3]);\n";
532 }
533 }
534
535 /// Fragment Shader Stuff
536 GrTokenString fsCoordName;
537 // function used to access the shader, may be made projective
538 GrTokenString texFunc("texture2D");
539 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
540 StageDesc::kNoPerspective_OptFlagBit)) {
541 GrAssert(varyingDims == coordDims);
542 fsCoordName = varyingName;
543 } else {
544 // if we have to do some non-matrix op on the varyings to get
545 // our final tex coords then when in perspective we have to
546 // do an explicit divide
547 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
548 texFunc += "Proj";
549 fsCoordName = varyingName;
550 } else {
551 fsCoordName = "tCoord";
552 fsCoordName.appendInt(stageNum);
553
554 segments->fFSCode += "\t";
555 segments->fFSCode += float_vector_type(coordDims);
556 segments->fFSCode += " ";
557 segments->fFSCode += fsCoordName;
558 segments->fFSCode += " = ";
559 segments->fFSCode += varyingName;
560 segments->fFSCode += vector_nonhomog_coords(varyingDims);
561 segments->fFSCode += " / ";
562 segments->fFSCode += varyingName;
563 segments->fFSCode += vector_homog_coord(varyingDims);
564 segments->fFSCode += ";\n";
565 }
566 }
567
568 GrSStringBuilder<96> sampleCoords;
569 switch (desc.fCoordMapping) {
570 case StageDesc::kIdentity_CoordMapping:
571 sampleCoords = fsCoordName;
572 break;
573 case StageDesc::kSweepGradient_CoordMapping:
574 sampleCoords = "vec2(atan(-";
575 sampleCoords += fsCoordName;
576 sampleCoords += ".y, -";
577 sampleCoords += fsCoordName;
578 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
579 break;
580 case StageDesc::kRadialGradient_CoordMapping:
581 sampleCoords = "vec2(length(";
582 sampleCoords += fsCoordName;
583 sampleCoords += ".xy), 0.5)";
584 break;
585 case StageDesc::kRadial2Gradient_CoordMapping: {
586 GrTokenString cName = "c";
587 GrTokenString ac4Name = "ac4";
588 GrTokenString rootName = "root";
589
590 cName.appendInt(stageNum);
591 ac4Name.appendInt(stageNum);
592 rootName.appendInt(stageNum);
593
594 GrTokenString bVar;
595 if (coordDims == varyingDims) {
596 bVar = radial2VaryingName;
597 GrAssert(2 == varyingDims);
598 } else {
599 GrAssert(3 == varyingDims);
600 bVar = "b";
601 bVar.appendInt(stageNum);
602 segments->fFSCode += "\tfloat ";
603 segments->fFSCode += bVar;
604 segments->fFSCode += " = 2.0 * (";
605 segments->fFSCode += radial2ParamsName;
606 segments->fFSCode += "[2] * ";
607 segments->fFSCode += fsCoordName;
608 segments->fFSCode += ".x ";
609 segments->fFSCode += " - ";
610 segments->fFSCode += radial2ParamsName;
611 segments->fFSCode += "[3]);\n";
612 }
613
614 segments->fFSCode += "\tfloat ";
615 segments->fFSCode += cName;
616 segments->fFSCode += " = dot(";
617 segments->fFSCode += fsCoordName;
618 segments->fFSCode += ", ";
619 segments->fFSCode += fsCoordName;
620 segments->fFSCode += ") + ";
621 segments->fFSCode += " - ";
622 segments->fFSCode += radial2ParamsName;
623 segments->fFSCode += "[4];\n";
624
625 segments->fFSCode += "\tfloat ";
626 segments->fFSCode += ac4Name;
627 segments->fFSCode += " = ";
628 segments->fFSCode += radial2ParamsName;
629 segments->fFSCode += "[0] * 4.0 * ";
630 segments->fFSCode += cName;
631 segments->fFSCode += ";\n";
632
633 segments->fFSCode += "\tfloat ";
634 segments->fFSCode += rootName;
635 segments->fFSCode += " = sqrt(abs(";
636 segments->fFSCode += bVar;
637 segments->fFSCode += " * ";
638 segments->fFSCode += bVar;
639 segments->fFSCode += " - ";
640 segments->fFSCode += ac4Name;
641 segments->fFSCode += "));\n";
642
643 sampleCoords = "vec2((-";
644 sampleCoords += bVar;
645 sampleCoords += " + ";
646 sampleCoords += radial2ParamsName;
647 sampleCoords += "[5] * ";
648 sampleCoords += rootName;
649 sampleCoords += ") * ";
650 sampleCoords += radial2ParamsName;
651 sampleCoords += "[1], 0.5)\n";
652 break;}
653 };
654
655 segments->fFSCode += "\t";
656 segments->fFSCode += fsOutColor;
657 segments->fFSCode += " = ";
658 if (NULL != fsInColor) {
659 segments->fFSCode += fsInColor;
660 segments->fFSCode += " * ";
661 }
662 segments->fFSCode += texFunc;
663 segments->fFSCode += "(";
664 segments->fFSCode += samplerName;
665 segments->fFSCode += ", ";
666 segments->fFSCode += sampleCoords;
667 segments->fFSCode += ")";
668 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
669 segments->fFSCode += ".aaaa";
670 }
671 segments->fFSCode += ";\n";
672
673}
674
675void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
676 Program* program) {
677
678 ShaderCodeSegments segments;
679 const uint32_t& layout = desc.fVertexLayout;
680
681 memset(&program->fUniLocations, 0, sizeof(UniLocations));
682
683 bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
684 desc.fOptFlags);
685
686#if ATTRIBUTE_MATRIX
687 segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"
688#else
689 segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
690 segments.fVSAttrs = "";
691#endif
692 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
693 if (haveColor) {
694 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
695 segments.fVaryings = "varying vec4 vColor;\n";
696 } else {
697 segments.fVaryings = "";
698 }
699
700 segments.fVSCode = "void main() {\n"
701 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
702 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
703 if (haveColor) {
704 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
705 }
706
707 if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
708 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
709 }
710 segments.fFSCode = "void main() {\n";
711
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000712 // add texture coordinates that are used to the list of vertex attr decls
713 GrTokenString texCoordAttrs[kMaxTexCoords];
714 for (int t = 0; t < kMaxTexCoords; ++t) {
715 if (VertexUsesTexCoordIdx(t, layout)) {
716 tex_attr_name(t, texCoordAttrs + t);
717
718 segments.fVSAttrs += "attribute vec2 ";
719 segments.fVSAttrs += texCoordAttrs[t];
720 segments.fVSAttrs += ";\n";
721 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000722 }
723
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000724 // for each enabled stage figure out what the input coordinates are
725 // and count the number of stages in use.
726 const char* stageInCoords[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000727 int numActiveStages = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000728
729 for (int s = 0; s < kNumStages; ++s) {
730 if (desc.fStages[s].fEnabled) {
731 if (StagePosAsTexCoordVertexLayoutBit(s) & layout) {
732 stageInCoords[s] = POS_ATTR_NAME;
733 } else {
734 int tcIdx = VertexTexCoordsForStage(s, layout);
735 // we better have input tex coordinates if stage is enabled.
736 GrAssert(tcIdx >= 0);
737 GrAssert(texCoordAttrs[tcIdx].length());
738 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
739 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000740 ++numActiveStages;
741 }
742 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000743
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000744 GrTokenString inColor = "vColor";
745
746 // if we have active stages string them together, feeding the output color
747 // of each to the next and generating code for each stage.
748 if (numActiveStages) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000749 int currActiveStage = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000750 for (int s = 0; s < kNumStages; ++s) {
751 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000752 GrTokenString outColor;
753 if (currActiveStage < (numActiveStages - 1)) {
754 outColor = "color";
755 outColor.appendInt(currActiveStage);
756 segments.fFSCode += "\tvec4 ";
757 segments.fFSCode += outColor;
758 segments.fFSCode += ";\n";
759 } else {
760 outColor = "gl_FragColor";
761 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000762 GenStageCode(s,
763 desc.fStages[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000764 haveColor ? inColor.cstr() : NULL,
765 outColor.cstr(),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000766 stageInCoords[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000767 &segments,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000768 &program->fUniLocations.fStages[s]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000769 ++currActiveStage;
770 inColor = outColor;
771 haveColor = true;
772 }
773 }
774 } else {
775 segments.fFSCode += "\tgl_FragColor = ";
776 if (haveColor) {
777 segments.fFSCode += inColor;
778 } else {
779 segments.fFSCode += "vec4(1,1,1,1)";
780 }
781 segments.fFSCode += ";\n";
782 }
783 segments.fFSCode += "}\n";
784 segments.fVSCode += "}\n";
785
786
787 const char* strings[4];
788 int lengths[4];
789 int stringCnt = 0;
790
791 if (segments.fVSUnis.length()) {
792 strings[stringCnt] = segments.fVSUnis.cstr();
793 lengths[stringCnt] = segments.fVSUnis.length();
794 ++stringCnt;
795 }
796 if (segments.fVSAttrs.length()) {
797 strings[stringCnt] = segments.fVSAttrs.cstr();
798 lengths[stringCnt] = segments.fVSAttrs.length();
799 ++stringCnt;
800 }
801 if (segments.fVaryings.length()) {
802 strings[stringCnt] = segments.fVaryings.cstr();
803 lengths[stringCnt] = segments.fVaryings.length();
804 ++stringCnt;
805 }
806
807 GrAssert(segments.fVSCode.length());
808 strings[stringCnt] = segments.fVSCode.cstr();
809 lengths[stringCnt] = segments.fVSCode.length();
810 ++stringCnt;
811
812#if PRINT_SHADERS
813 GrPrintf("%s%s%s%s\n",
814 segments.fVSUnis.cstr(),
815 segments.fVSAttrs.cstr(),
816 segments.fVaryings.cstr(),
817 segments.fVSCode.cstr());
818#endif
819 program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
820 stringCnt,
821 strings,
822 lengths);
823
824 stringCnt = 0;
825
826 if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
827 strings[stringCnt] = GR_SHADER_PRECISION;
828 lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
829 ++stringCnt;
830 }
831 if (segments.fFSUnis.length()) {
832 strings[stringCnt] = segments.fFSUnis.cstr();
833 lengths[stringCnt] = segments.fFSUnis.length();
834 ++stringCnt;
835 }
836 if (segments.fVaryings.length()) {
837 strings[stringCnt] = segments.fVaryings.cstr();
838 lengths[stringCnt] = segments.fVaryings.length();
839 ++stringCnt;
840 }
841
842 GrAssert(segments.fFSCode.length());
843 strings[stringCnt] = segments.fFSCode.cstr();
844 lengths[stringCnt] = segments.fFSCode.length();
845 ++stringCnt;
846
847#if PRINT_SHADERS
848 GrPrintf("%s%s%s%s\n",
849 GR_SHADER_PRECISION,
850 segments.fFSUnis.cstr(),
851 segments.fVaryings.cstr(),
852 segments.fFSCode.cstr());
853#endif
854 program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
855 stringCnt,
856 strings,
857 lengths);
858
859 program->fProgramID = GR_GL(CreateProgram());
860 const GLint& progID = program->fProgramID;
861
862 GR_GL(AttachShader(progID, program->fVShaderID));
863 GR_GL(AttachShader(progID, program->fFShaderID));
864
865 // Bind the attrib locations to same values for all shaders
866 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000867 for (int t = 0; t < kMaxTexCoords; ++t) {
868 if (texCoordAttrs[t].length()) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000869 GR_GL(BindAttribLocation(progID,
870 TEX_ATTR_LOCATION(t),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000871 texCoordAttrs[t].cstr()));
872 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 }
874
875#if ATTRIBUTE_MATRIX
876 // set unis to a bogus value so that checks against -1 before
877 // flushing will pass.
878 GR_GL(BindAttribLocation(progID,
879 VIEWMAT_ATTR_LOCATION,
880 VIEW_MATRIX_NAME));
881
882 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
883
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000884 for (int s = 0; s < kNumStages; ++s) {
885 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000886 GR_GL(BindAttribLocation(progID,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000887 TEXMAT_ATTR_LOCATION(s),
reed@google.comac10a2d2010-12-22 21:39:39 +0000888 tex_matrix_name(i).cstr()));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000889 program->fUniLocations.fStages[s].fTextureMatrixUni =
reed@google.comac10a2d2010-12-22 21:39:39 +0000890 BOGUS_MATRIX_UNI_LOCATION;
891 }
892 }
893#endif
894
895 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
896
897 GR_GL(LinkProgram(progID));
898
reed@google.com5f6ee1a2011-01-31 14:24:48 +0000899 GLint linked = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +0000900 GR_GL(GetProgramiv(progID, GL_LINK_STATUS, &linked));
901 if (!linked) {
reed@google.com5f6ee1a2011-01-31 14:24:48 +0000902 GLint infoLen = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +0000903 GR_GL(GetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen));
904 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
905 if (infoLen > 0) {
906 GR_GL(GetProgramInfoLog(progID,
907 infoLen+1,
908 NULL,
909 (char*)log.get()));
910 GrPrintf((char*)log.get());
911 }
912 GrAssert(!"Error linking program");
913 GR_GL(DeleteProgram(progID));
914 program->fProgramID = 0;
915 return;
916 }
917
918 // Get uniform locations
919#if !ATTRIBUTE_MATRIX
920 program->fUniLocations.fViewMatrixUni =
921 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
922 GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
923#endif
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000924 for (int s = 0; s < kNumStages; ++s) {
925 StageUniLocations& locations = program->fUniLocations.fStages[s];
926 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000927#if !ATTRIBUTE_MATRIX
928 if (locations.fTextureMatrixUni) {
929 GrTokenString texMName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000930 tex_matrix_name(s, &texMName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
932 progID,
933 texMName.cstr()));
934 GrAssert(-1 != locations.fTextureMatrixUni);
935 } else {
936 locations.fTextureMatrixUni = -1;
937
938 }
939#endif
940
941 if (locations.fSamplerUni) {
942 GrTokenString samplerName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000943 sampler_name(s, &samplerName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000944 locations.fSamplerUni = GR_GL(GetUniformLocation(
945 progID,
946 samplerName.cstr()));
947 GrAssert(-1 != locations.fSamplerUni);
948 } else {
949 locations.fSamplerUni = -1;
950 }
951
952 if (locations.fRadial2Uni) {
953 GrTokenString radial2ParamName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000954 radial2_param_name(s, &radial2ParamName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000955 locations.fRadial2Uni = GR_GL(GetUniformLocation(
956 progID,
957 radial2ParamName.cstr()));
958 GrAssert(-1 != locations.fRadial2Uni);
959 } else {
960 locations.fRadial2Uni = -1;
961 }
962 } else {
963 locations.fSamplerUni = -1;
964 locations.fRadial2Uni = -1;
965 locations.fTextureMatrixUni = -1;
966 }
967 }
968 GR_GL(UseProgram(progID));
969
970 // init sampler unis and set bogus values for state tracking
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000971 for (int s = 0; s < kNumStages; ++s) {
972 if (-1 != program->fUniLocations.fStages[s].fSamplerUni) {
973 GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s));
reed@google.comac10a2d2010-12-22 21:39:39 +0000974 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000975 program->fTextureMatrix[s].setScale(GR_ScalarMax, GR_ScalarMax);
976 program->fRadial2CenterX1[s] = GR_ScalarMax;
977 program->fRadial2Radius0[s] = -GR_ScalarMax;
reed@google.comac10a2d2010-12-22 21:39:39 +0000978 }
979 program->fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
980}
981
982void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
983
984 // Must initialize all fields or cache will have false negatives!
985 desc->fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000986
bsalomon@google.comd16983b2011-02-02 22:42:20 +0000987 desc->fOptFlags = 0;
988 if (kPoints_PrimitiveType != primType) {
989 desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit;
990 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000991#if GR_AGGRESSIVE_SHADER_OPTS
992 if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
993 (0xffffffff == fCurrDrawState.fColor)) {
994 desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
995 }
bsalomon@google.comd16983b2011-02-02 22:42:20 +0000996#endif
997
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000998 for (int s = 0; s < kNumStages; ++s) {
999 StageDesc& stage = desc->fStages[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001000
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001001 stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001002
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001003 if (stage.fEnabled) {
1004 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1005 GrAssert(NULL != texture);
1006 // we matrix to invert when orientation is TopDown, so make sure
1007 // we aren't in that case before flagging as identity.
1008 if (fCurrDrawState.fTextureMatrices[s].isIdentity() &&
1009 GrGLTexture::kTopDown_Orientation == texture->orientation()) {
1010 stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
1011 } else if (!fCurrDrawState.fTextureMatrices[s].hasPerspective()) {
1012 stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
1013 } else {
1014 stage.fOptFlags = 0;
1015 }
1016 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
1017 case GrSamplerState::kNormal_SampleMode:
1018 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1019 break;
1020 case GrSamplerState::kRadial_SampleMode:
1021 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1022 break;
1023 case GrSamplerState::kRadial2_SampleMode:
1024 stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
1025 break;
1026 case GrSamplerState::kSweep_SampleMode:
1027 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1028 break;
1029 default:
1030 GrAssert(!"Unexpected sample mode!");
1031 break;
1032 }
1033 if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
1034 stage.fModulation = StageDesc::kAlpha_Modulation;
1035 } else {
1036 stage.fModulation = StageDesc::kColor_Modulation;
1037 }
1038 } else {
1039 stage.fOptFlags = 0;
1040 stage.fCoordMapping = (StageDesc::CoordMapping)0;
1041 stage.fModulation = (StageDesc::Modulation)0;
1042 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 }
1044}
1045
1046GLuint GrGpuGLShaders2::CompileShader(GLenum type,
1047 int stringCnt,
1048 const char** strings,
1049 int* stringLengths) {
1050 GLuint shader = GR_GL(CreateShader(type));
1051 if (0 == shader) {
1052 return 0;
1053 }
1054
reed@google.com5f6ee1a2011-01-31 14:24:48 +00001055 GLint compiled = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +00001056 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
1057 GR_GL(CompileShader(shader));
1058 GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
1059
1060 if (!compiled) {
reed@google.com5f6ee1a2011-01-31 14:24:48 +00001061 GLint infoLen = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +00001062 GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
1063 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1064 if (infoLen > 0) {
1065 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
1066 for (int i = 0; i < stringCnt; ++i) {
1067 if (NULL == stringLengths || stringLengths[i] < 0) {
1068 GrPrintf(strings[i]);
1069 } else {
1070 GrPrintf("%.*s", stringLengths[i], strings[i]);
1071 }
1072 }
1073 GrPrintf("\n%s", log.get());
1074 }
1075 GrAssert(!"Shader compilation failed!");
1076 GR_GL(DeleteShader(shader));
1077 return 0;
1078 }
1079 return shader;
1080}
1081
1082void GrGpuGLShaders2::DeleteProgram(Program* program) {
1083 GR_GL(DeleteShader(program->fVShaderID));
1084 GR_GL(DeleteShader(program->fFShaderID));
1085 GR_GL(DeleteProgram(program->fProgramID));
1086 GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
1087}
1088
1089
1090GrGpuGLShaders2::GrGpuGLShaders2() {
1091
1092 resetContextHelper();
1093
1094 fProgram = NULL;
1095 fProgramCache = new ProgramCache();
1096
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001097#if 0
reed@google.comac10a2d2010-12-22 21:39:39 +00001098 ProgramUnitTest();
1099#endif
1100}
1101
1102GrGpuGLShaders2::~GrGpuGLShaders2() {
1103 delete fProgramCache;
1104}
1105
1106void GrGpuGLShaders2::resetContext() {
1107 INHERITED::resetContext();
1108 resetContextHelper();
1109}
1110
1111void GrGpuGLShaders2::resetContextHelper() {
1112 fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
1113
1114 fHWGeometryState.fVertexLayout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001115 fHWGeometryState.fVertexOffset = ~0;
reed@google.comac10a2d2010-12-22 21:39:39 +00001116 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001117 for (int t = 0; t < kMaxTexCoords; ++t) {
1118 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1119 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001120 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1121
1122 fHWProgramID = 0;
1123}
1124
1125void GrGpuGLShaders2::flushViewMatrix() {
1126 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1127 GrMatrix m (
1128 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1129 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1130 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001131 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001132
1133 // ES doesn't allow you to pass true to the transpose param,
1134 // so do our own transpose
1135 GrScalar mt[] = {
1136 m[GrMatrix::kScaleX],
1137 m[GrMatrix::kSkewY],
1138 m[GrMatrix::kPersp0],
1139 m[GrMatrix::kSkewX],
1140 m[GrMatrix::kScaleY],
1141 m[GrMatrix::kPersp1],
1142 m[GrMatrix::kTransX],
1143 m[GrMatrix::kTransY],
1144 m[GrMatrix::kPersp2]
1145 };
1146#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001147 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1148 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1149 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001150#else
1151 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1152#endif
1153}
1154
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001155void GrGpuGLShaders2::flushTextureMatrix(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001156
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001157 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001158 GrGLTexture::Orientation orientation =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001159 ((GrGLTexture*)fCurrDrawState.fTextures[stage])->orientation();
reed@google.comac10a2d2010-12-22 21:39:39 +00001160
1161 GrMatrix* m;
1162 GrMatrix temp;
1163 if (GrGLTexture::kBottomUp_Orientation == orientation) {
1164 temp.setAll(
1165 GR_Scalar1, 0, 0,
1166 0, -GR_Scalar1, GR_Scalar1,
1167 0, 0, GrMatrix::I()[8]
1168 );
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001169 temp.preConcat(fCurrDrawState.fTextureMatrices[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001170 m = &temp;
1171 } else {
1172 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001173 m = &fCurrDrawState.fTextureMatrices[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001174 }
1175
1176 // ES doesn't allow you to pass true to the transpose param,
1177 // so do our own transpose
1178 GrScalar mt[] = {
1179 (*m)[GrMatrix::kScaleX],
1180 (*m)[GrMatrix::kSkewY],
1181 (*m)[GrMatrix::kPersp0],
1182 (*m)[GrMatrix::kSkewX],
1183 (*m)[GrMatrix::kScaleY],
1184 (*m)[GrMatrix::kPersp1],
1185 (*m)[GrMatrix::kTransX],
1186 (*m)[GrMatrix::kTransY],
1187 (*m)[GrMatrix::kPersp2]
1188 };
1189#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001190 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
1191 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
1192 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001193#else
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001194 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni,
reed@google.comac10a2d2010-12-22 21:39:39 +00001195 1,
1196 false,
1197 mt));
1198#endif
1199}
1200
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001201void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001202
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001203 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001204
1205 GrScalar centerX1 = sampler.getRadial2CenterX1();
1206 GrScalar radius0 = sampler.getRadial2Radius0();
1207
1208 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1209
1210 float unis[6] = {
1211 GrScalarToFloat(a),
1212 1 / (2.f * unis[0]),
1213 GrScalarToFloat(centerX1),
1214 GrScalarToFloat(radius0),
1215 GrScalarToFloat(GrMul(radius0, radius0)),
1216 sampler.isRadial2PosRoot() ? 1.f : -1.f
1217 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001218 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1219 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001220 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001221}
1222
1223void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
1224 ProgramDesc desc;
1225 getProgramDesc(type, &desc);
1226 fProgram = fProgramCache->getProgram(desc);
1227
1228 if (fHWProgramID != fProgram->fProgramID) {
1229 GR_GL(UseProgram(fProgram->fProgramID));
1230 fHWProgramID = fProgram->fProgramID;
1231#if GR_COLLECT_STATS
1232 ++fStats.fProgChngCnt;
1233#endif
1234 }
1235}
1236
1237bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
1238
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001239 if (!flushGLStateCommon(type)) {
1240 return false;
1241 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001242
1243 if (fRenderTargetChanged) {
1244 // our coords are in pixel space and the GL matrices map to NDC
1245 // so if the viewport changed, our matrix is now wrong.
1246#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001247 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
reed@google.comac10a2d2010-12-22 21:39:39 +00001248#else
1249 // we assume all shader matrices may be wrong after viewport changes
1250 fProgramCache->invalidateViewMatrices();
1251#endif
1252 fRenderTargetChanged = false;
1253 }
1254
1255 flushProgram(type);
1256
1257 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1258 // invalidate the immediate mode color
1259 fHWDrawState.fColor = GrColor_ILLEGAL;
1260 } else {
1261 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
1262 // OpenGL ES only supports the float varities of glVertexAttrib
1263 float c[] = {
1264 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1265 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1266 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1267 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1268 };
1269 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1270 fHWDrawState.fColor = fCurrDrawState.fColor;
1271 }
1272 }
1273
1274#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001275 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001276 GrMatrix& currTextureMatrix = fHWDrawState.fMatrixModeCache[kTexture_MatrixMode];
1277 GrGLTexture::Orientation& orientation = fTextureOrientation;
1278#else
1279 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
1280 GrMatrix& currTextureMatrix = fProgram->fTextureMatrix[0];
1281 GrGLTexture::Orientation& orientation = fProgram->fTextureOrientation[0];
1282#endif
1283
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001284 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001285 flushViewMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001286 currViewMatrix = fCurrDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 }
1288
bsalomon@google.com316f99232011-01-13 21:28:12 +00001289 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001290 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1291 if (NULL != texture) {
1292 if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni &&
1293 (currTextureMatrix != fCurrDrawState.fTextureMatrices[s] ||
1294 orientation != texture->orientation())) {
1295 flushTextureMatrix(s);
1296 currTextureMatrix = fCurrDrawState.fTextureMatrices[s];
1297 orientation = texture->orientation();
1298 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001299 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001300
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001301 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1302 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1303 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1304 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1305 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001306
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001307 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001308
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001309 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1310 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1311 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1312 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001313 }
1314
1315 return true;
1316}
1317
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001318void GrGpuGLShaders2::setupGeometry(int* startVertex,
1319 int* startIndex,
1320 int vertexCount,
1321 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001322
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001323 int newColorOffset;
1324 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001325
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001326 GLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1327 newTexCoordOffsets,
1328 &newColorOffset);
1329 int oldColorOffset;
1330 int oldTexCoordOffsets[kMaxTexCoords];
1331 GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1332 oldTexCoordOffsets,
1333 &oldColorOffset);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001334 bool indexed = NULL != startIndex;
reed@google.comac10a2d2010-12-22 21:39:39 +00001335
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001336 int extraVertexOffset;
1337 int extraIndexOffset;
1338 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001339
1340 GLenum scalarType;
1341 bool texCoordNorm;
1342 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1343 scalarType = GrGLTextType;
1344 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1345 } else {
1346 scalarType = GrGLType;
1347 texCoordNorm = false;
1348 }
1349
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001350 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
1351 *startVertex = 0;
1352 if (indexed) {
1353 *startIndex += extraIndexOffset;
1354 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001355
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001356 // all the Pointers must be set if any of these are true
1357 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
1358 vertexOffset != fHWGeometryState.fVertexOffset ||
1359 newStride != oldStride;
1360
1361 // position and tex coord offsets change if above conditions are true
1362 // or the type/normalization changed based on text vs nontext type coords.
1363 bool posAndTexChange = allOffsetsChange ||
1364 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
1365 (kTextFormat_VertexLayoutBit &
1366 (fHWGeometryState.fVertexLayout ^
1367 fGeometrySrc.fVertexLayout)));
1368
1369 if (posAndTexChange) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001370 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001371 false, newStride, (GLvoid*)vertexOffset));
1372 fHWGeometryState.fVertexOffset = vertexOffset;
reed@google.comac10a2d2010-12-22 21:39:39 +00001373 }
1374
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001375 for (int t = 0; t < kMaxTexCoords; ++t) {
1376 if (newTexCoordOffsets[t] > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001377 GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001378 if (oldTexCoordOffsets[t] <= 0) {
1379 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001380 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001381 texCoordNorm, newStride, texCoordOffset));
1382 } else if (posAndTexChange ||
1383 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001384 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001385 texCoordNorm, newStride, texCoordOffset));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001386 }
1387 } else if (oldTexCoordOffsets[t] > 0) {
1388 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001389 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001390 }
1391
1392 if (newColorOffset > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001393 GLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001394 if (oldColorOffset <= 0) {
1395 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001396 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1397 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001398 true, newStride, colorOffset));
1399 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001400 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1401 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001402 true, newStride, colorOffset));
reed@google.comac10a2d2010-12-22 21:39:39 +00001403 }
1404 } else if (oldColorOffset > 0) {
1405 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1406 }
1407
1408 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001409 fHWGeometryState.fArrayPtrsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001410}
1411#endif
1412
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001413