blob: 88c2b5c2cd531167700918d5b6cf1116eef4ba55 [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
30#define SKIP_COLOR_MODULATE_OPT 0
31
32#define PRINT_SHADERS 0
33
34#define SKIP_CACHE_CHECK true
35
36#if GR_SUPPORT_GLES2
37 #define GR_PRECISION "mediump"
38 const char GR_SHADER_PRECISION[] = "precision mediump float;\n";
39#else
40 #define GR_PRECISION ""
41 const char GR_SHADER_PRECISION[] = "";
42#endif
43
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000044
reed@google.comac10a2d2010-12-22 21:39:39 +000045#define POS_ATTR_LOCATION 0
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000046#define TEX_ATTR_LOCATION(X) (1 + X)
47#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords)
reed@google.comac10a2d2010-12-22 21:39:39 +000048#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000049#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
50#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
reed@google.comac10a2d2010-12-22 21:39:39 +000051#define BOGUS_MATRIX_UNI_LOCATION 1000
52#endif
53
reed@google.comd2938db2011-01-28 20:54:15 +000054#define GR_UINT32_MAX static_cast<uint32_t>(-1)
55
reed@google.comac10a2d2010-12-22 21:39:39 +000056struct GrGpuGLShaders2::StageUniLocations {
57 GLint fTextureMatrixUni;
58 GLint fSamplerUni;
59 GLint fRadial2Uni;
60};
61
62struct GrGpuGLShaders2::UniLocations {
63 GLint fViewMatrixUni;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000064 StageUniLocations fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000065};
66
67// Records per-program information
68// we can specify the attribute locations so that they are constant
69// across our shaders. But the driver determines the uniform locations
70// at link time. We don't need to remember the sampler uniform location
71// because we will bind a texture slot to it and never change it
72// Uniforms are program-local so we can't rely on fHWState to hold the
73// previous uniform state after a program change.
74struct GrGpuGLShaders2::Program {
75 // IDs
76 GLuint fVShaderID;
77 GLuint fFShaderID;
78 GLuint fProgramID;
79
80 // shader uniform locations (-1 if shader doesn't use them)
81 UniLocations fUniLocations;
82
83 // these reflect the current values of uniforms
84 // (GL uniform values travel with program)
85 GrMatrix fViewMatrix;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000086 GrMatrix fTextureMatrix[kNumStages];
87 GrGLTexture::Orientation fTextureOrientation[kNumStages];
88 GrScalar fRadial2CenterX1[kNumStages];
89 GrScalar fRadial2Radius0[kNumStages];
90 bool fRadial2PosRoot[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000091
92};
93
94// must be tightly packed
95struct GrGpuGLShaders2::StageDesc {
96 enum OptFlagBits {
97 kNoPerspective_OptFlagBit = 0x1,
98 kIdentityMatrix_OptFlagBit = 0x2,
99 };
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000100 unsigned fOptFlags : 8;
101
102 unsigned fEnabled : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000103
reed@google.comac10a2d2010-12-22 21:39:39 +0000104 enum Modulation {
105 kColor_Modulation,
106 kAlpha_Modulation,
107 } fModulation : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000108
reed@google.comac10a2d2010-12-22 21:39:39 +0000109 enum CoordMapping {
110 kIdentity_CoordMapping,
111 kRadialGradient_CoordMapping,
112 kSweepGradient_CoordMapping,
113 kRadial2Gradient_CoordMapping,
114 } fCoordMapping : 8;
115};
116
117// must be tightly packed
118struct GrGpuGLShaders2::ProgramDesc {
119 GrVertexLayout fVertexLayout;
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000120 GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field
121
reed@google.comac10a2d2010-12-22 21:39:39 +0000122 enum {
123 kNotPoints_OptFlagBit = 0x1,
124 kVertexColorAllOnes_OptFlagBit = 0x2,
125 };
126 // we're assuming optflags and layout pack into 32 bits
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000127 // VS 2010 seems to require short rather than just unsigned
128 // for this to pack
129 unsigned short fOptFlags : 16;
reed@google.comac10a2d2010-12-22 21:39:39 +0000130
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000131 StageDesc fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000132
133 bool operator == (const ProgramDesc& desc) const {
134 // keep 4-byte aligned and tightly packed
135 GR_STATIC_ASSERT(4 == sizeof(StageDesc));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000136 GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000137 return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
138 }
139};
140
141#include "GrTHashCache.h"
142
143class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
144private:
145 struct Entry;
146 class HashKey {
147 public:
148 HashKey();
149 HashKey(const ProgramDesc& desc);
150 static const HashKey& GetKey(const Entry&);
151 static bool EQ(const Entry&, const HashKey&);
152 static bool LT(const Entry&, const HashKey&);
153 bool operator <(const HashKey& key) const;
154 bool operator ==(const HashKey& key) const;
155 uint32_t getHash() const;
156 private:
157 ProgramDesc fDesc;
158 uint32_t fHash;
159 };
160
161 struct Entry {
162 Program fProgram;
163 HashKey fKey;
164 uint32_t fLRUStamp;
165 };
166
167 // if hash bits is changed, need to change hash function
168 GrTHashTable<Entry, HashKey, 8> fHashCache;
169
170 static const int MAX_ENTRIES = 16;
171 Entry fEntries[MAX_ENTRIES];
172 int fCount;
173 uint32_t fCurrLRUStamp;
174
175public:
176 ProgramCache() {
177 fCount = 0;
178 fCurrLRUStamp = 0;
179 }
180
181 ~ProgramCache() {
182 for (int i = 0; i < fCount; ++i) {
183 GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
184 }
185 }
186
187 void abandon() {
188 fCount = 0;
189 }
190
191 void invalidateViewMatrices() {
192 for (int i = 0; i < fCount; ++i) {
193 // set to illegal matrix
194 fEntries[i].fProgram.fViewMatrix.setScale(GR_ScalarMax,
195 GR_ScalarMax);
196 }
197 }
198
199 Program* getProgram(const ProgramDesc& desc) {
200 HashKey key(desc);
201 Entry* entry = fHashCache.find(key);
202 if (NULL == entry) {
203 if (fCount < MAX_ENTRIES) {
204 entry = fEntries + fCount;
205 ++fCount;
206 } else {
207 GrAssert(MAX_ENTRIES == fCount);
208 entry = fEntries;
209 for (int i = 1; i < MAX_ENTRIES; ++i) {
210 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
211 entry = fEntries + i;
212 }
213 }
214 fHashCache.remove(entry->fKey, entry);
215 GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
216 }
217 entry->fKey = key;
218 GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
219 fHashCache.insert(entry->fKey, entry);
220 }
221
222 entry->fLRUStamp = fCurrLRUStamp;
reed@google.comd2938db2011-01-28 20:54:15 +0000223 if (GR_UINT32_MAX == fCurrLRUStamp) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000224 // wrap around! just trash our LRU, one time hit.
225 for (int i = 0; i < fCount; ++i) {
226 fEntries[i].fLRUStamp = 0;
227 }
228 }
229 ++fCurrLRUStamp;
230 return &entry->fProgram;
231 }
232};
233
234GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
235}
236
237static uint32_t ror(uint32_t x) {
238 return (x >> 8) | (x << 24);
239}
240
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000241static uint32_t rol(uint32_t x) {
242 return (x << 8) | (x >> 24);
243}
244
reed@google.comac10a2d2010-12-22 21:39:39 +0000245GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
246 fDesc = desc;
247 // if you change the size of the desc, need to update the hash function
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000248 GR_STATIC_ASSERT(12 == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000249
reed@google.com38690072011-01-26 01:44:18 +0000250 uint32_t* d = GrTCast<uint32_t*>(&fDesc);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000251 fHash = d[0] ^ ror(d[1]) ^ rol(d[2]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000252}
253
254bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
255 const HashKey& key) {
256 return entry.fKey == key;
257}
258
259bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
260 const HashKey& key) {
261 return entry.fKey < key;
262}
263
264bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
265 return fDesc == key.fDesc;
266}
267
268bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
269 return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
270}
271
272uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
273 return fHash;
274}
275
reed@google.comac10a2d2010-12-22 21:39:39 +0000276struct GrGpuGLShaders2::ShaderCodeSegments {
277 GrSStringBuilder<256> fVSUnis;
278 GrSStringBuilder<256> fVSAttrs;
279 GrSStringBuilder<256> fVaryings;
280 GrSStringBuilder<256> fFSUnis;
281 GrSStringBuilder<512> fVSCode;
282 GrSStringBuilder<512> fFSCode;
283};
284// for variable names etc
285typedef GrSStringBuilder<16> GrTokenString;
286
287#if ATTRIBUTE_MATRIX
288 #define VIEW_MATRIX_NAME "aViewM"
289#else
290 #define VIEW_MATRIX_NAME "uViewM"
291#endif
292
293#define POS_ATTR_NAME "aPosition"
294#define COL_ATTR_NAME "aColor"
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000295
296static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
297 *s = "aTexCoord";
298 s->appendInt(coordIdx);
299}
reed@google.comac10a2d2010-12-22 21:39:39 +0000300
301static inline const char* float_vector_type(int count) {
302 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
reed@google.com38690072011-01-26 01:44:18 +0000303 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 return FLOAT_VECS[count];
305}
306
307static inline const char* vector_homog_coord(int count) {
308 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
reed@google.com38690072011-01-26 01:44:18 +0000309 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000310 return HOMOGS[count];
311}
312
313static inline const char* vector_nonhomog_coords(int count) {
314 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
reed@google.com38690072011-01-26 01:44:18 +0000315 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 return NONHOMOGS[count];
317}
318
319static inline const char* vector_all_coords(int count) {
320 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
reed@google.com38690072011-01-26 01:44:18 +0000321 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
reed@google.comac10a2d2010-12-22 21:39:39 +0000322 return ALL[count];
323}
324
325static void tex_matrix_name(int stage, GrStringBuilder* s) {
326#if ATTRIBUTE_MATRIX
327 *s = "aTexM";
328#else
329 *s = "uTexM";
330#endif
331 s->appendInt(stage);
332}
333
334static void sampler_name(int stage, GrStringBuilder* s) {
335 *s = "uSampler";
336 s->appendInt(stage);
337}
338
339static void stage_varying_name(int stage, GrStringBuilder* s) {
340 *s = "vStage";
341 s->appendInt(stage);
342}
343
344static void radial2_param_name(int stage, GrStringBuilder* s) {
345 *s = "uRadial2Params";
346 s->appendInt(stage);
347}
348
349static void radial2_varying_name(int stage, GrStringBuilder* s) {
350 *s = "vB";
351 s->appendInt(stage);
352}
353
354#include "GrRandom.h"
355
356void GrGpuGLShaders2::ProgramUnitTest() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000357 static const int PROG_OPTS[] = {
358 0,
359 ProgramDesc::kNotPoints_OptFlagBit,
360 ProgramDesc::kVertexColorAllOnes_OptFlagBit,
361 ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
362 };
363 static const int STAGE_OPTS[] = {
364 0,
365 StageDesc::kNoPerspective_OptFlagBit,
366 StageDesc::kIdentity_CoordMapping
367 };
368 static const int STAGE_MODULATES[] = {
369 StageDesc::kColor_Modulation,
370 StageDesc::kAlpha_Modulation
371 };
372 static const int STAGE_COORD_MAPPINGS[] = {
373 StageDesc::kIdentity_CoordMapping,
374 StageDesc::kRadialGradient_CoordMapping,
375 StageDesc::kSweepGradient_CoordMapping,
376 StageDesc::kRadial2Gradient_CoordMapping
377 };
378 ProgramDesc pdesc;
379 memset(&pdesc, 0, sizeof(pdesc));
380
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000381 static const int NUM_TESTS = 512;
reed@google.comac10a2d2010-12-22 21:39:39 +0000382
383 // GrRandoms nextU() values have patterns in the low bits
384 // So using nextU() % array_count might never take some values.
385 GrRandom random;
386 for (int t = 0; t < NUM_TESTS; ++t) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000387
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000388 pdesc.fVertexLayout = 0;
389 for (int s = 0; s < kNumStages; ++s) {
390 // enable the stage?
391 if (random.nextF() > .5f) {
392 // use separate tex coords?
393 if (random.nextF() > .5f) {
394 int t = (int)(random.nextF() * kMaxTexCoords);
395 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
396 } else {
397 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
398 }
399 }
400 // use text-formatted verts?
401 if (random.nextF() > .5f) {
402 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
403 }
404 }
405
406 int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 pdesc.fOptFlags = PROG_OPTS[x];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000408 for (int s = 0; s < kNumStages; ++s) {
409 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000410 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
411 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
412 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000413 pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000415 pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000416 }
417 Program program;
418 GenProgram(pdesc, &program);
419 DeleteProgram(&program);
420 }
421}
422
423void GrGpuGLShaders2::GenStageCode(int stageNum,
424 const StageDesc& desc,
425 const char* fsInColor, // NULL means no incoming color
426 const char* fsOutColor,
427 const char* vsInCoord,
428 ShaderCodeSegments* segments,
429 StageUniLocations* locations) {
430
431 GrAssert(stageNum >= 0 && stageNum <= 9);
432
433 GrTokenString varyingName;
434 stage_varying_name(stageNum, &varyingName);
435
436 // First decide how many coords are needed to access the texture
437 // Right now it's always 2 but we could start using 1D textures for
438 // gradients.
439 static const int coordDims = 2;
440 int varyingDims;
441 /// Vertex Shader Stuff
442
443 // decide whether we need a matrix to transform texture coords
444 // and whether the varying needs a perspective coord.
445 GrTokenString texMName;
446 tex_matrix_name(stageNum, &texMName);
447 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
448 varyingDims = coordDims;
449 } else {
450 #if ATTRIBUTE_MATRIX
451 segments->fVSAttrs += "attribute mat3 ";
452 segments->fVSAttrs += texMName;
453 segments->fVSAttrs += ";\n";
454 #else
455 segments->fVSUnis += "uniform mat3 ";
456 segments->fVSUnis += texMName;
457 segments->fVSUnis += ";\n";
458 locations->fTextureMatrixUni = 1;
459 #endif
460 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
461 varyingDims = coordDims;
462 } else {
463 varyingDims = coordDims + 1;
464 }
465 }
466
467 GrTokenString samplerName;
468 sampler_name(stageNum, &samplerName);
469 segments->fFSUnis += "uniform sampler2D ";
470 segments->fFSUnis += samplerName;
471 segments->fFSUnis += ";\n";
472 locations->fSamplerUni = 1;
473
474 segments->fVaryings += "varying ";
475 segments->fVaryings += float_vector_type(varyingDims);
476 segments->fVaryings += " ";
477 segments->fVaryings += varyingName;
478 segments->fVaryings += ";\n";
479
480 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
481 GrAssert(varyingDims == coordDims);
482 segments->fVSCode += "\t";
483 segments->fVSCode += varyingName;
484 segments->fVSCode += " = ";
485 segments->fVSCode += vsInCoord;
486 segments->fVSCode += ";\n";
487 } else {
488 segments->fVSCode += "\t";
489 segments->fVSCode += varyingName;
490 segments->fVSCode += " = (";
491 segments->fVSCode += texMName;
492 segments->fVSCode += " * vec3(";
493 segments->fVSCode += vsInCoord;
494 segments->fVSCode += ", 1))";
495 segments->fVSCode += vector_all_coords(varyingDims);
496 segments->fVSCode += ";\n";
497 }
498
499 GrTokenString radial2ParamsName;
500 radial2_param_name(stageNum, &radial2ParamsName);
501 // for radial grads without perspective we can pass the linear
502 // part of the quadratic as a varying.
503 GrTokenString radial2VaryingName;
504 radial2_varying_name(stageNum, &radial2VaryingName);
505
506 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
507
508 segments->fVSUnis += "uniform " GR_PRECISION " float ";
509 segments->fVSUnis += radial2ParamsName;
510 segments->fVSUnis += "[6];\n";
511
512 segments->fFSUnis += "uniform " GR_PRECISION " float ";
513 segments->fFSUnis += radial2ParamsName;
514 segments->fFSUnis += "[6];\n";
515 locations->fRadial2Uni = 1;
516
517 // if there is perspective we don't interpolate this
518 if (varyingDims == coordDims) {
519 GrAssert(2 == coordDims);
520 segments->fVaryings += "varying float ";
521 segments->fVaryings += radial2VaryingName;
522 segments->fVaryings += ";\n";
523
524 segments->fVSCode += "\t";
525 segments->fVSCode += radial2VaryingName;
526 segments->fVSCode += " = 2.0 * (";
527 segments->fVSCode += radial2ParamsName;
528 segments->fVSCode += "[2] * ";
529 segments->fVSCode += varyingName;
530 segments->fVSCode += ".x ";
531 segments->fVSCode += " - ";
532 segments->fVSCode += radial2ParamsName;
533 segments->fVSCode += "[3]);\n";
534 }
535 }
536
537 /// Fragment Shader Stuff
538 GrTokenString fsCoordName;
539 // function used to access the shader, may be made projective
540 GrTokenString texFunc("texture2D");
541 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
542 StageDesc::kNoPerspective_OptFlagBit)) {
543 GrAssert(varyingDims == coordDims);
544 fsCoordName = varyingName;
545 } else {
546 // if we have to do some non-matrix op on the varyings to get
547 // our final tex coords then when in perspective we have to
548 // do an explicit divide
549 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
550 texFunc += "Proj";
551 fsCoordName = varyingName;
552 } else {
553 fsCoordName = "tCoord";
554 fsCoordName.appendInt(stageNum);
555
556 segments->fFSCode += "\t";
557 segments->fFSCode += float_vector_type(coordDims);
558 segments->fFSCode += " ";
559 segments->fFSCode += fsCoordName;
560 segments->fFSCode += " = ";
561 segments->fFSCode += varyingName;
562 segments->fFSCode += vector_nonhomog_coords(varyingDims);
563 segments->fFSCode += " / ";
564 segments->fFSCode += varyingName;
565 segments->fFSCode += vector_homog_coord(varyingDims);
566 segments->fFSCode += ";\n";
567 }
568 }
569
570 GrSStringBuilder<96> sampleCoords;
571 switch (desc.fCoordMapping) {
572 case StageDesc::kIdentity_CoordMapping:
573 sampleCoords = fsCoordName;
574 break;
575 case StageDesc::kSweepGradient_CoordMapping:
576 sampleCoords = "vec2(atan(-";
577 sampleCoords += fsCoordName;
578 sampleCoords += ".y, -";
579 sampleCoords += fsCoordName;
580 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
581 break;
582 case StageDesc::kRadialGradient_CoordMapping:
583 sampleCoords = "vec2(length(";
584 sampleCoords += fsCoordName;
585 sampleCoords += ".xy), 0.5)";
586 break;
587 case StageDesc::kRadial2Gradient_CoordMapping: {
588 GrTokenString cName = "c";
589 GrTokenString ac4Name = "ac4";
590 GrTokenString rootName = "root";
591
592 cName.appendInt(stageNum);
593 ac4Name.appendInt(stageNum);
594 rootName.appendInt(stageNum);
595
596 GrTokenString bVar;
597 if (coordDims == varyingDims) {
598 bVar = radial2VaryingName;
599 GrAssert(2 == varyingDims);
600 } else {
601 GrAssert(3 == varyingDims);
602 bVar = "b";
603 bVar.appendInt(stageNum);
604 segments->fFSCode += "\tfloat ";
605 segments->fFSCode += bVar;
606 segments->fFSCode += " = 2.0 * (";
607 segments->fFSCode += radial2ParamsName;
608 segments->fFSCode += "[2] * ";
609 segments->fFSCode += fsCoordName;
610 segments->fFSCode += ".x ";
611 segments->fFSCode += " - ";
612 segments->fFSCode += radial2ParamsName;
613 segments->fFSCode += "[3]);\n";
614 }
615
616 segments->fFSCode += "\tfloat ";
617 segments->fFSCode += cName;
618 segments->fFSCode += " = dot(";
619 segments->fFSCode += fsCoordName;
620 segments->fFSCode += ", ";
621 segments->fFSCode += fsCoordName;
622 segments->fFSCode += ") + ";
623 segments->fFSCode += " - ";
624 segments->fFSCode += radial2ParamsName;
625 segments->fFSCode += "[4];\n";
626
627 segments->fFSCode += "\tfloat ";
628 segments->fFSCode += ac4Name;
629 segments->fFSCode += " = ";
630 segments->fFSCode += radial2ParamsName;
631 segments->fFSCode += "[0] * 4.0 * ";
632 segments->fFSCode += cName;
633 segments->fFSCode += ";\n";
634
635 segments->fFSCode += "\tfloat ";
636 segments->fFSCode += rootName;
637 segments->fFSCode += " = sqrt(abs(";
638 segments->fFSCode += bVar;
639 segments->fFSCode += " * ";
640 segments->fFSCode += bVar;
641 segments->fFSCode += " - ";
642 segments->fFSCode += ac4Name;
643 segments->fFSCode += "));\n";
644
645 sampleCoords = "vec2((-";
646 sampleCoords += bVar;
647 sampleCoords += " + ";
648 sampleCoords += radial2ParamsName;
649 sampleCoords += "[5] * ";
650 sampleCoords += rootName;
651 sampleCoords += ") * ";
652 sampleCoords += radial2ParamsName;
653 sampleCoords += "[1], 0.5)\n";
654 break;}
655 };
656
657 segments->fFSCode += "\t";
658 segments->fFSCode += fsOutColor;
659 segments->fFSCode += " = ";
660 if (NULL != fsInColor) {
661 segments->fFSCode += fsInColor;
662 segments->fFSCode += " * ";
663 }
664 segments->fFSCode += texFunc;
665 segments->fFSCode += "(";
666 segments->fFSCode += samplerName;
667 segments->fFSCode += ", ";
668 segments->fFSCode += sampleCoords;
669 segments->fFSCode += ")";
670 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
671 segments->fFSCode += ".aaaa";
672 }
673 segments->fFSCode += ";\n";
674
675}
676
677void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
678 Program* program) {
679
680 ShaderCodeSegments segments;
681 const uint32_t& layout = desc.fVertexLayout;
682
683 memset(&program->fUniLocations, 0, sizeof(UniLocations));
684
685 bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
686 desc.fOptFlags);
687
688#if ATTRIBUTE_MATRIX
689 segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"
690#else
691 segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
692 segments.fVSAttrs = "";
693#endif
694 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
695 if (haveColor) {
696 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
697 segments.fVaryings = "varying vec4 vColor;\n";
698 } else {
699 segments.fVaryings = "";
700 }
701
702 segments.fVSCode = "void main() {\n"
703 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
704 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
705 if (haveColor) {
706 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
707 }
708
709 if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
710 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
711 }
712 segments.fFSCode = "void main() {\n";
713
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000714 // add texture coordinates that are used to the list of vertex attr decls
715 GrTokenString texCoordAttrs[kMaxTexCoords];
716 for (int t = 0; t < kMaxTexCoords; ++t) {
717 if (VertexUsesTexCoordIdx(t, layout)) {
718 tex_attr_name(t, texCoordAttrs + t);
719
720 segments.fVSAttrs += "attribute vec2 ";
721 segments.fVSAttrs += texCoordAttrs[t];
722 segments.fVSAttrs += ";\n";
723 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000724 }
725
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000726 // for each enabled stage figure out what the input coordinates are
727 // and count the number of stages in use.
728 const char* stageInCoords[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000729 int numActiveStages = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000730
731 for (int s = 0; s < kNumStages; ++s) {
732 if (desc.fStages[s].fEnabled) {
733 if (StagePosAsTexCoordVertexLayoutBit(s) & layout) {
734 stageInCoords[s] = POS_ATTR_NAME;
735 } else {
736 int tcIdx = VertexTexCoordsForStage(s, layout);
737 // we better have input tex coordinates if stage is enabled.
738 GrAssert(tcIdx >= 0);
739 GrAssert(texCoordAttrs[tcIdx].length());
740 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
741 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000742 ++numActiveStages;
743 }
744 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000745
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000746 GrTokenString inColor = "vColor";
747
748 // if we have active stages string them together, feeding the output color
749 // of each to the next and generating code for each stage.
750 if (numActiveStages) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000751 int currActiveStage = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000752 for (int s = 0; s < kNumStages; ++s) {
753 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000754 GrTokenString outColor;
755 if (currActiveStage < (numActiveStages - 1)) {
756 outColor = "color";
757 outColor.appendInt(currActiveStage);
758 segments.fFSCode += "\tvec4 ";
759 segments.fFSCode += outColor;
760 segments.fFSCode += ";\n";
761 } else {
762 outColor = "gl_FragColor";
763 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000764 GenStageCode(s,
765 desc.fStages[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000766 haveColor ? inColor.cstr() : NULL,
767 outColor.cstr(),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000768 stageInCoords[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000769 &segments,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000770 &program->fUniLocations.fStages[s]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000771 ++currActiveStage;
772 inColor = outColor;
773 haveColor = true;
774 }
775 }
776 } else {
777 segments.fFSCode += "\tgl_FragColor = ";
778 if (haveColor) {
779 segments.fFSCode += inColor;
780 } else {
781 segments.fFSCode += "vec4(1,1,1,1)";
782 }
783 segments.fFSCode += ";\n";
784 }
785 segments.fFSCode += "}\n";
786 segments.fVSCode += "}\n";
787
788
789 const char* strings[4];
790 int lengths[4];
791 int stringCnt = 0;
792
793 if (segments.fVSUnis.length()) {
794 strings[stringCnt] = segments.fVSUnis.cstr();
795 lengths[stringCnt] = segments.fVSUnis.length();
796 ++stringCnt;
797 }
798 if (segments.fVSAttrs.length()) {
799 strings[stringCnt] = segments.fVSAttrs.cstr();
800 lengths[stringCnt] = segments.fVSAttrs.length();
801 ++stringCnt;
802 }
803 if (segments.fVaryings.length()) {
804 strings[stringCnt] = segments.fVaryings.cstr();
805 lengths[stringCnt] = segments.fVaryings.length();
806 ++stringCnt;
807 }
808
809 GrAssert(segments.fVSCode.length());
810 strings[stringCnt] = segments.fVSCode.cstr();
811 lengths[stringCnt] = segments.fVSCode.length();
812 ++stringCnt;
813
814#if PRINT_SHADERS
815 GrPrintf("%s%s%s%s\n",
816 segments.fVSUnis.cstr(),
817 segments.fVSAttrs.cstr(),
818 segments.fVaryings.cstr(),
819 segments.fVSCode.cstr());
820#endif
821 program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
822 stringCnt,
823 strings,
824 lengths);
825
826 stringCnt = 0;
827
828 if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
829 strings[stringCnt] = GR_SHADER_PRECISION;
830 lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
831 ++stringCnt;
832 }
833 if (segments.fFSUnis.length()) {
834 strings[stringCnt] = segments.fFSUnis.cstr();
835 lengths[stringCnt] = segments.fFSUnis.length();
836 ++stringCnt;
837 }
838 if (segments.fVaryings.length()) {
839 strings[stringCnt] = segments.fVaryings.cstr();
840 lengths[stringCnt] = segments.fVaryings.length();
841 ++stringCnt;
842 }
843
844 GrAssert(segments.fFSCode.length());
845 strings[stringCnt] = segments.fFSCode.cstr();
846 lengths[stringCnt] = segments.fFSCode.length();
847 ++stringCnt;
848
849#if PRINT_SHADERS
850 GrPrintf("%s%s%s%s\n",
851 GR_SHADER_PRECISION,
852 segments.fFSUnis.cstr(),
853 segments.fVaryings.cstr(),
854 segments.fFSCode.cstr());
855#endif
856 program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
857 stringCnt,
858 strings,
859 lengths);
860
861 program->fProgramID = GR_GL(CreateProgram());
862 const GLint& progID = program->fProgramID;
863
864 GR_GL(AttachShader(progID, program->fVShaderID));
865 GR_GL(AttachShader(progID, program->fFShaderID));
866
867 // Bind the attrib locations to same values for all shaders
868 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000869 for (int t = 0; t < kMaxTexCoords; ++t) {
870 if (texCoordAttrs[t].length()) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000871 GR_GL(BindAttribLocation(progID,
872 TEX_ATTR_LOCATION(t),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000873 texCoordAttrs[t].cstr()));
874 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000875 }
876
877#if ATTRIBUTE_MATRIX
878 // set unis to a bogus value so that checks against -1 before
879 // flushing will pass.
880 GR_GL(BindAttribLocation(progID,
881 VIEWMAT_ATTR_LOCATION,
882 VIEW_MATRIX_NAME));
883
884 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
885
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000886 for (int s = 0; s < kNumStages; ++s) {
887 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000888 GR_GL(BindAttribLocation(progID,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000889 TEXMAT_ATTR_LOCATION(s),
reed@google.comac10a2d2010-12-22 21:39:39 +0000890 tex_matrix_name(i).cstr()));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000891 program->fUniLocations.fStages[s].fTextureMatrixUni =
reed@google.comac10a2d2010-12-22 21:39:39 +0000892 BOGUS_MATRIX_UNI_LOCATION;
893 }
894 }
895#endif
896
897 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
898
899 GR_GL(LinkProgram(progID));
900
901 GLint linked;
902 GR_GL(GetProgramiv(progID, GL_LINK_STATUS, &linked));
903 if (!linked) {
904 GLint infoLen;
905 GR_GL(GetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen));
906 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
907 if (infoLen > 0) {
908 GR_GL(GetProgramInfoLog(progID,
909 infoLen+1,
910 NULL,
911 (char*)log.get()));
912 GrPrintf((char*)log.get());
913 }
914 GrAssert(!"Error linking program");
915 GR_GL(DeleteProgram(progID));
916 program->fProgramID = 0;
917 return;
918 }
919
920 // Get uniform locations
921#if !ATTRIBUTE_MATRIX
922 program->fUniLocations.fViewMatrixUni =
923 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
924 GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
925#endif
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000926 for (int s = 0; s < kNumStages; ++s) {
927 StageUniLocations& locations = program->fUniLocations.fStages[s];
928 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000929#if !ATTRIBUTE_MATRIX
930 if (locations.fTextureMatrixUni) {
931 GrTokenString texMName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000932 tex_matrix_name(s, &texMName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000933 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
934 progID,
935 texMName.cstr()));
936 GrAssert(-1 != locations.fTextureMatrixUni);
937 } else {
938 locations.fTextureMatrixUni = -1;
939
940 }
941#endif
942
943 if (locations.fSamplerUni) {
944 GrTokenString samplerName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000945 sampler_name(s, &samplerName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000946 locations.fSamplerUni = GR_GL(GetUniformLocation(
947 progID,
948 samplerName.cstr()));
949 GrAssert(-1 != locations.fSamplerUni);
950 } else {
951 locations.fSamplerUni = -1;
952 }
953
954 if (locations.fRadial2Uni) {
955 GrTokenString radial2ParamName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000956 radial2_param_name(s, &radial2ParamName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 locations.fRadial2Uni = GR_GL(GetUniformLocation(
958 progID,
959 radial2ParamName.cstr()));
960 GrAssert(-1 != locations.fRadial2Uni);
961 } else {
962 locations.fRadial2Uni = -1;
963 }
964 } else {
965 locations.fSamplerUni = -1;
966 locations.fRadial2Uni = -1;
967 locations.fTextureMatrixUni = -1;
968 }
969 }
970 GR_GL(UseProgram(progID));
971
972 // init sampler unis and set bogus values for state tracking
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000973 for (int s = 0; s < kNumStages; ++s) {
974 if (-1 != program->fUniLocations.fStages[s].fSamplerUni) {
975 GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s));
reed@google.comac10a2d2010-12-22 21:39:39 +0000976 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000977 program->fTextureMatrix[s].setScale(GR_ScalarMax, GR_ScalarMax);
978 program->fRadial2CenterX1[s] = GR_ScalarMax;
979 program->fRadial2Radius0[s] = -GR_ScalarMax;
reed@google.comac10a2d2010-12-22 21:39:39 +0000980 }
981 program->fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
982}
983
984void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
985
986 // Must initialize all fields or cache will have false negatives!
987 desc->fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000988 for (int s = 0; s < kNumStages; ++s) {
989 StageDesc& stage = desc->fStages[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +0000990
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000991 stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000992
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000993 if (primType != kPoints_PrimitiveType) {
994 desc->fOptFlags = ProgramDesc::kNotPoints_OptFlagBit;
reed@google.comac10a2d2010-12-22 21:39:39 +0000995 } else {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000996 desc->fOptFlags = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000998 #if SKIP_COLOR_MODULATE_OPT
999 if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
1000 (0xffffffff == fCurrDrawState.fColor)) {
1001 desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
reed@google.comac10a2d2010-12-22 21:39:39 +00001002 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001003 #endif
1004
1005 if (stage.fEnabled) {
1006 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1007 GrAssert(NULL != texture);
1008 // we matrix to invert when orientation is TopDown, so make sure
1009 // we aren't in that case before flagging as identity.
1010 if (fCurrDrawState.fTextureMatrices[s].isIdentity() &&
1011 GrGLTexture::kTopDown_Orientation == texture->orientation()) {
1012 stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
1013 } else if (!fCurrDrawState.fTextureMatrices[s].hasPerspective()) {
1014 stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
1015 } else {
1016 stage.fOptFlags = 0;
1017 }
1018 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
1019 case GrSamplerState::kNormal_SampleMode:
1020 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1021 break;
1022 case GrSamplerState::kRadial_SampleMode:
1023 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1024 break;
1025 case GrSamplerState::kRadial2_SampleMode:
1026 stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
1027 break;
1028 case GrSamplerState::kSweep_SampleMode:
1029 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1030 break;
1031 default:
1032 GrAssert(!"Unexpected sample mode!");
1033 break;
1034 }
1035 if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
1036 stage.fModulation = StageDesc::kAlpha_Modulation;
1037 } else {
1038 stage.fModulation = StageDesc::kColor_Modulation;
1039 }
1040 } else {
1041 stage.fOptFlags = 0;
1042 stage.fCoordMapping = (StageDesc::CoordMapping)0;
1043 stage.fModulation = (StageDesc::Modulation)0;
1044 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001045 }
1046}
1047
1048GLuint GrGpuGLShaders2::CompileShader(GLenum type,
1049 int stringCnt,
1050 const char** strings,
1051 int* stringLengths) {
1052 GLuint shader = GR_GL(CreateShader(type));
1053 if (0 == shader) {
1054 return 0;
1055 }
1056
1057 GLint compiled;
1058 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
1059 GR_GL(CompileShader(shader));
1060 GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
1061
1062 if (!compiled) {
1063 GLint infoLen;
1064 GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
1065 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1066 if (infoLen > 0) {
1067 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
1068 for (int i = 0; i < stringCnt; ++i) {
1069 if (NULL == stringLengths || stringLengths[i] < 0) {
1070 GrPrintf(strings[i]);
1071 } else {
1072 GrPrintf("%.*s", stringLengths[i], strings[i]);
1073 }
1074 }
1075 GrPrintf("\n%s", log.get());
1076 }
1077 GrAssert(!"Shader compilation failed!");
1078 GR_GL(DeleteShader(shader));
1079 return 0;
1080 }
1081 return shader;
1082}
1083
1084void GrGpuGLShaders2::DeleteProgram(Program* program) {
1085 GR_GL(DeleteShader(program->fVShaderID));
1086 GR_GL(DeleteShader(program->fFShaderID));
1087 GR_GL(DeleteProgram(program->fProgramID));
1088 GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
1089}
1090
1091
1092GrGpuGLShaders2::GrGpuGLShaders2() {
1093
1094 resetContextHelper();
1095
1096 fProgram = NULL;
1097 fProgramCache = new ProgramCache();
1098
1099#if GR_DEBUG
1100 ProgramUnitTest();
1101#endif
1102}
1103
1104GrGpuGLShaders2::~GrGpuGLShaders2() {
1105 delete fProgramCache;
1106}
1107
1108void GrGpuGLShaders2::resetContext() {
1109 INHERITED::resetContext();
1110 resetContextHelper();
1111}
1112
1113void GrGpuGLShaders2::resetContextHelper() {
1114 fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
1115
1116 fHWGeometryState.fVertexLayout = 0;
1117 fHWGeometryState.fPositionPtr = (void*) ~0;
1118 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001119 for (int t = 0; t < kMaxTexCoords; ++t) {
1120 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1121 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001122 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1123
1124 fHWProgramID = 0;
1125}
1126
1127void GrGpuGLShaders2::flushViewMatrix() {
1128 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1129 GrMatrix m (
1130 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1131 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1132 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001133 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001134
1135 // ES doesn't allow you to pass true to the transpose param,
1136 // so do our own transpose
1137 GrScalar mt[] = {
1138 m[GrMatrix::kScaleX],
1139 m[GrMatrix::kSkewY],
1140 m[GrMatrix::kPersp0],
1141 m[GrMatrix::kSkewX],
1142 m[GrMatrix::kScaleY],
1143 m[GrMatrix::kPersp1],
1144 m[GrMatrix::kTransX],
1145 m[GrMatrix::kTransY],
1146 m[GrMatrix::kPersp2]
1147 };
1148#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001149 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1150 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1151 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001152#else
1153 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1154#endif
1155}
1156
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001157void GrGpuGLShaders2::flushTextureMatrix(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001158
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001159 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001160 GrGLTexture::Orientation orientation =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001161 ((GrGLTexture*)fCurrDrawState.fTextures[stage])->orientation();
reed@google.comac10a2d2010-12-22 21:39:39 +00001162
1163 GrMatrix* m;
1164 GrMatrix temp;
1165 if (GrGLTexture::kBottomUp_Orientation == orientation) {
1166 temp.setAll(
1167 GR_Scalar1, 0, 0,
1168 0, -GR_Scalar1, GR_Scalar1,
1169 0, 0, GrMatrix::I()[8]
1170 );
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001171 temp.preConcat(fCurrDrawState.fTextureMatrices[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001172 m = &temp;
1173 } else {
1174 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001175 m = &fCurrDrawState.fTextureMatrices[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001176 }
1177
1178 // ES doesn't allow you to pass true to the transpose param,
1179 // so do our own transpose
1180 GrScalar mt[] = {
1181 (*m)[GrMatrix::kScaleX],
1182 (*m)[GrMatrix::kSkewY],
1183 (*m)[GrMatrix::kPersp0],
1184 (*m)[GrMatrix::kSkewX],
1185 (*m)[GrMatrix::kScaleY],
1186 (*m)[GrMatrix::kPersp1],
1187 (*m)[GrMatrix::kTransX],
1188 (*m)[GrMatrix::kTransY],
1189 (*m)[GrMatrix::kPersp2]
1190 };
1191#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001192 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
1193 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
1194 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001195#else
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001196 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni,
reed@google.comac10a2d2010-12-22 21:39:39 +00001197 1,
1198 false,
1199 mt));
1200#endif
1201}
1202
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001203void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001204
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001205 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001206
1207 GrScalar centerX1 = sampler.getRadial2CenterX1();
1208 GrScalar radius0 = sampler.getRadial2Radius0();
1209
1210 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1211
1212 float unis[6] = {
1213 GrScalarToFloat(a),
1214 1 / (2.f * unis[0]),
1215 GrScalarToFloat(centerX1),
1216 GrScalarToFloat(radius0),
1217 GrScalarToFloat(GrMul(radius0, radius0)),
1218 sampler.isRadial2PosRoot() ? 1.f : -1.f
1219 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001220 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1221 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001222 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001223}
1224
1225void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
1226 ProgramDesc desc;
1227 getProgramDesc(type, &desc);
1228 fProgram = fProgramCache->getProgram(desc);
1229
1230 if (fHWProgramID != fProgram->fProgramID) {
1231 GR_GL(UseProgram(fProgram->fProgramID));
1232 fHWProgramID = fProgram->fProgramID;
1233#if GR_COLLECT_STATS
1234 ++fStats.fProgChngCnt;
1235#endif
1236 }
1237}
1238
1239bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
1240
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001241 if (!flushGLStateCommon(type)) {
1242 return false;
1243 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001244
1245 if (fRenderTargetChanged) {
1246 // our coords are in pixel space and the GL matrices map to NDC
1247 // so if the viewport changed, our matrix is now wrong.
1248#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001249 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
reed@google.comac10a2d2010-12-22 21:39:39 +00001250#else
1251 // we assume all shader matrices may be wrong after viewport changes
1252 fProgramCache->invalidateViewMatrices();
1253#endif
1254 fRenderTargetChanged = false;
1255 }
1256
1257 flushProgram(type);
1258
1259 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1260 // invalidate the immediate mode color
1261 fHWDrawState.fColor = GrColor_ILLEGAL;
1262 } else {
1263 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
1264 // OpenGL ES only supports the float varities of glVertexAttrib
1265 float c[] = {
1266 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1267 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1268 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1269 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1270 };
1271 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1272 fHWDrawState.fColor = fCurrDrawState.fColor;
1273 }
1274 }
1275
1276#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001277 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001278 GrMatrix& currTextureMatrix = fHWDrawState.fMatrixModeCache[kTexture_MatrixMode];
1279 GrGLTexture::Orientation& orientation = fTextureOrientation;
1280#else
1281 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
1282 GrMatrix& currTextureMatrix = fProgram->fTextureMatrix[0];
1283 GrGLTexture::Orientation& orientation = fProgram->fTextureOrientation[0];
1284#endif
1285
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001286 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 flushViewMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001288 currViewMatrix = fCurrDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001289 }
1290
bsalomon@google.com316f99232011-01-13 21:28:12 +00001291 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001292 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1293 if (NULL != texture) {
1294 if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni &&
1295 (currTextureMatrix != fCurrDrawState.fTextureMatrices[s] ||
1296 orientation != texture->orientation())) {
1297 flushTextureMatrix(s);
1298 currTextureMatrix = fCurrDrawState.fTextureMatrices[s];
1299 orientation = texture->orientation();
1300 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001301 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001302
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001303 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1304 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1305 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1306 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1307 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001308
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001309 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001310
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001311 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1312 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1313 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1314 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001315 }
1316
1317 return true;
1318}
1319
1320void GrGpuGLShaders2::setupGeometry(uint32_t startVertex,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001321 uint32_t startIndex,
1322 uint32_t vertexCount,
1323 uint32_t indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001324
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001325 int newColorOffset;
1326 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001327
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001328 GLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1329 newTexCoordOffsets,
1330 &newColorOffset);
1331 int oldColorOffset;
1332 int oldTexCoordOffsets[kMaxTexCoords];
1333 GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1334 oldTexCoordOffsets,
1335 &oldColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001336
1337 const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
1338
1339 if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
1340 GrAssert(NULL != fGeometrySrc.fVertexBuffer);
1341 GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
1342 if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
1343 GrGLVertexBuffer* buf =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001344 (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001345 GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
1346 fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
1347 }
1348 } else {
1349 if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
1350 posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
1351 (intptr_t)posPtr);
1352 } else {
1353 GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
1354 posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
1355 }
1356 if (NULL != fHWGeometryState.fVertexBuffer) {
1357 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
1358 fHWGeometryState.fVertexBuffer = NULL;
1359 }
1360 }
1361
1362 if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1363 GrAssert(NULL != fGeometrySrc.fIndexBuffer);
1364 GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
1365 if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001366 GrGLIndexBuffer* buf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001367 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
1368 fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
1369 }
1370 } else if (NULL != fHWGeometryState.fIndexBuffer) {
1371 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
1372 fHWGeometryState.fIndexBuffer = NULL;
1373 }
1374
1375 GLenum scalarType;
1376 bool texCoordNorm;
1377 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1378 scalarType = GrGLTextType;
1379 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1380 } else {
1381 scalarType = GrGLType;
1382 texCoordNorm = false;
1383 }
1384
1385 bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
1386 bool scalarChange = (GrGLTextType != GrGLType) &&
1387 (kTextFormat_VertexLayoutBit &
1388 (fHWGeometryState.fVertexLayout ^
1389 fGeometrySrc.fVertexLayout));
1390 bool strideChange = newStride != oldStride;
1391 bool posChange = baseChange || scalarChange || strideChange;
1392
1393 if (posChange) {
1394 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
1395 false, newStride, posPtr));
1396 fHWGeometryState.fPositionPtr = posPtr;
1397 }
1398
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001399 for (int t = 0; t < kMaxTexCoords; ++t) {
1400 if (newTexCoordOffsets[t] > 0) {
1401 GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[t];
1402 if (oldTexCoordOffsets[t] <= 0) {
1403 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1404 }
1405 if (posChange || newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
1406 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
1407 texCoordNorm, newStride, texCoordPtr));
1408 }
1409 } else if (oldTexCoordOffsets[t] > 0) {
1410 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001411 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001412 }
1413
1414 if (newColorOffset > 0) {
1415 GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
1416 if (oldColorOffset <= 0) {
1417 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
1418 }
1419 if (posChange || newColorOffset != oldColorOffset) {
1420 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1421 GL_UNSIGNED_BYTE,
1422 true, newStride, colorPtr));
1423 }
1424 } else if (oldColorOffset > 0) {
1425 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1426 }
1427
1428 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
1429}
1430#endif
1431