blob: f79e9c883a7bbc8d782d05d569dc4f25957466c0 [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.comc6cf7232011-02-17 16:43:10 +000084 GrMatrix fTextureMatrices[kNumStages];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000085 GrScalar fRadial2CenterX1[kNumStages];
86 GrScalar fRadial2Radius0[kNumStages];
87 bool fRadial2PosRoot[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000088
89};
90
91// must be tightly packed
92struct GrGpuGLShaders2::StageDesc {
93 enum OptFlagBits {
94 kNoPerspective_OptFlagBit = 0x1,
95 kIdentityMatrix_OptFlagBit = 0x2,
96 };
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000097 unsigned fOptFlags : 8;
98
99 unsigned fEnabled : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000100
reed@google.comac10a2d2010-12-22 21:39:39 +0000101 enum Modulation {
102 kColor_Modulation,
103 kAlpha_Modulation,
104 } fModulation : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000105
reed@google.comac10a2d2010-12-22 21:39:39 +0000106 enum CoordMapping {
107 kIdentity_CoordMapping,
108 kRadialGradient_CoordMapping,
109 kSweepGradient_CoordMapping,
110 kRadial2Gradient_CoordMapping,
111 } fCoordMapping : 8;
112};
113
114// must be tightly packed
115struct GrGpuGLShaders2::ProgramDesc {
116 GrVertexLayout fVertexLayout;
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000117 GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field
118
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 enum {
120 kNotPoints_OptFlagBit = 0x1,
121 kVertexColorAllOnes_OptFlagBit = 0x2,
122 };
123 // we're assuming optflags and layout pack into 32 bits
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000124 // VS 2010 seems to require short rather than just unsigned
125 // for this to pack
126 unsigned short fOptFlags : 16;
reed@google.comac10a2d2010-12-22 21:39:39 +0000127
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000128 StageDesc fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000129
130 bool operator == (const ProgramDesc& desc) const {
131 // keep 4-byte aligned and tightly packed
132 GR_STATIC_ASSERT(4 == sizeof(StageDesc));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000133 GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
135 }
136};
137
138#include "GrTHashCache.h"
139
140class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
141private:
142 struct Entry;
143 class HashKey {
144 public:
145 HashKey();
146 HashKey(const ProgramDesc& desc);
147 static const HashKey& GetKey(const Entry&);
148 static bool EQ(const Entry&, const HashKey&);
149 static bool LT(const Entry&, const HashKey&);
150 bool operator <(const HashKey& key) const;
151 bool operator ==(const HashKey& key) const;
152 uint32_t getHash() const;
153 private:
154 ProgramDesc fDesc;
155 uint32_t fHash;
156 };
157
158 struct Entry {
159 Program fProgram;
160 HashKey fKey;
161 uint32_t fLRUStamp;
162 };
163
164 // if hash bits is changed, need to change hash function
165 GrTHashTable<Entry, HashKey, 8> fHashCache;
166
167 static const int MAX_ENTRIES = 16;
168 Entry fEntries[MAX_ENTRIES];
169 int fCount;
170 uint32_t fCurrLRUStamp;
171
172public:
173 ProgramCache() {
174 fCount = 0;
175 fCurrLRUStamp = 0;
176 }
177
178 ~ProgramCache() {
179 for (int i = 0; i < fCount; ++i) {
180 GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
181 }
182 }
183
184 void abandon() {
185 fCount = 0;
186 }
187
188 void invalidateViewMatrices() {
189 for (int i = 0; i < fCount; ++i) {
190 // set to illegal matrix
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000191 fEntries[i].fProgram.fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000192 }
193 }
194
195 Program* getProgram(const ProgramDesc& desc) {
196 HashKey key(desc);
197 Entry* entry = fHashCache.find(key);
198 if (NULL == entry) {
199 if (fCount < MAX_ENTRIES) {
200 entry = fEntries + fCount;
201 ++fCount;
202 } else {
203 GrAssert(MAX_ENTRIES == fCount);
204 entry = fEntries;
205 for (int i = 1; i < MAX_ENTRIES; ++i) {
206 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
207 entry = fEntries + i;
208 }
209 }
210 fHashCache.remove(entry->fKey, entry);
211 GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
212 }
213 entry->fKey = key;
214 GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
215 fHashCache.insert(entry->fKey, entry);
216 }
217
218 entry->fLRUStamp = fCurrLRUStamp;
reed@google.comd2938db2011-01-28 20:54:15 +0000219 if (GR_UINT32_MAX == fCurrLRUStamp) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000220 // wrap around! just trash our LRU, one time hit.
221 for (int i = 0; i < fCount; ++i) {
222 fEntries[i].fLRUStamp = 0;
223 }
224 }
225 ++fCurrLRUStamp;
226 return &entry->fProgram;
227 }
228};
229
230GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
231}
232
233static uint32_t ror(uint32_t x) {
234 return (x >> 8) | (x << 24);
235}
236
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000237static uint32_t rol(uint32_t x) {
238 return (x << 8) | (x >> 24);
239}
240
reed@google.comac10a2d2010-12-22 21:39:39 +0000241GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
242 fDesc = desc;
243 // if you change the size of the desc, need to update the hash function
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000244 GR_STATIC_ASSERT(12 == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000245
reed@google.com38690072011-01-26 01:44:18 +0000246 uint32_t* d = GrTCast<uint32_t*>(&fDesc);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000247 fHash = d[0] ^ ror(d[1]) ^ rol(d[2]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000248}
249
250bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
251 const HashKey& key) {
252 return entry.fKey == key;
253}
254
255bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
256 const HashKey& key) {
257 return entry.fKey < key;
258}
259
260bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
261 return fDesc == key.fDesc;
262}
263
264bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
265 return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
266}
267
268uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
269 return fHash;
270}
271
reed@google.comac10a2d2010-12-22 21:39:39 +0000272struct GrGpuGLShaders2::ShaderCodeSegments {
273 GrSStringBuilder<256> fVSUnis;
274 GrSStringBuilder<256> fVSAttrs;
275 GrSStringBuilder<256> fVaryings;
276 GrSStringBuilder<256> fFSUnis;
277 GrSStringBuilder<512> fVSCode;
278 GrSStringBuilder<512> fFSCode;
279};
280// for variable names etc
281typedef GrSStringBuilder<16> GrTokenString;
282
283#if ATTRIBUTE_MATRIX
284 #define VIEW_MATRIX_NAME "aViewM"
285#else
286 #define VIEW_MATRIX_NAME "uViewM"
287#endif
288
289#define POS_ATTR_NAME "aPosition"
290#define COL_ATTR_NAME "aColor"
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000291
292static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
293 *s = "aTexCoord";
294 s->appendInt(coordIdx);
295}
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
297static inline const char* float_vector_type(int count) {
298 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
reed@google.com38690072011-01-26 01:44:18 +0000299 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000300 return FLOAT_VECS[count];
301}
302
303static inline const char* vector_homog_coord(int count) {
304 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
reed@google.com38690072011-01-26 01:44:18 +0000305 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000306 return HOMOGS[count];
307}
308
309static inline const char* vector_nonhomog_coords(int count) {
310 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
reed@google.com38690072011-01-26 01:44:18 +0000311 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000312 return NONHOMOGS[count];
313}
314
315static inline const char* vector_all_coords(int count) {
316 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
reed@google.com38690072011-01-26 01:44:18 +0000317 GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
reed@google.comac10a2d2010-12-22 21:39:39 +0000318 return ALL[count];
319}
320
321static void tex_matrix_name(int stage, GrStringBuilder* s) {
322#if ATTRIBUTE_MATRIX
323 *s = "aTexM";
324#else
325 *s = "uTexM";
326#endif
327 s->appendInt(stage);
328}
329
330static void sampler_name(int stage, GrStringBuilder* s) {
331 *s = "uSampler";
332 s->appendInt(stage);
333}
334
335static void stage_varying_name(int stage, GrStringBuilder* s) {
336 *s = "vStage";
337 s->appendInt(stage);
338}
339
340static void radial2_param_name(int stage, GrStringBuilder* s) {
341 *s = "uRadial2Params";
342 s->appendInt(stage);
343}
344
345static void radial2_varying_name(int stage, GrStringBuilder* s) {
346 *s = "vB";
347 s->appendInt(stage);
348}
349
350#include "GrRandom.h"
351
352void GrGpuGLShaders2::ProgramUnitTest() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000353 static const int PROG_OPTS[] = {
354 0,
355 ProgramDesc::kNotPoints_OptFlagBit,
356 ProgramDesc::kVertexColorAllOnes_OptFlagBit,
357 ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
358 };
359 static const int STAGE_OPTS[] = {
360 0,
361 StageDesc::kNoPerspective_OptFlagBit,
362 StageDesc::kIdentity_CoordMapping
363 };
364 static const int STAGE_MODULATES[] = {
365 StageDesc::kColor_Modulation,
366 StageDesc::kAlpha_Modulation
367 };
368 static const int STAGE_COORD_MAPPINGS[] = {
369 StageDesc::kIdentity_CoordMapping,
370 StageDesc::kRadialGradient_CoordMapping,
371 StageDesc::kSweepGradient_CoordMapping,
372 StageDesc::kRadial2Gradient_CoordMapping
373 };
374 ProgramDesc pdesc;
375 memset(&pdesc, 0, sizeof(pdesc));
376
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000377 static const int NUM_TESTS = 512;
reed@google.comac10a2d2010-12-22 21:39:39 +0000378
379 // GrRandoms nextU() values have patterns in the low bits
380 // So using nextU() % array_count might never take some values.
381 GrRandom random;
382 for (int t = 0; t < NUM_TESTS; ++t) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000383
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000384 pdesc.fVertexLayout = 0;
385 for (int s = 0; s < kNumStages; ++s) {
386 // enable the stage?
387 if (random.nextF() > .5f) {
388 // use separate tex coords?
389 if (random.nextF() > .5f) {
390 int t = (int)(random.nextF() * kMaxTexCoords);
391 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
392 } else {
393 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
394 }
395 }
396 // use text-formatted verts?
397 if (random.nextF() > .5f) {
398 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
399 }
400 }
401
402 int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000403 pdesc.fOptFlags = PROG_OPTS[x];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000404 for (int s = 0; s < kNumStages; ++s) {
405 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000406 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
407 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
408 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000409 pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000410 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000411 pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 }
413 Program program;
414 GenProgram(pdesc, &program);
415 DeleteProgram(&program);
416 }
417}
418
419void GrGpuGLShaders2::GenStageCode(int stageNum,
420 const StageDesc& desc,
421 const char* fsInColor, // NULL means no incoming color
422 const char* fsOutColor,
423 const char* vsInCoord,
424 ShaderCodeSegments* segments,
425 StageUniLocations* locations) {
426
427 GrAssert(stageNum >= 0 && stageNum <= 9);
428
429 GrTokenString varyingName;
430 stage_varying_name(stageNum, &varyingName);
431
432 // First decide how many coords are needed to access the texture
433 // Right now it's always 2 but we could start using 1D textures for
434 // gradients.
435 static const int coordDims = 2;
436 int varyingDims;
437 /// Vertex Shader Stuff
438
439 // decide whether we need a matrix to transform texture coords
440 // and whether the varying needs a perspective coord.
441 GrTokenString texMName;
442 tex_matrix_name(stageNum, &texMName);
443 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
444 varyingDims = coordDims;
445 } else {
446 #if ATTRIBUTE_MATRIX
447 segments->fVSAttrs += "attribute mat3 ";
448 segments->fVSAttrs += texMName;
449 segments->fVSAttrs += ";\n";
450 #else
451 segments->fVSUnis += "uniform mat3 ";
452 segments->fVSUnis += texMName;
453 segments->fVSUnis += ";\n";
454 locations->fTextureMatrixUni = 1;
455 #endif
456 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
457 varyingDims = coordDims;
458 } else {
459 varyingDims = coordDims + 1;
460 }
461 }
462
463 GrTokenString samplerName;
464 sampler_name(stageNum, &samplerName);
465 segments->fFSUnis += "uniform sampler2D ";
466 segments->fFSUnis += samplerName;
467 segments->fFSUnis += ";\n";
468 locations->fSamplerUni = 1;
469
470 segments->fVaryings += "varying ";
471 segments->fVaryings += float_vector_type(varyingDims);
472 segments->fVaryings += " ";
473 segments->fVaryings += varyingName;
474 segments->fVaryings += ";\n";
475
476 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
477 GrAssert(varyingDims == coordDims);
478 segments->fVSCode += "\t";
479 segments->fVSCode += varyingName;
480 segments->fVSCode += " = ";
481 segments->fVSCode += vsInCoord;
482 segments->fVSCode += ";\n";
483 } else {
484 segments->fVSCode += "\t";
485 segments->fVSCode += varyingName;
486 segments->fVSCode += " = (";
487 segments->fVSCode += texMName;
488 segments->fVSCode += " * vec3(";
489 segments->fVSCode += vsInCoord;
490 segments->fVSCode += ", 1))";
491 segments->fVSCode += vector_all_coords(varyingDims);
492 segments->fVSCode += ";\n";
493 }
494
495 GrTokenString radial2ParamsName;
496 radial2_param_name(stageNum, &radial2ParamsName);
497 // for radial grads without perspective we can pass the linear
498 // part of the quadratic as a varying.
499 GrTokenString radial2VaryingName;
500 radial2_varying_name(stageNum, &radial2VaryingName);
501
502 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
503
504 segments->fVSUnis += "uniform " GR_PRECISION " float ";
505 segments->fVSUnis += radial2ParamsName;
506 segments->fVSUnis += "[6];\n";
507
508 segments->fFSUnis += "uniform " GR_PRECISION " float ";
509 segments->fFSUnis += radial2ParamsName;
510 segments->fFSUnis += "[6];\n";
511 locations->fRadial2Uni = 1;
512
513 // if there is perspective we don't interpolate this
514 if (varyingDims == coordDims) {
515 GrAssert(2 == coordDims);
516 segments->fVaryings += "varying float ";
517 segments->fVaryings += radial2VaryingName;
518 segments->fVaryings += ";\n";
519
520 segments->fVSCode += "\t";
521 segments->fVSCode += radial2VaryingName;
522 segments->fVSCode += " = 2.0 * (";
523 segments->fVSCode += radial2ParamsName;
524 segments->fVSCode += "[2] * ";
525 segments->fVSCode += varyingName;
526 segments->fVSCode += ".x ";
527 segments->fVSCode += " - ";
528 segments->fVSCode += radial2ParamsName;
529 segments->fVSCode += "[3]);\n";
530 }
531 }
532
533 /// Fragment Shader Stuff
534 GrTokenString fsCoordName;
535 // function used to access the shader, may be made projective
536 GrTokenString texFunc("texture2D");
537 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
538 StageDesc::kNoPerspective_OptFlagBit)) {
539 GrAssert(varyingDims == coordDims);
540 fsCoordName = varyingName;
541 } else {
542 // if we have to do some non-matrix op on the varyings to get
543 // our final tex coords then when in perspective we have to
544 // do an explicit divide
545 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
546 texFunc += "Proj";
547 fsCoordName = varyingName;
548 } else {
549 fsCoordName = "tCoord";
550 fsCoordName.appendInt(stageNum);
551
552 segments->fFSCode += "\t";
553 segments->fFSCode += float_vector_type(coordDims);
554 segments->fFSCode += " ";
555 segments->fFSCode += fsCoordName;
556 segments->fFSCode += " = ";
557 segments->fFSCode += varyingName;
558 segments->fFSCode += vector_nonhomog_coords(varyingDims);
559 segments->fFSCode += " / ";
560 segments->fFSCode += varyingName;
561 segments->fFSCode += vector_homog_coord(varyingDims);
562 segments->fFSCode += ";\n";
563 }
564 }
565
566 GrSStringBuilder<96> sampleCoords;
567 switch (desc.fCoordMapping) {
568 case StageDesc::kIdentity_CoordMapping:
569 sampleCoords = fsCoordName;
570 break;
571 case StageDesc::kSweepGradient_CoordMapping:
572 sampleCoords = "vec2(atan(-";
573 sampleCoords += fsCoordName;
574 sampleCoords += ".y, -";
575 sampleCoords += fsCoordName;
576 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
577 break;
578 case StageDesc::kRadialGradient_CoordMapping:
579 sampleCoords = "vec2(length(";
580 sampleCoords += fsCoordName;
581 sampleCoords += ".xy), 0.5)";
582 break;
583 case StageDesc::kRadial2Gradient_CoordMapping: {
584 GrTokenString cName = "c";
585 GrTokenString ac4Name = "ac4";
586 GrTokenString rootName = "root";
587
588 cName.appendInt(stageNum);
589 ac4Name.appendInt(stageNum);
590 rootName.appendInt(stageNum);
591
592 GrTokenString bVar;
593 if (coordDims == varyingDims) {
594 bVar = radial2VaryingName;
595 GrAssert(2 == varyingDims);
596 } else {
597 GrAssert(3 == varyingDims);
598 bVar = "b";
599 bVar.appendInt(stageNum);
600 segments->fFSCode += "\tfloat ";
601 segments->fFSCode += bVar;
602 segments->fFSCode += " = 2.0 * (";
603 segments->fFSCode += radial2ParamsName;
604 segments->fFSCode += "[2] * ";
605 segments->fFSCode += fsCoordName;
606 segments->fFSCode += ".x ";
607 segments->fFSCode += " - ";
608 segments->fFSCode += radial2ParamsName;
609 segments->fFSCode += "[3]);\n";
610 }
611
612 segments->fFSCode += "\tfloat ";
613 segments->fFSCode += cName;
614 segments->fFSCode += " = dot(";
615 segments->fFSCode += fsCoordName;
616 segments->fFSCode += ", ";
617 segments->fFSCode += fsCoordName;
618 segments->fFSCode += ") + ";
619 segments->fFSCode += " - ";
620 segments->fFSCode += radial2ParamsName;
621 segments->fFSCode += "[4];\n";
622
623 segments->fFSCode += "\tfloat ";
624 segments->fFSCode += ac4Name;
625 segments->fFSCode += " = ";
626 segments->fFSCode += radial2ParamsName;
627 segments->fFSCode += "[0] * 4.0 * ";
628 segments->fFSCode += cName;
629 segments->fFSCode += ";\n";
630
631 segments->fFSCode += "\tfloat ";
632 segments->fFSCode += rootName;
633 segments->fFSCode += " = sqrt(abs(";
634 segments->fFSCode += bVar;
635 segments->fFSCode += " * ";
636 segments->fFSCode += bVar;
637 segments->fFSCode += " - ";
638 segments->fFSCode += ac4Name;
639 segments->fFSCode += "));\n";
640
641 sampleCoords = "vec2((-";
642 sampleCoords += bVar;
643 sampleCoords += " + ";
644 sampleCoords += radial2ParamsName;
645 sampleCoords += "[5] * ";
646 sampleCoords += rootName;
647 sampleCoords += ") * ";
648 sampleCoords += radial2ParamsName;
649 sampleCoords += "[1], 0.5)\n";
650 break;}
651 };
652
653 segments->fFSCode += "\t";
654 segments->fFSCode += fsOutColor;
655 segments->fFSCode += " = ";
656 if (NULL != fsInColor) {
657 segments->fFSCode += fsInColor;
658 segments->fFSCode += " * ";
659 }
660 segments->fFSCode += texFunc;
661 segments->fFSCode += "(";
662 segments->fFSCode += samplerName;
663 segments->fFSCode += ", ";
664 segments->fFSCode += sampleCoords;
665 segments->fFSCode += ")";
666 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
667 segments->fFSCode += ".aaaa";
668 }
669 segments->fFSCode += ";\n";
670
671}
672
673void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
674 Program* program) {
675
676 ShaderCodeSegments segments;
677 const uint32_t& layout = desc.fVertexLayout;
678
679 memset(&program->fUniLocations, 0, sizeof(UniLocations));
680
681 bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
682 desc.fOptFlags);
683
684#if ATTRIBUTE_MATRIX
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000685 segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n";
reed@google.comac10a2d2010-12-22 21:39:39 +0000686#else
687 segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
688 segments.fVSAttrs = "";
689#endif
690 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
691 if (haveColor) {
692 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
693 segments.fVaryings = "varying vec4 vColor;\n";
694 } else {
695 segments.fVaryings = "";
696 }
697
698 segments.fVSCode = "void main() {\n"
699 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
700 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
701 if (haveColor) {
702 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
703 }
704
705 if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
706 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
707 }
708 segments.fFSCode = "void main() {\n";
709
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000710 // add texture coordinates that are used to the list of vertex attr decls
711 GrTokenString texCoordAttrs[kMaxTexCoords];
712 for (int t = 0; t < kMaxTexCoords; ++t) {
713 if (VertexUsesTexCoordIdx(t, layout)) {
714 tex_attr_name(t, texCoordAttrs + t);
715
716 segments.fVSAttrs += "attribute vec2 ";
717 segments.fVSAttrs += texCoordAttrs[t];
718 segments.fVSAttrs += ";\n";
719 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000720 }
721
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000722 // for each enabled stage figure out what the input coordinates are
723 // and count the number of stages in use.
724 const char* stageInCoords[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000725 int numActiveStages = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000726
727 for (int s = 0; s < kNumStages; ++s) {
728 if (desc.fStages[s].fEnabled) {
729 if (StagePosAsTexCoordVertexLayoutBit(s) & layout) {
730 stageInCoords[s] = POS_ATTR_NAME;
731 } else {
732 int tcIdx = VertexTexCoordsForStage(s, layout);
733 // we better have input tex coordinates if stage is enabled.
734 GrAssert(tcIdx >= 0);
735 GrAssert(texCoordAttrs[tcIdx].length());
736 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
737 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000738 ++numActiveStages;
739 }
740 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000741
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000742 GrTokenString inColor = "vColor";
743
744 // if we have active stages string them together, feeding the output color
745 // of each to the next and generating code for each stage.
746 if (numActiveStages) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000747 int currActiveStage = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000748 for (int s = 0; s < kNumStages; ++s) {
749 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 GrTokenString outColor;
751 if (currActiveStage < (numActiveStages - 1)) {
752 outColor = "color";
753 outColor.appendInt(currActiveStage);
754 segments.fFSCode += "\tvec4 ";
755 segments.fFSCode += outColor;
756 segments.fFSCode += ";\n";
757 } else {
758 outColor = "gl_FragColor";
759 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000760 GenStageCode(s,
761 desc.fStages[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000762 haveColor ? inColor.cstr() : NULL,
763 outColor.cstr(),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000764 stageInCoords[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000765 &segments,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000766 &program->fUniLocations.fStages[s]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000767 ++currActiveStage;
768 inColor = outColor;
769 haveColor = true;
770 }
771 }
772 } else {
773 segments.fFSCode += "\tgl_FragColor = ";
774 if (haveColor) {
775 segments.fFSCode += inColor;
776 } else {
777 segments.fFSCode += "vec4(1,1,1,1)";
778 }
779 segments.fFSCode += ";\n";
780 }
781 segments.fFSCode += "}\n";
782 segments.fVSCode += "}\n";
783
784
785 const char* strings[4];
786 int lengths[4];
787 int stringCnt = 0;
788
789 if (segments.fVSUnis.length()) {
790 strings[stringCnt] = segments.fVSUnis.cstr();
791 lengths[stringCnt] = segments.fVSUnis.length();
792 ++stringCnt;
793 }
794 if (segments.fVSAttrs.length()) {
795 strings[stringCnt] = segments.fVSAttrs.cstr();
796 lengths[stringCnt] = segments.fVSAttrs.length();
797 ++stringCnt;
798 }
799 if (segments.fVaryings.length()) {
800 strings[stringCnt] = segments.fVaryings.cstr();
801 lengths[stringCnt] = segments.fVaryings.length();
802 ++stringCnt;
803 }
804
805 GrAssert(segments.fVSCode.length());
806 strings[stringCnt] = segments.fVSCode.cstr();
807 lengths[stringCnt] = segments.fVSCode.length();
808 ++stringCnt;
809
810#if PRINT_SHADERS
811 GrPrintf("%s%s%s%s\n",
812 segments.fVSUnis.cstr(),
813 segments.fVSAttrs.cstr(),
814 segments.fVaryings.cstr(),
815 segments.fVSCode.cstr());
816#endif
817 program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
818 stringCnt,
819 strings,
820 lengths);
821
822 stringCnt = 0;
823
824 if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
825 strings[stringCnt] = GR_SHADER_PRECISION;
826 lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
827 ++stringCnt;
828 }
829 if (segments.fFSUnis.length()) {
830 strings[stringCnt] = segments.fFSUnis.cstr();
831 lengths[stringCnt] = segments.fFSUnis.length();
832 ++stringCnt;
833 }
834 if (segments.fVaryings.length()) {
835 strings[stringCnt] = segments.fVaryings.cstr();
836 lengths[stringCnt] = segments.fVaryings.length();
837 ++stringCnt;
838 }
839
840 GrAssert(segments.fFSCode.length());
841 strings[stringCnt] = segments.fFSCode.cstr();
842 lengths[stringCnt] = segments.fFSCode.length();
843 ++stringCnt;
844
845#if PRINT_SHADERS
846 GrPrintf("%s%s%s%s\n",
847 GR_SHADER_PRECISION,
848 segments.fFSUnis.cstr(),
849 segments.fVaryings.cstr(),
850 segments.fFSCode.cstr());
851#endif
852 program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
853 stringCnt,
854 strings,
855 lengths);
856
857 program->fProgramID = GR_GL(CreateProgram());
858 const GLint& progID = program->fProgramID;
859
860 GR_GL(AttachShader(progID, program->fVShaderID));
861 GR_GL(AttachShader(progID, program->fFShaderID));
862
863 // Bind the attrib locations to same values for all shaders
864 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000865 for (int t = 0; t < kMaxTexCoords; ++t) {
866 if (texCoordAttrs[t].length()) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000867 GR_GL(BindAttribLocation(progID,
868 TEX_ATTR_LOCATION(t),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000869 texCoordAttrs[t].cstr()));
870 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 }
872
873#if ATTRIBUTE_MATRIX
874 // set unis to a bogus value so that checks against -1 before
875 // flushing will pass.
876 GR_GL(BindAttribLocation(progID,
877 VIEWMAT_ATTR_LOCATION,
878 VIEW_MATRIX_NAME));
879
880 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
881
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000882 for (int s = 0; s < kNumStages; ++s) {
883 if (desc.fStages[s].fEnabled) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000884 GrStringBuilder matName;
885 tex_matrix_name(s, &matName);
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),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000888 matName.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.comc6cf7232011-02-17 16:43:10 +0000975 program->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000976 program->fRadial2CenterX1[s] = GR_ScalarMax;
977 program->fRadial2Radius0[s] = -GR_ScalarMax;
reed@google.comac10a2d2010-12-22 21:39:39 +0000978 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000979 program->fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000980}
981
bsalomon@google.comffca4002011-02-22 20:34:01 +0000982void GrGpuGLShaders2::getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000983
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.
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001008 if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001009 stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001010 } else if (!getSamplerMatrix(s).hasPerspective()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001011 stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
1012 } else {
1013 stage.fOptFlags = 0;
1014 }
1015 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
1016 case GrSamplerState::kNormal_SampleMode:
1017 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1018 break;
1019 case GrSamplerState::kRadial_SampleMode:
1020 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1021 break;
1022 case GrSamplerState::kRadial2_SampleMode:
1023 stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
1024 break;
1025 case GrSamplerState::kSweep_SampleMode:
1026 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1027 break;
1028 default:
1029 GrAssert(!"Unexpected sample mode!");
1030 break;
1031 }
1032 if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
1033 stage.fModulation = StageDesc::kAlpha_Modulation;
1034 } else {
1035 stage.fModulation = StageDesc::kColor_Modulation;
1036 }
1037 } else {
1038 stage.fOptFlags = 0;
1039 stage.fCoordMapping = (StageDesc::CoordMapping)0;
1040 stage.fModulation = (StageDesc::Modulation)0;
1041 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001042 }
1043}
1044
1045GLuint GrGpuGLShaders2::CompileShader(GLenum type,
1046 int stringCnt,
1047 const char** strings,
1048 int* stringLengths) {
1049 GLuint shader = GR_GL(CreateShader(type));
1050 if (0 == shader) {
1051 return 0;
1052 }
1053
reed@google.com5f6ee1a2011-01-31 14:24:48 +00001054 GLint compiled = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
1056 GR_GL(CompileShader(shader));
1057 GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
1058
1059 if (!compiled) {
reed@google.com5f6ee1a2011-01-31 14:24:48 +00001060 GLint infoLen = GR_GL_INIT_ZERO;
reed@google.comac10a2d2010-12-22 21:39:39 +00001061 GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
1062 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1063 if (infoLen > 0) {
1064 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
1065 for (int i = 0; i < stringCnt; ++i) {
1066 if (NULL == stringLengths || stringLengths[i] < 0) {
1067 GrPrintf(strings[i]);
1068 } else {
1069 GrPrintf("%.*s", stringLengths[i], strings[i]);
1070 }
1071 }
1072 GrPrintf("\n%s", log.get());
1073 }
1074 GrAssert(!"Shader compilation failed!");
1075 GR_GL(DeleteShader(shader));
1076 return 0;
1077 }
1078 return shader;
1079}
1080
1081void GrGpuGLShaders2::DeleteProgram(Program* program) {
1082 GR_GL(DeleteShader(program->fVShaderID));
1083 GR_GL(DeleteShader(program->fFShaderID));
1084 GR_GL(DeleteProgram(program->fProgramID));
1085 GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
1086}
1087
1088
1089GrGpuGLShaders2::GrGpuGLShaders2() {
1090
reed@google.comac10a2d2010-12-22 21:39:39 +00001091 fProgram = NULL;
1092 fProgramCache = new ProgramCache();
1093
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001094#if 0
reed@google.comac10a2d2010-12-22 21:39:39 +00001095 ProgramUnitTest();
1096#endif
1097}
1098
1099GrGpuGLShaders2::~GrGpuGLShaders2() {
1100 delete fProgramCache;
1101}
1102
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001103const GrMatrix& GrGpuGLShaders2::getHWSamplerMatrix(int stage) {
1104#if ATTRIBUTE_MATRIX
1105 return fHWDrawState.fSamplerStates[stage].getMatrix();
1106#else
1107 return fProgram->fTextureMatrices[stage];
1108#endif
1109}
1110
1111void GrGpuGLShaders2::recordHWSamplerMatrix(int stage, const GrMatrix& matrix){
1112#if ATTRIBUTE_MATRIX
1113 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
1114#else
1115 fProgram->fTextureMatrices[stage] = matrix;
1116#endif
1117}
1118
reed@google.comac10a2d2010-12-22 21:39:39 +00001119void GrGpuGLShaders2::resetContext() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001120
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001121 INHERITED::resetContext();
1122
reed@google.comac10a2d2010-12-22 21:39:39 +00001123 fHWGeometryState.fVertexLayout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001124 fHWGeometryState.fVertexOffset = ~0;
reed@google.comac10a2d2010-12-22 21:39:39 +00001125 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001126 for (int t = 0; t < kMaxTexCoords; ++t) {
1127 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1128 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001129 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1130
1131 fHWProgramID = 0;
1132}
1133
1134void GrGpuGLShaders2::flushViewMatrix() {
1135 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1136 GrMatrix m (
1137 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1138 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1139 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001140 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001141
1142 // ES doesn't allow you to pass true to the transpose param,
1143 // so do our own transpose
1144 GrScalar mt[] = {
1145 m[GrMatrix::kScaleX],
1146 m[GrMatrix::kSkewY],
1147 m[GrMatrix::kPersp0],
1148 m[GrMatrix::kSkewX],
1149 m[GrMatrix::kScaleY],
1150 m[GrMatrix::kPersp1],
1151 m[GrMatrix::kTransX],
1152 m[GrMatrix::kTransY],
1153 m[GrMatrix::kPersp2]
1154 };
1155#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001156 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1157 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1158 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001159#else
1160 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1161#endif
1162}
1163
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001164void GrGpuGLShaders2::flushTextureMatrix(int stage) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001165 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001166
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001167 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage];
1168
1169 GrMatrix m = getSamplerMatrix(stage);
1170 GrSamplerState::SampleMode mode =
1171 fCurrDrawState.fSamplerStates[0].getSampleMode();
1172 AdjustTextureMatrix(texture, mode, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001173
1174 // ES doesn't allow you to pass true to the transpose param,
1175 // so do our own transpose
1176 GrScalar mt[] = {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001177 m[GrMatrix::kScaleX],
1178 m[GrMatrix::kSkewY],
1179 m[GrMatrix::kPersp0],
1180 m[GrMatrix::kSkewX],
1181 m[GrMatrix::kScaleY],
1182 m[GrMatrix::kPersp1],
1183 m[GrMatrix::kTransX],
1184 m[GrMatrix::kTransY],
1185 m[GrMatrix::kPersp2]
reed@google.comac10a2d2010-12-22 21:39:39 +00001186 };
1187#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001188 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
1189 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
1190 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001191#else
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001192 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001193 1, false, mt));
reed@google.comac10a2d2010-12-22 21:39:39 +00001194#endif
1195}
1196
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001197void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001198
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001199 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001200
1201 GrScalar centerX1 = sampler.getRadial2CenterX1();
1202 GrScalar radius0 = sampler.getRadial2Radius0();
1203
1204 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1205
1206 float unis[6] = {
1207 GrScalarToFloat(a),
1208 1 / (2.f * unis[0]),
1209 GrScalarToFloat(centerX1),
1210 GrScalarToFloat(radius0),
1211 GrScalarToFloat(GrMul(radius0, radius0)),
1212 sampler.isRadial2PosRoot() ? 1.f : -1.f
1213 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001214 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1215 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001216 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001217}
1218
bsalomon@google.comffca4002011-02-22 20:34:01 +00001219void GrGpuGLShaders2::flushProgram(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001220 ProgramDesc desc;
1221 getProgramDesc(type, &desc);
1222 fProgram = fProgramCache->getProgram(desc);
1223
1224 if (fHWProgramID != fProgram->fProgramID) {
1225 GR_GL(UseProgram(fProgram->fProgramID));
1226 fHWProgramID = fProgram->fProgramID;
1227#if GR_COLLECT_STATS
1228 ++fStats.fProgChngCnt;
1229#endif
1230 }
1231}
1232
bsalomon@google.comffca4002011-02-22 20:34:01 +00001233bool GrGpuGLShaders2::flushGraphicsState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001234
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001235 if (!flushGLStateCommon(type)) {
1236 return false;
1237 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001238
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001239 if (fDirtyFlags.fRenderTargetChanged) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001240 // our coords are in pixel space and the GL matrices map to NDC
1241 // so if the viewport changed, our matrix is now wrong.
1242#if ATTRIBUTE_MATRIX
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001243 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001244#else
1245 // we assume all shader matrices may be wrong after viewport changes
1246 fProgramCache->invalidateViewMatrices();
1247#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001248 }
1249
1250 flushProgram(type);
1251
1252 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1253 // invalidate the immediate mode color
1254 fHWDrawState.fColor = GrColor_ILLEGAL;
1255 } else {
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +00001256 if (fHWDrawState.fColor != fCurrDrawState.fColor &&
1257 (!GR_AGGRESSIVE_SHADER_OPTS || 0xffffffff != fCurrDrawState.fColor)) {
1258 // avoid pushing the color attrib if the shader will optimize it out
1259
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 // OpenGL ES only supports the float varities of glVertexAttrib
1261 float c[] = {
1262 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1263 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1264 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1265 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1266 };
1267 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1268 fHWDrawState.fColor = fCurrDrawState.fColor;
1269 }
1270 }
1271
1272#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001273 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001274#else
1275 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001276#endif
1277
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001278 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001279 flushViewMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001280 currViewMatrix = fCurrDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001281 }
1282
bsalomon@google.com316f99232011-01-13 21:28:12 +00001283 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001284 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1285 if (NULL != texture) {
1286 if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni &&
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001287 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
1288 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001289 flushTextureMatrix(s);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001290 recordHWSamplerMatrix(s, getSamplerMatrix(s));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001291 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001292 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001293
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001294 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1295 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1296 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1297 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1298 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001299
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001300 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001301
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001302 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1303 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1304 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1305 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001306 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001307 resetDirtyFlags();
reed@google.comac10a2d2010-12-22 21:39:39 +00001308 return true;
1309}
1310
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001311void GrGpuGLShaders2::setupGeometry(int* startVertex,
1312 int* startIndex,
1313 int vertexCount,
1314 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001315
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001316 int newColorOffset;
1317 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001318
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001319 GLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1320 newTexCoordOffsets,
1321 &newColorOffset);
1322 int oldColorOffset;
1323 int oldTexCoordOffsets[kMaxTexCoords];
1324 GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1325 oldTexCoordOffsets,
1326 &oldColorOffset);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001327 bool indexed = NULL != startIndex;
reed@google.comac10a2d2010-12-22 21:39:39 +00001328
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001329 int extraVertexOffset;
1330 int extraIndexOffset;
1331 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001332
1333 GLenum scalarType;
1334 bool texCoordNorm;
1335 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1336 scalarType = GrGLTextType;
1337 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1338 } else {
1339 scalarType = GrGLType;
1340 texCoordNorm = false;
1341 }
1342
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001343 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
1344 *startVertex = 0;
1345 if (indexed) {
1346 *startIndex += extraIndexOffset;
1347 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001348
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001349 // all the Pointers must be set if any of these are true
1350 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
1351 vertexOffset != fHWGeometryState.fVertexOffset ||
1352 newStride != oldStride;
1353
1354 // position and tex coord offsets change if above conditions are true
1355 // or the type/normalization changed based on text vs nontext type coords.
1356 bool posAndTexChange = allOffsetsChange ||
1357 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
1358 (kTextFormat_VertexLayoutBit &
1359 (fHWGeometryState.fVertexLayout ^
1360 fGeometrySrc.fVertexLayout)));
1361
1362 if (posAndTexChange) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001363 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001364 false, newStride, (GLvoid*)vertexOffset));
1365 fHWGeometryState.fVertexOffset = vertexOffset;
reed@google.comac10a2d2010-12-22 21:39:39 +00001366 }
1367
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001368 for (int t = 0; t < kMaxTexCoords; ++t) {
1369 if (newTexCoordOffsets[t] > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001370 GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001371 if (oldTexCoordOffsets[t] <= 0) {
1372 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001373 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001374 texCoordNorm, newStride, texCoordOffset));
1375 } else if (posAndTexChange ||
1376 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001377 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001378 texCoordNorm, newStride, texCoordOffset));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001379 }
1380 } else if (oldTexCoordOffsets[t] > 0) {
1381 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001382 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001383 }
1384
1385 if (newColorOffset > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001386 GLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001387 if (oldColorOffset <= 0) {
1388 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001389 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1390 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001391 true, newStride, colorOffset));
1392 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001393 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1394 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001395 true, newStride, colorOffset));
reed@google.comac10a2d2010-12-22 21:39:39 +00001396 }
1397 } else if (oldColorOffset > 0) {
1398 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1399 }
1400
1401 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001402 fHWGeometryState.fArrayPtrsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001403}
1404#endif
1405
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001406