blob: 34e7c87e50f0524bd43d7049d1ea37e6817baf79 [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
982void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
983
984 // Must initialize all fields or cache will have false negatives!
985 desc->fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000986
bsalomon@google.comd16983b2011-02-02 22:42:20 +0000987 desc->fOptFlags = 0;
988 if (kPoints_PrimitiveType != primType) {
989 desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit;
990 }
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000991#if GR_AGGRESSIVE_SHADER_OPTS
992 if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
993 (0xffffffff == fCurrDrawState.fColor)) {
994 desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
995 }
bsalomon@google.comd16983b2011-02-02 22:42:20 +0000996#endif
997
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000998 for (int s = 0; s < kNumStages; ++s) {
999 StageDesc& stage = desc->fStages[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +00001000
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001001 stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +00001002
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001003 if (stage.fEnabled) {
1004 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1005 GrAssert(NULL != texture);
1006 // we matrix to invert when orientation is TopDown, so make sure
1007 // we aren't in that case before flagging as identity.
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
1091 resetContextHelper();
1092
1093 fProgram = NULL;
1094 fProgramCache = new ProgramCache();
1095
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001096#if 0
reed@google.comac10a2d2010-12-22 21:39:39 +00001097 ProgramUnitTest();
1098#endif
1099}
1100
1101GrGpuGLShaders2::~GrGpuGLShaders2() {
1102 delete fProgramCache;
1103}
1104
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001105const GrMatrix& GrGpuGLShaders2::getHWSamplerMatrix(int stage) {
1106#if ATTRIBUTE_MATRIX
1107 return fHWDrawState.fSamplerStates[stage].getMatrix();
1108#else
1109 return fProgram->fTextureMatrices[stage];
1110#endif
1111}
1112
1113void GrGpuGLShaders2::recordHWSamplerMatrix(int stage, const GrMatrix& matrix){
1114#if ATTRIBUTE_MATRIX
1115 fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
1116#else
1117 fProgram->fTextureMatrices[stage] = matrix;
1118#endif
1119}
1120
reed@google.comac10a2d2010-12-22 21:39:39 +00001121void GrGpuGLShaders2::resetContext() {
1122 INHERITED::resetContext();
1123 resetContextHelper();
1124}
1125
1126void GrGpuGLShaders2::resetContextHelper() {
reed@google.comac10a2d2010-12-22 21:39:39 +00001127 fHWGeometryState.fVertexLayout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001128 fHWGeometryState.fVertexOffset = ~0;
reed@google.comac10a2d2010-12-22 21:39:39 +00001129 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001130 for (int t = 0; t < kMaxTexCoords; ++t) {
1131 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1132 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001133 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1134
1135 fHWProgramID = 0;
1136}
1137
1138void GrGpuGLShaders2::flushViewMatrix() {
1139 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1140 GrMatrix m (
1141 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1142 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1143 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001144 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001145
1146 // ES doesn't allow you to pass true to the transpose param,
1147 // so do our own transpose
1148 GrScalar mt[] = {
1149 m[GrMatrix::kScaleX],
1150 m[GrMatrix::kSkewY],
1151 m[GrMatrix::kPersp0],
1152 m[GrMatrix::kSkewX],
1153 m[GrMatrix::kScaleY],
1154 m[GrMatrix::kPersp1],
1155 m[GrMatrix::kTransX],
1156 m[GrMatrix::kTransY],
1157 m[GrMatrix::kPersp2]
1158 };
1159#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001160 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1161 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1162 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001163#else
1164 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1165#endif
1166}
1167
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001168void GrGpuGLShaders2::flushTextureMatrix(int stage) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001169 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001170
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001171 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage];
1172
1173 GrMatrix m = getSamplerMatrix(stage);
1174 GrSamplerState::SampleMode mode =
1175 fCurrDrawState.fSamplerStates[0].getSampleMode();
1176 AdjustTextureMatrix(texture, mode, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001177
1178 // ES doesn't allow you to pass true to the transpose param,
1179 // so do our own transpose
1180 GrScalar mt[] = {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001181 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]
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 };
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,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001197 1, false, mt));
reed@google.comac10a2d2010-12-22 21:39:39 +00001198#endif
1199}
1200
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001201void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001202
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001203 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001204
1205 GrScalar centerX1 = sampler.getRadial2CenterX1();
1206 GrScalar radius0 = sampler.getRadial2Radius0();
1207
1208 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1209
1210 float unis[6] = {
1211 GrScalarToFloat(a),
1212 1 / (2.f * unis[0]),
1213 GrScalarToFloat(centerX1),
1214 GrScalarToFloat(radius0),
1215 GrScalarToFloat(GrMul(radius0, radius0)),
1216 sampler.isRadial2PosRoot() ? 1.f : -1.f
1217 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001218 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1219 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001220 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001221}
1222
1223void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
1224 ProgramDesc desc;
1225 getProgramDesc(type, &desc);
1226 fProgram = fProgramCache->getProgram(desc);
1227
1228 if (fHWProgramID != fProgram->fProgramID) {
1229 GR_GL(UseProgram(fProgram->fProgramID));
1230 fHWProgramID = fProgram->fProgramID;
1231#if GR_COLLECT_STATS
1232 ++fStats.fProgChngCnt;
1233#endif
1234 }
1235}
1236
1237bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
1238
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001239 if (!flushGLStateCommon(type)) {
1240 return false;
1241 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001242
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001243 if (fDirtyFlags.fRenderTargetChanged) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001244 // our coords are in pixel space and the GL matrices map to NDC
1245 // so if the viewport changed, our matrix is now wrong.
1246#if ATTRIBUTE_MATRIX
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001247 fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001248#else
1249 // we assume all shader matrices may be wrong after viewport changes
1250 fProgramCache->invalidateViewMatrices();
1251#endif
reed@google.comac10a2d2010-12-22 21:39:39 +00001252 }
1253
1254 flushProgram(type);
1255
1256 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1257 // invalidate the immediate mode color
1258 fHWDrawState.fColor = GrColor_ILLEGAL;
1259 } else {
1260 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
1261 // OpenGL ES only supports the float varities of glVertexAttrib
1262 float c[] = {
1263 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1264 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1265 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1266 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1267 };
1268 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1269 fHWDrawState.fColor = fCurrDrawState.fColor;
1270 }
1271 }
1272
1273#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001274 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001275#else
1276 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001277#endif
1278
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001279 if (currViewMatrix != fCurrDrawState.fViewMatrix) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001280 flushViewMatrix();
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001281 currViewMatrix = fCurrDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001282 }
1283
bsalomon@google.com316f99232011-01-13 21:28:12 +00001284 for (int s = 0; s < kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001285 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1286 if (NULL != texture) {
1287 if (-1 != fProgram->fUniLocations.fStages[s].fTextureMatrixUni &&
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001288 (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
1289 getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001290 flushTextureMatrix(s);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001291 recordHWSamplerMatrix(s, getSamplerMatrix(s));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001292 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001293 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001294
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001295 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1296 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1297 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1298 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1299 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001300
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001301 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001302
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001303 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1304 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1305 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1306 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001307 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001308 resetDirtyFlags();
reed@google.comac10a2d2010-12-22 21:39:39 +00001309 return true;
1310}
1311
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001312void GrGpuGLShaders2::setupGeometry(int* startVertex,
1313 int* startIndex,
1314 int vertexCount,
1315 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001316
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001317 int newColorOffset;
1318 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001319
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001320 GLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1321 newTexCoordOffsets,
1322 &newColorOffset);
1323 int oldColorOffset;
1324 int oldTexCoordOffsets[kMaxTexCoords];
1325 GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1326 oldTexCoordOffsets,
1327 &oldColorOffset);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001328 bool indexed = NULL != startIndex;
reed@google.comac10a2d2010-12-22 21:39:39 +00001329
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001330 int extraVertexOffset;
1331 int extraIndexOffset;
1332 setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001333
1334 GLenum scalarType;
1335 bool texCoordNorm;
1336 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1337 scalarType = GrGLTextType;
1338 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1339 } else {
1340 scalarType = GrGLType;
1341 texCoordNorm = false;
1342 }
1343
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001344 size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
1345 *startVertex = 0;
1346 if (indexed) {
1347 *startIndex += extraIndexOffset;
1348 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001349
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001350 // all the Pointers must be set if any of these are true
1351 bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
1352 vertexOffset != fHWGeometryState.fVertexOffset ||
1353 newStride != oldStride;
1354
1355 // position and tex coord offsets change if above conditions are true
1356 // or the type/normalization changed based on text vs nontext type coords.
1357 bool posAndTexChange = allOffsetsChange ||
1358 (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
1359 (kTextFormat_VertexLayoutBit &
1360 (fHWGeometryState.fVertexLayout ^
1361 fGeometrySrc.fVertexLayout)));
1362
1363 if (posAndTexChange) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001364 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001365 false, newStride, (GLvoid*)vertexOffset));
1366 fHWGeometryState.fVertexOffset = vertexOffset;
reed@google.comac10a2d2010-12-22 21:39:39 +00001367 }
1368
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001369 for (int t = 0; t < kMaxTexCoords; ++t) {
1370 if (newTexCoordOffsets[t] > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001371 GLvoid* texCoordOffset = (GLvoid*)(vertexOffset + newTexCoordOffsets[t]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001372 if (oldTexCoordOffsets[t] <= 0) {
1373 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001374 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001375 texCoordNorm, newStride, texCoordOffset));
1376 } else if (posAndTexChange ||
1377 newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001378 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001379 texCoordNorm, newStride, texCoordOffset));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001380 }
1381 } else if (oldTexCoordOffsets[t] > 0) {
1382 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001383 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001384 }
1385
1386 if (newColorOffset > 0) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001387 GLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001388 if (oldColorOffset <= 0) {
1389 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001390 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1391 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001392 true, newStride, colorOffset));
1393 } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001394 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1395 GL_UNSIGNED_BYTE,
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001396 true, newStride, colorOffset));
reed@google.comac10a2d2010-12-22 21:39:39 +00001397 }
1398 } else if (oldColorOffset > 0) {
1399 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1400 }
1401
1402 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001403 fHWGeometryState.fArrayPtrsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +00001404}
1405#endif
1406
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001407