blob: e47fe5dc5df2692efd971c8f6f7e8651a4e05941 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrGLConfig.h"
19
20#if GR_SUPPORT_GLES2 || GR_SUPPORT_GLDESKTOP
21
22#include "GrGpuGLShaders2.h"
23#include "GrGpuVertex.h"
24#include "GrMemory.h"
25#include "GrStringBuilder.h"
26
27
28#define ATTRIBUTE_MATRIX 0
29
30#define SKIP_COLOR_MODULATE_OPT 0
31
32#define PRINT_SHADERS 0
33
34#define SKIP_CACHE_CHECK true
35
36#if GR_SUPPORT_GLES2
37 #define GR_PRECISION "mediump"
38 const char GR_SHADER_PRECISION[] = "precision mediump float;\n";
39#else
40 #define GR_PRECISION ""
41 const char GR_SHADER_PRECISION[] = "";
42#endif
43
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000044
reed@google.comac10a2d2010-12-22 21:39:39 +000045#define POS_ATTR_LOCATION 0
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000046#define TEX_ATTR_LOCATION(X) (1 + X)
47#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords)
reed@google.comac10a2d2010-12-22 21:39:39 +000048#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000049#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
50#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
reed@google.comac10a2d2010-12-22 21:39:39 +000051#define BOGUS_MATRIX_UNI_LOCATION 1000
52#endif
53
reed@google.comac10a2d2010-12-22 21:39:39 +000054struct GrGpuGLShaders2::StageUniLocations {
55 GLint fTextureMatrixUni;
56 GLint fSamplerUni;
57 GLint fRadial2Uni;
58};
59
60struct GrGpuGLShaders2::UniLocations {
61 GLint fViewMatrixUni;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000062 StageUniLocations fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000063};
64
65// Records per-program information
66// we can specify the attribute locations so that they are constant
67// across our shaders. But the driver determines the uniform locations
68// at link time. We don't need to remember the sampler uniform location
69// because we will bind a texture slot to it and never change it
70// Uniforms are program-local so we can't rely on fHWState to hold the
71// previous uniform state after a program change.
72struct GrGpuGLShaders2::Program {
73 // IDs
74 GLuint fVShaderID;
75 GLuint fFShaderID;
76 GLuint fProgramID;
77
78 // shader uniform locations (-1 if shader doesn't use them)
79 UniLocations fUniLocations;
80
81 // these reflect the current values of uniforms
82 // (GL uniform values travel with program)
83 GrMatrix fViewMatrix;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000084 GrMatrix fTextureMatrix[kNumStages];
85 GrGLTexture::Orientation fTextureOrientation[kNumStages];
86 GrScalar fRadial2CenterX1[kNumStages];
87 GrScalar fRadial2Radius0[kNumStages];
88 bool fRadial2PosRoot[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +000089
90};
91
92// must be tightly packed
93struct GrGpuGLShaders2::StageDesc {
94 enum OptFlagBits {
95 kNoPerspective_OptFlagBit = 0x1,
96 kIdentityMatrix_OptFlagBit = 0x2,
97 };
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +000098 unsigned fOptFlags : 8;
99
100 unsigned fEnabled : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000101
reed@google.comac10a2d2010-12-22 21:39:39 +0000102 enum Modulation {
103 kColor_Modulation,
104 kAlpha_Modulation,
105 } fModulation : 8;
bsalomon@google.com316f99232011-01-13 21:28:12 +0000106
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 enum CoordMapping {
108 kIdentity_CoordMapping,
109 kRadialGradient_CoordMapping,
110 kSweepGradient_CoordMapping,
111 kRadial2Gradient_CoordMapping,
112 } fCoordMapping : 8;
113};
114
115// must be tightly packed
116struct GrGpuGLShaders2::ProgramDesc {
117 GrVertexLayout fVertexLayout;
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000118 GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout)); // pack with next field
119
reed@google.comac10a2d2010-12-22 21:39:39 +0000120 enum {
121 kNotPoints_OptFlagBit = 0x1,
122 kVertexColorAllOnes_OptFlagBit = 0x2,
123 };
124 // we're assuming optflags and layout pack into 32 bits
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000125 // VS 2010 seems to require short rather than just unsigned
126 // for this to pack
127 unsigned short fOptFlags : 16;
reed@google.comac10a2d2010-12-22 21:39:39 +0000128
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000129 StageDesc fStages[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000130
131 bool operator == (const ProgramDesc& desc) const {
132 // keep 4-byte aligned and tightly packed
133 GR_STATIC_ASSERT(4 == sizeof(StageDesc));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000134 GR_STATIC_ASSERT(2 + 2 + 4 * kNumStages == sizeof(ProgramDesc));
reed@google.comac10a2d2010-12-22 21:39:39 +0000135 return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
136 }
137};
138
139#include "GrTHashCache.h"
140
141class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
142private:
143 struct Entry;
144 class HashKey {
145 public:
146 HashKey();
147 HashKey(const ProgramDesc& desc);
148 static const HashKey& GetKey(const Entry&);
149 static bool EQ(const Entry&, const HashKey&);
150 static bool LT(const Entry&, const HashKey&);
151 bool operator <(const HashKey& key) const;
152 bool operator ==(const HashKey& key) const;
153 uint32_t getHash() const;
154 private:
155 ProgramDesc fDesc;
156 uint32_t fHash;
157 };
158
159 struct Entry {
160 Program fProgram;
161 HashKey fKey;
162 uint32_t fLRUStamp;
163 };
164
165 // if hash bits is changed, need to change hash function
166 GrTHashTable<Entry, HashKey, 8> fHashCache;
167
168 static const int MAX_ENTRIES = 16;
169 Entry fEntries[MAX_ENTRIES];
170 int fCount;
171 uint32_t fCurrLRUStamp;
172
173public:
174 ProgramCache() {
175 fCount = 0;
176 fCurrLRUStamp = 0;
177 }
178
179 ~ProgramCache() {
180 for (int i = 0; i < fCount; ++i) {
181 GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
182 }
183 }
184
185 void abandon() {
186 fCount = 0;
187 }
188
189 void invalidateViewMatrices() {
190 for (int i = 0; i < fCount; ++i) {
191 // set to illegal matrix
192 fEntries[i].fProgram.fViewMatrix.setScale(GR_ScalarMax,
193 GR_ScalarMax);
194 }
195 }
196
197 Program* getProgram(const ProgramDesc& desc) {
198 HashKey key(desc);
199 Entry* entry = fHashCache.find(key);
200 if (NULL == entry) {
201 if (fCount < MAX_ENTRIES) {
202 entry = fEntries + fCount;
203 ++fCount;
204 } else {
205 GrAssert(MAX_ENTRIES == fCount);
206 entry = fEntries;
207 for (int i = 1; i < MAX_ENTRIES; ++i) {
208 if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
209 entry = fEntries + i;
210 }
211 }
212 fHashCache.remove(entry->fKey, entry);
213 GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
214 }
215 entry->fKey = key;
216 GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
217 fHashCache.insert(entry->fKey, entry);
218 }
219
220 entry->fLRUStamp = fCurrLRUStamp;
221 if (UINT32_MAX == fCurrLRUStamp) {
222 // wrap around! just trash our LRU, one time hit.
223 for (int i = 0; i < fCount; ++i) {
224 fEntries[i].fLRUStamp = 0;
225 }
226 }
227 ++fCurrLRUStamp;
228 return &entry->fProgram;
229 }
230};
231
232GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
233}
234
235static uint32_t ror(uint32_t x) {
236 return (x >> 8) | (x << 24);
237}
238
reed@google.comac10a2d2010-12-22 21:39:39 +0000239GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
240 fDesc = desc;
241 // if you change the size of the desc, need to update the hash function
242 GR_STATIC_ASSERT(8 == sizeof(ProgramDesc));
243
244 uint32_t* d = (uint32_t*) &fDesc;
245 fHash = d[0] ^ ror(d[1]);
246}
247
248bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
249 const HashKey& key) {
250 return entry.fKey == key;
251}
252
253bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
254 const HashKey& key) {
255 return entry.fKey < key;
256}
257
258bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
259 return fDesc == key.fDesc;
260}
261
262bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
263 return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
264}
265
266uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
267 return fHash;
268}
269
270
271struct GrGpuGLShaders2::ShaderCodeSegments {
272 GrSStringBuilder<256> fVSUnis;
273 GrSStringBuilder<256> fVSAttrs;
274 GrSStringBuilder<256> fVaryings;
275 GrSStringBuilder<256> fFSUnis;
276 GrSStringBuilder<512> fVSCode;
277 GrSStringBuilder<512> fFSCode;
278};
279// for variable names etc
280typedef GrSStringBuilder<16> GrTokenString;
281
282#if ATTRIBUTE_MATRIX
283 #define VIEW_MATRIX_NAME "aViewM"
284#else
285 #define VIEW_MATRIX_NAME "uViewM"
286#endif
287
288#define POS_ATTR_NAME "aPosition"
289#define COL_ATTR_NAME "aColor"
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000290
291static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
292 *s = "aTexCoord";
293 s->appendInt(coordIdx);
294}
reed@google.comac10a2d2010-12-22 21:39:39 +0000295
296static inline const char* float_vector_type(int count) {
297 static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
298 GrAssert(count >= 1 && count < GR_ARRAY_COUNT(FLOAT_VECS));
299 return FLOAT_VECS[count];
300}
301
302static inline const char* vector_homog_coord(int count) {
303 static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
304 GrAssert(count >= 1 && count < GR_ARRAY_COUNT(HOMOGS));
305 return HOMOGS[count];
306}
307
308static inline const char* vector_nonhomog_coords(int count) {
309 static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
310 GrAssert(count >= 1 && count < GR_ARRAY_COUNT(NONHOMOGS));
311 return NONHOMOGS[count];
312}
313
314static inline const char* vector_all_coords(int count) {
315 static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
316 GrAssert(count >= 1 && count < GR_ARRAY_COUNT(ALL));
317 return ALL[count];
318}
319
320static void tex_matrix_name(int stage, GrStringBuilder* s) {
321#if ATTRIBUTE_MATRIX
322 *s = "aTexM";
323#else
324 *s = "uTexM";
325#endif
326 s->appendInt(stage);
327}
328
329static void sampler_name(int stage, GrStringBuilder* s) {
330 *s = "uSampler";
331 s->appendInt(stage);
332}
333
334static void stage_varying_name(int stage, GrStringBuilder* s) {
335 *s = "vStage";
336 s->appendInt(stage);
337}
338
339static void radial2_param_name(int stage, GrStringBuilder* s) {
340 *s = "uRadial2Params";
341 s->appendInt(stage);
342}
343
344static void radial2_varying_name(int stage, GrStringBuilder* s) {
345 *s = "vB";
346 s->appendInt(stage);
347}
348
349#include "GrRandom.h"
350
351void GrGpuGLShaders2::ProgramUnitTest() {
reed@google.comac10a2d2010-12-22 21:39:39 +0000352 static const int PROG_OPTS[] = {
353 0,
354 ProgramDesc::kNotPoints_OptFlagBit,
355 ProgramDesc::kVertexColorAllOnes_OptFlagBit,
356 ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
357 };
358 static const int STAGE_OPTS[] = {
359 0,
360 StageDesc::kNoPerspective_OptFlagBit,
361 StageDesc::kIdentity_CoordMapping
362 };
363 static const int STAGE_MODULATES[] = {
364 StageDesc::kColor_Modulation,
365 StageDesc::kAlpha_Modulation
366 };
367 static const int STAGE_COORD_MAPPINGS[] = {
368 StageDesc::kIdentity_CoordMapping,
369 StageDesc::kRadialGradient_CoordMapping,
370 StageDesc::kSweepGradient_CoordMapping,
371 StageDesc::kRadial2Gradient_CoordMapping
372 };
373 ProgramDesc pdesc;
374 memset(&pdesc, 0, sizeof(pdesc));
375
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000376 static const int NUM_TESTS = 512;
reed@google.comac10a2d2010-12-22 21:39:39 +0000377
378 // GrRandoms nextU() values have patterns in the low bits
379 // So using nextU() % array_count might never take some values.
380 GrRandom random;
381 for (int t = 0; t < NUM_TESTS; ++t) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000382
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000383 pdesc.fVertexLayout = 0;
384 for (int s = 0; s < kNumStages; ++s) {
385 // enable the stage?
386 if (random.nextF() > .5f) {
387 // use separate tex coords?
388 if (random.nextF() > .5f) {
389 int t = (int)(random.nextF() * kMaxTexCoords);
390 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
391 } else {
392 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
393 }
394 }
395 // use text-formatted verts?
396 if (random.nextF() > .5f) {
397 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
398 }
399 }
400
401 int x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
reed@google.comac10a2d2010-12-22 21:39:39 +0000402 pdesc.fOptFlags = PROG_OPTS[x];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000403 for (int s = 0; s < kNumStages; ++s) {
404 pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
406 pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
407 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000408 pdesc.fStages[s].fModulation = (StageDesc::Modulation) STAGE_MODULATES[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000409 x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
bsalomon@google.com2fbc7fa2011-01-05 16:34:41 +0000410 pdesc.fStages[s].fCoordMapping = (StageDesc::CoordMapping) STAGE_COORD_MAPPINGS[x];
reed@google.comac10a2d2010-12-22 21:39:39 +0000411 }
412 Program program;
413 GenProgram(pdesc, &program);
414 DeleteProgram(&program);
415 }
416}
417
418void GrGpuGLShaders2::GenStageCode(int stageNum,
419 const StageDesc& desc,
420 const char* fsInColor, // NULL means no incoming color
421 const char* fsOutColor,
422 const char* vsInCoord,
423 ShaderCodeSegments* segments,
424 StageUniLocations* locations) {
425
426 GrAssert(stageNum >= 0 && stageNum <= 9);
427
428 GrTokenString varyingName;
429 stage_varying_name(stageNum, &varyingName);
430
431 // First decide how many coords are needed to access the texture
432 // Right now it's always 2 but we could start using 1D textures for
433 // gradients.
434 static const int coordDims = 2;
435 int varyingDims;
436 /// Vertex Shader Stuff
437
438 // decide whether we need a matrix to transform texture coords
439 // and whether the varying needs a perspective coord.
440 GrTokenString texMName;
441 tex_matrix_name(stageNum, &texMName);
442 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
443 varyingDims = coordDims;
444 } else {
445 #if ATTRIBUTE_MATRIX
446 segments->fVSAttrs += "attribute mat3 ";
447 segments->fVSAttrs += texMName;
448 segments->fVSAttrs += ";\n";
449 #else
450 segments->fVSUnis += "uniform mat3 ";
451 segments->fVSUnis += texMName;
452 segments->fVSUnis += ";\n";
453 locations->fTextureMatrixUni = 1;
454 #endif
455 if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
456 varyingDims = coordDims;
457 } else {
458 varyingDims = coordDims + 1;
459 }
460 }
461
462 GrTokenString samplerName;
463 sampler_name(stageNum, &samplerName);
464 segments->fFSUnis += "uniform sampler2D ";
465 segments->fFSUnis += samplerName;
466 segments->fFSUnis += ";\n";
467 locations->fSamplerUni = 1;
468
469 segments->fVaryings += "varying ";
470 segments->fVaryings += float_vector_type(varyingDims);
471 segments->fVaryings += " ";
472 segments->fVaryings += varyingName;
473 segments->fVaryings += ";\n";
474
475 if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
476 GrAssert(varyingDims == coordDims);
477 segments->fVSCode += "\t";
478 segments->fVSCode += varyingName;
479 segments->fVSCode += " = ";
480 segments->fVSCode += vsInCoord;
481 segments->fVSCode += ";\n";
482 } else {
483 segments->fVSCode += "\t";
484 segments->fVSCode += varyingName;
485 segments->fVSCode += " = (";
486 segments->fVSCode += texMName;
487 segments->fVSCode += " * vec3(";
488 segments->fVSCode += vsInCoord;
489 segments->fVSCode += ", 1))";
490 segments->fVSCode += vector_all_coords(varyingDims);
491 segments->fVSCode += ";\n";
492 }
493
494 GrTokenString radial2ParamsName;
495 radial2_param_name(stageNum, &radial2ParamsName);
496 // for radial grads without perspective we can pass the linear
497 // part of the quadratic as a varying.
498 GrTokenString radial2VaryingName;
499 radial2_varying_name(stageNum, &radial2VaryingName);
500
501 if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
502
503 segments->fVSUnis += "uniform " GR_PRECISION " float ";
504 segments->fVSUnis += radial2ParamsName;
505 segments->fVSUnis += "[6];\n";
506
507 segments->fFSUnis += "uniform " GR_PRECISION " float ";
508 segments->fFSUnis += radial2ParamsName;
509 segments->fFSUnis += "[6];\n";
510 locations->fRadial2Uni = 1;
511
512 // if there is perspective we don't interpolate this
513 if (varyingDims == coordDims) {
514 GrAssert(2 == coordDims);
515 segments->fVaryings += "varying float ";
516 segments->fVaryings += radial2VaryingName;
517 segments->fVaryings += ";\n";
518
519 segments->fVSCode += "\t";
520 segments->fVSCode += radial2VaryingName;
521 segments->fVSCode += " = 2.0 * (";
522 segments->fVSCode += radial2ParamsName;
523 segments->fVSCode += "[2] * ";
524 segments->fVSCode += varyingName;
525 segments->fVSCode += ".x ";
526 segments->fVSCode += " - ";
527 segments->fVSCode += radial2ParamsName;
528 segments->fVSCode += "[3]);\n";
529 }
530 }
531
532 /// Fragment Shader Stuff
533 GrTokenString fsCoordName;
534 // function used to access the shader, may be made projective
535 GrTokenString texFunc("texture2D");
536 if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
537 StageDesc::kNoPerspective_OptFlagBit)) {
538 GrAssert(varyingDims == coordDims);
539 fsCoordName = varyingName;
540 } else {
541 // if we have to do some non-matrix op on the varyings to get
542 // our final tex coords then when in perspective we have to
543 // do an explicit divide
544 if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
545 texFunc += "Proj";
546 fsCoordName = varyingName;
547 } else {
548 fsCoordName = "tCoord";
549 fsCoordName.appendInt(stageNum);
550
551 segments->fFSCode += "\t";
552 segments->fFSCode += float_vector_type(coordDims);
553 segments->fFSCode += " ";
554 segments->fFSCode += fsCoordName;
555 segments->fFSCode += " = ";
556 segments->fFSCode += varyingName;
557 segments->fFSCode += vector_nonhomog_coords(varyingDims);
558 segments->fFSCode += " / ";
559 segments->fFSCode += varyingName;
560 segments->fFSCode += vector_homog_coord(varyingDims);
561 segments->fFSCode += ";\n";
562 }
563 }
564
565 GrSStringBuilder<96> sampleCoords;
566 switch (desc.fCoordMapping) {
567 case StageDesc::kIdentity_CoordMapping:
568 sampleCoords = fsCoordName;
569 break;
570 case StageDesc::kSweepGradient_CoordMapping:
571 sampleCoords = "vec2(atan(-";
572 sampleCoords += fsCoordName;
573 sampleCoords += ".y, -";
574 sampleCoords += fsCoordName;
575 sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
576 break;
577 case StageDesc::kRadialGradient_CoordMapping:
578 sampleCoords = "vec2(length(";
579 sampleCoords += fsCoordName;
580 sampleCoords += ".xy), 0.5)";
581 break;
582 case StageDesc::kRadial2Gradient_CoordMapping: {
583 GrTokenString cName = "c";
584 GrTokenString ac4Name = "ac4";
585 GrTokenString rootName = "root";
586
587 cName.appendInt(stageNum);
588 ac4Name.appendInt(stageNum);
589 rootName.appendInt(stageNum);
590
591 GrTokenString bVar;
592 if (coordDims == varyingDims) {
593 bVar = radial2VaryingName;
594 GrAssert(2 == varyingDims);
595 } else {
596 GrAssert(3 == varyingDims);
597 bVar = "b";
598 bVar.appendInt(stageNum);
599 segments->fFSCode += "\tfloat ";
600 segments->fFSCode += bVar;
601 segments->fFSCode += " = 2.0 * (";
602 segments->fFSCode += radial2ParamsName;
603 segments->fFSCode += "[2] * ";
604 segments->fFSCode += fsCoordName;
605 segments->fFSCode += ".x ";
606 segments->fFSCode += " - ";
607 segments->fFSCode += radial2ParamsName;
608 segments->fFSCode += "[3]);\n";
609 }
610
611 segments->fFSCode += "\tfloat ";
612 segments->fFSCode += cName;
613 segments->fFSCode += " = dot(";
614 segments->fFSCode += fsCoordName;
615 segments->fFSCode += ", ";
616 segments->fFSCode += fsCoordName;
617 segments->fFSCode += ") + ";
618 segments->fFSCode += " - ";
619 segments->fFSCode += radial2ParamsName;
620 segments->fFSCode += "[4];\n";
621
622 segments->fFSCode += "\tfloat ";
623 segments->fFSCode += ac4Name;
624 segments->fFSCode += " = ";
625 segments->fFSCode += radial2ParamsName;
626 segments->fFSCode += "[0] * 4.0 * ";
627 segments->fFSCode += cName;
628 segments->fFSCode += ";\n";
629
630 segments->fFSCode += "\tfloat ";
631 segments->fFSCode += rootName;
632 segments->fFSCode += " = sqrt(abs(";
633 segments->fFSCode += bVar;
634 segments->fFSCode += " * ";
635 segments->fFSCode += bVar;
636 segments->fFSCode += " - ";
637 segments->fFSCode += ac4Name;
638 segments->fFSCode += "));\n";
639
640 sampleCoords = "vec2((-";
641 sampleCoords += bVar;
642 sampleCoords += " + ";
643 sampleCoords += radial2ParamsName;
644 sampleCoords += "[5] * ";
645 sampleCoords += rootName;
646 sampleCoords += ") * ";
647 sampleCoords += radial2ParamsName;
648 sampleCoords += "[1], 0.5)\n";
649 break;}
650 };
651
652 segments->fFSCode += "\t";
653 segments->fFSCode += fsOutColor;
654 segments->fFSCode += " = ";
655 if (NULL != fsInColor) {
656 segments->fFSCode += fsInColor;
657 segments->fFSCode += " * ";
658 }
659 segments->fFSCode += texFunc;
660 segments->fFSCode += "(";
661 segments->fFSCode += samplerName;
662 segments->fFSCode += ", ";
663 segments->fFSCode += sampleCoords;
664 segments->fFSCode += ")";
665 if (desc.fModulation == StageDesc::kAlpha_Modulation) {
666 segments->fFSCode += ".aaaa";
667 }
668 segments->fFSCode += ";\n";
669
670}
671
672void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
673 Program* program) {
674
675 ShaderCodeSegments segments;
676 const uint32_t& layout = desc.fVertexLayout;
677
678 memset(&program->fUniLocations, 0, sizeof(UniLocations));
679
680 bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
681 desc.fOptFlags);
682
683#if ATTRIBUTE_MATRIX
684 segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"
685#else
686 segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
687 segments.fVSAttrs = "";
688#endif
689 segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
690 if (haveColor) {
691 segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
692 segments.fVaryings = "varying vec4 vColor;\n";
693 } else {
694 segments.fVaryings = "";
695 }
696
697 segments.fVSCode = "void main() {\n"
698 "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
699 "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
700 if (haveColor) {
701 segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
702 }
703
704 if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
705 segments.fVSCode += "\tgl_PointSize = 1.0;\n";
706 }
707 segments.fFSCode = "void main() {\n";
708
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000709 // add texture coordinates that are used to the list of vertex attr decls
710 GrTokenString texCoordAttrs[kMaxTexCoords];
711 for (int t = 0; t < kMaxTexCoords; ++t) {
712 if (VertexUsesTexCoordIdx(t, layout)) {
713 tex_attr_name(t, texCoordAttrs + t);
714
715 segments.fVSAttrs += "attribute vec2 ";
716 segments.fVSAttrs += texCoordAttrs[t];
717 segments.fVSAttrs += ";\n";
718 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000719 }
720
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000721 // for each enabled stage figure out what the input coordinates are
722 // and count the number of stages in use.
723 const char* stageInCoords[kNumStages];
reed@google.comac10a2d2010-12-22 21:39:39 +0000724 int numActiveStages = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000725
726 for (int s = 0; s < kNumStages; ++s) {
727 if (desc.fStages[s].fEnabled) {
728 if (StagePosAsTexCoordVertexLayoutBit(s) & layout) {
729 stageInCoords[s] = POS_ATTR_NAME;
730 } else {
731 int tcIdx = VertexTexCoordsForStage(s, layout);
732 // we better have input tex coordinates if stage is enabled.
733 GrAssert(tcIdx >= 0);
734 GrAssert(texCoordAttrs[tcIdx].length());
735 stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
736 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000737 ++numActiveStages;
738 }
739 }
bsalomon@google.com316f99232011-01-13 21:28:12 +0000740
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000741 GrTokenString inColor = "vColor";
742
743 // if we have active stages string them together, feeding the output color
744 // of each to the next and generating code for each stage.
745 if (numActiveStages) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000746 int currActiveStage = 0;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000747 for (int s = 0; s < kNumStages; ++s) {
748 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000749 GrTokenString outColor;
750 if (currActiveStage < (numActiveStages - 1)) {
751 outColor = "color";
752 outColor.appendInt(currActiveStage);
753 segments.fFSCode += "\tvec4 ";
754 segments.fFSCode += outColor;
755 segments.fFSCode += ";\n";
756 } else {
757 outColor = "gl_FragColor";
758 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000759 GenStageCode(s,
760 desc.fStages[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000761 haveColor ? inColor.cstr() : NULL,
762 outColor.cstr(),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000763 stageInCoords[s],
reed@google.comac10a2d2010-12-22 21:39:39 +0000764 &segments,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000765 &program->fUniLocations.fStages[s]);
reed@google.comac10a2d2010-12-22 21:39:39 +0000766 ++currActiveStage;
767 inColor = outColor;
768 haveColor = true;
769 }
770 }
771 } else {
772 segments.fFSCode += "\tgl_FragColor = ";
773 if (haveColor) {
774 segments.fFSCode += inColor;
775 } else {
776 segments.fFSCode += "vec4(1,1,1,1)";
777 }
778 segments.fFSCode += ";\n";
779 }
780 segments.fFSCode += "}\n";
781 segments.fVSCode += "}\n";
782
783
784 const char* strings[4];
785 int lengths[4];
786 int stringCnt = 0;
787
788 if (segments.fVSUnis.length()) {
789 strings[stringCnt] = segments.fVSUnis.cstr();
790 lengths[stringCnt] = segments.fVSUnis.length();
791 ++stringCnt;
792 }
793 if (segments.fVSAttrs.length()) {
794 strings[stringCnt] = segments.fVSAttrs.cstr();
795 lengths[stringCnt] = segments.fVSAttrs.length();
796 ++stringCnt;
797 }
798 if (segments.fVaryings.length()) {
799 strings[stringCnt] = segments.fVaryings.cstr();
800 lengths[stringCnt] = segments.fVaryings.length();
801 ++stringCnt;
802 }
803
804 GrAssert(segments.fVSCode.length());
805 strings[stringCnt] = segments.fVSCode.cstr();
806 lengths[stringCnt] = segments.fVSCode.length();
807 ++stringCnt;
808
809#if PRINT_SHADERS
810 GrPrintf("%s%s%s%s\n",
811 segments.fVSUnis.cstr(),
812 segments.fVSAttrs.cstr(),
813 segments.fVaryings.cstr(),
814 segments.fVSCode.cstr());
815#endif
816 program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
817 stringCnt,
818 strings,
819 lengths);
820
821 stringCnt = 0;
822
823 if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
824 strings[stringCnt] = GR_SHADER_PRECISION;
825 lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
826 ++stringCnt;
827 }
828 if (segments.fFSUnis.length()) {
829 strings[stringCnt] = segments.fFSUnis.cstr();
830 lengths[stringCnt] = segments.fFSUnis.length();
831 ++stringCnt;
832 }
833 if (segments.fVaryings.length()) {
834 strings[stringCnt] = segments.fVaryings.cstr();
835 lengths[stringCnt] = segments.fVaryings.length();
836 ++stringCnt;
837 }
838
839 GrAssert(segments.fFSCode.length());
840 strings[stringCnt] = segments.fFSCode.cstr();
841 lengths[stringCnt] = segments.fFSCode.length();
842 ++stringCnt;
843
844#if PRINT_SHADERS
845 GrPrintf("%s%s%s%s\n",
846 GR_SHADER_PRECISION,
847 segments.fFSUnis.cstr(),
848 segments.fVaryings.cstr(),
849 segments.fFSCode.cstr());
850#endif
851 program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
852 stringCnt,
853 strings,
854 lengths);
855
856 program->fProgramID = GR_GL(CreateProgram());
857 const GLint& progID = program->fProgramID;
858
859 GR_GL(AttachShader(progID, program->fVShaderID));
860 GR_GL(AttachShader(progID, program->fFShaderID));
861
862 // Bind the attrib locations to same values for all shaders
863 GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000864 for (int t = 0; t < kMaxTexCoords; ++t) {
865 if (texCoordAttrs[t].length()) {
bsalomon@google.com316f99232011-01-13 21:28:12 +0000866 GR_GL(BindAttribLocation(progID,
867 TEX_ATTR_LOCATION(t),
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000868 texCoordAttrs[t].cstr()));
869 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000870 }
871
872#if ATTRIBUTE_MATRIX
873 // set unis to a bogus value so that checks against -1 before
874 // flushing will pass.
875 GR_GL(BindAttribLocation(progID,
876 VIEWMAT_ATTR_LOCATION,
877 VIEW_MATRIX_NAME));
878
879 program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
880
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000881 for (int s = 0; s < kNumStages; ++s) {
882 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000883 GR_GL(BindAttribLocation(progID,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000884 TEXMAT_ATTR_LOCATION(s),
reed@google.comac10a2d2010-12-22 21:39:39 +0000885 tex_matrix_name(i).cstr()));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000886 program->fUniLocations.fStages[s].fTextureMatrixUni =
reed@google.comac10a2d2010-12-22 21:39:39 +0000887 BOGUS_MATRIX_UNI_LOCATION;
888 }
889 }
890#endif
891
892 GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
893
894 GR_GL(LinkProgram(progID));
895
896 GLint linked;
897 GR_GL(GetProgramiv(progID, GL_LINK_STATUS, &linked));
898 if (!linked) {
899 GLint infoLen;
900 GR_GL(GetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen));
901 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
902 if (infoLen > 0) {
903 GR_GL(GetProgramInfoLog(progID,
904 infoLen+1,
905 NULL,
906 (char*)log.get()));
907 GrPrintf((char*)log.get());
908 }
909 GrAssert(!"Error linking program");
910 GR_GL(DeleteProgram(progID));
911 program->fProgramID = 0;
912 return;
913 }
914
915 // Get uniform locations
916#if !ATTRIBUTE_MATRIX
917 program->fUniLocations.fViewMatrixUni =
918 GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
919 GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
920#endif
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000921 for (int s = 0; s < kNumStages; ++s) {
922 StageUniLocations& locations = program->fUniLocations.fStages[s];
923 if (desc.fStages[s].fEnabled) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000924#if !ATTRIBUTE_MATRIX
925 if (locations.fTextureMatrixUni) {
926 GrTokenString texMName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000927 tex_matrix_name(s, &texMName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000928 locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
929 progID,
930 texMName.cstr()));
931 GrAssert(-1 != locations.fTextureMatrixUni);
932 } else {
933 locations.fTextureMatrixUni = -1;
934
935 }
936#endif
937
938 if (locations.fSamplerUni) {
939 GrTokenString samplerName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000940 sampler_name(s, &samplerName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000941 locations.fSamplerUni = GR_GL(GetUniformLocation(
942 progID,
943 samplerName.cstr()));
944 GrAssert(-1 != locations.fSamplerUni);
945 } else {
946 locations.fSamplerUni = -1;
947 }
948
949 if (locations.fRadial2Uni) {
950 GrTokenString radial2ParamName;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000951 radial2_param_name(s, &radial2ParamName);
reed@google.comac10a2d2010-12-22 21:39:39 +0000952 locations.fRadial2Uni = GR_GL(GetUniformLocation(
953 progID,
954 radial2ParamName.cstr()));
955 GrAssert(-1 != locations.fRadial2Uni);
956 } else {
957 locations.fRadial2Uni = -1;
958 }
959 } else {
960 locations.fSamplerUni = -1;
961 locations.fRadial2Uni = -1;
962 locations.fTextureMatrixUni = -1;
963 }
964 }
965 GR_GL(UseProgram(progID));
966
967 // init sampler unis and set bogus values for state tracking
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000968 for (int s = 0; s < kNumStages; ++s) {
969 if (-1 != program->fUniLocations.fStages[s].fSamplerUni) {
970 GR_GL(Uniform1i(program->fUniLocations.fStages[s].fSamplerUni, s));
reed@google.comac10a2d2010-12-22 21:39:39 +0000971 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000972 program->fTextureMatrix[s].setScale(GR_ScalarMax, GR_ScalarMax);
973 program->fRadial2CenterX1[s] = GR_ScalarMax;
974 program->fRadial2Radius0[s] = -GR_ScalarMax;
reed@google.comac10a2d2010-12-22 21:39:39 +0000975 }
976 program->fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
977}
978
979void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
980
981 // Must initialize all fields or cache will have false negatives!
982 desc->fVertexLayout = fGeometrySrc.fVertexLayout;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000983 for (int s = 0; s < kNumStages; ++s) {
984 StageDesc& stage = desc->fStages[s];
bsalomon@google.com316f99232011-01-13 21:28:12 +0000985
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000986 stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
reed@google.comac10a2d2010-12-22 21:39:39 +0000987
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000988 if (primType != kPoints_PrimitiveType) {
989 desc->fOptFlags = ProgramDesc::kNotPoints_OptFlagBit;
reed@google.comac10a2d2010-12-22 21:39:39 +0000990 } else {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000991 desc->fOptFlags = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +0000992 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000993 #if SKIP_COLOR_MODULATE_OPT
994 if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
995 (0xffffffff == fCurrDrawState.fColor)) {
996 desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000998 #endif
999
1000 if (stage.fEnabled) {
1001 GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
1002 GrAssert(NULL != texture);
1003 // we matrix to invert when orientation is TopDown, so make sure
1004 // we aren't in that case before flagging as identity.
1005 if (fCurrDrawState.fTextureMatrices[s].isIdentity() &&
1006 GrGLTexture::kTopDown_Orientation == texture->orientation()) {
1007 stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
1008 } else if (!fCurrDrawState.fTextureMatrices[s].hasPerspective()) {
1009 stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
1010 } else {
1011 stage.fOptFlags = 0;
1012 }
1013 switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
1014 case GrSamplerState::kNormal_SampleMode:
1015 stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
1016 break;
1017 case GrSamplerState::kRadial_SampleMode:
1018 stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
1019 break;
1020 case GrSamplerState::kRadial2_SampleMode:
1021 stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
1022 break;
1023 case GrSamplerState::kSweep_SampleMode:
1024 stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
1025 break;
1026 default:
1027 GrAssert(!"Unexpected sample mode!");
1028 break;
1029 }
1030 if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
1031 stage.fModulation = StageDesc::kAlpha_Modulation;
1032 } else {
1033 stage.fModulation = StageDesc::kColor_Modulation;
1034 }
1035 } else {
1036 stage.fOptFlags = 0;
1037 stage.fCoordMapping = (StageDesc::CoordMapping)0;
1038 stage.fModulation = (StageDesc::Modulation)0;
1039 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001040 }
1041}
1042
1043GLuint GrGpuGLShaders2::CompileShader(GLenum type,
1044 int stringCnt,
1045 const char** strings,
1046 int* stringLengths) {
1047 GLuint shader = GR_GL(CreateShader(type));
1048 if (0 == shader) {
1049 return 0;
1050 }
1051
1052 GLint compiled;
1053 GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
1054 GR_GL(CompileShader(shader));
1055 GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
1056
1057 if (!compiled) {
1058 GLint infoLen;
1059 GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
1060 GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
1061 if (infoLen > 0) {
1062 GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
1063 for (int i = 0; i < stringCnt; ++i) {
1064 if (NULL == stringLengths || stringLengths[i] < 0) {
1065 GrPrintf(strings[i]);
1066 } else {
1067 GrPrintf("%.*s", stringLengths[i], strings[i]);
1068 }
1069 }
1070 GrPrintf("\n%s", log.get());
1071 }
1072 GrAssert(!"Shader compilation failed!");
1073 GR_GL(DeleteShader(shader));
1074 return 0;
1075 }
1076 return shader;
1077}
1078
1079void GrGpuGLShaders2::DeleteProgram(Program* program) {
1080 GR_GL(DeleteShader(program->fVShaderID));
1081 GR_GL(DeleteShader(program->fFShaderID));
1082 GR_GL(DeleteProgram(program->fProgramID));
1083 GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
1084}
1085
1086
1087GrGpuGLShaders2::GrGpuGLShaders2() {
1088
1089 resetContextHelper();
1090
1091 fProgram = NULL;
1092 fProgramCache = new ProgramCache();
1093
1094#if GR_DEBUG
1095 ProgramUnitTest();
1096#endif
1097}
1098
1099GrGpuGLShaders2::~GrGpuGLShaders2() {
1100 delete fProgramCache;
1101}
1102
1103void GrGpuGLShaders2::resetContext() {
1104 INHERITED::resetContext();
1105 resetContextHelper();
1106}
1107
1108void GrGpuGLShaders2::resetContextHelper() {
1109 fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
1110
1111 fHWGeometryState.fVertexLayout = 0;
1112 fHWGeometryState.fPositionPtr = (void*) ~0;
1113 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001114 for (int t = 0; t < kMaxTexCoords; ++t) {
1115 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1116 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001117 GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
1118
1119 fHWProgramID = 0;
1120}
1121
1122void GrGpuGLShaders2::flushViewMatrix() {
1123 GrAssert(NULL != fCurrDrawState.fRenderTarget);
1124 GrMatrix m (
1125 GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
1126 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
1127 0, 0, GrMatrix::I()[8]);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001128 m.setConcat(m, fCurrDrawState.fViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001129
1130 // ES doesn't allow you to pass true to the transpose param,
1131 // so do our own transpose
1132 GrScalar mt[] = {
1133 m[GrMatrix::kScaleX],
1134 m[GrMatrix::kSkewY],
1135 m[GrMatrix::kPersp0],
1136 m[GrMatrix::kSkewX],
1137 m[GrMatrix::kScaleY],
1138 m[GrMatrix::kPersp1],
1139 m[GrMatrix::kTransX],
1140 m[GrMatrix::kTransY],
1141 m[GrMatrix::kPersp2]
1142 };
1143#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001144 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
1145 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
1146 GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001147#else
1148 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
1149#endif
1150}
1151
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001152void GrGpuGLShaders2::flushTextureMatrix(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001153
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001154 GrAssert(NULL != fCurrDrawState.fTextures[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001155 GrGLTexture::Orientation orientation =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001156 ((GrGLTexture*)fCurrDrawState.fTextures[stage])->orientation();
reed@google.comac10a2d2010-12-22 21:39:39 +00001157
1158 GrMatrix* m;
1159 GrMatrix temp;
1160 if (GrGLTexture::kBottomUp_Orientation == orientation) {
1161 temp.setAll(
1162 GR_Scalar1, 0, 0,
1163 0, -GR_Scalar1, GR_Scalar1,
1164 0, 0, GrMatrix::I()[8]
1165 );
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001166 temp.preConcat(fCurrDrawState.fTextureMatrices[stage]);
reed@google.comac10a2d2010-12-22 21:39:39 +00001167 m = &temp;
1168 } else {
1169 GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001170 m = &fCurrDrawState.fTextureMatrices[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001171 }
1172
1173 // ES doesn't allow you to pass true to the transpose param,
1174 // so do our own transpose
1175 GrScalar mt[] = {
1176 (*m)[GrMatrix::kScaleX],
1177 (*m)[GrMatrix::kSkewY],
1178 (*m)[GrMatrix::kPersp0],
1179 (*m)[GrMatrix::kSkewX],
1180 (*m)[GrMatrix::kScaleY],
1181 (*m)[GrMatrix::kPersp1],
1182 (*m)[GrMatrix::kTransX],
1183 (*m)[GrMatrix::kTransY],
1184 (*m)[GrMatrix::kPersp2]
1185 };
1186#if ATTRIBUTE_MATRIX
bsalomon@google.com316f99232011-01-13 21:28:12 +00001187 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
1188 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
1189 GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
reed@google.comac10a2d2010-12-22 21:39:39 +00001190#else
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001191 GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[stage].fTextureMatrixUni,
reed@google.comac10a2d2010-12-22 21:39:39 +00001192 1,
1193 false,
1194 mt));
1195#endif
1196}
1197
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001198void GrGpuGLShaders2::flushRadial2(int stage) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001199
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001200 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
reed@google.comac10a2d2010-12-22 21:39:39 +00001201
1202 GrScalar centerX1 = sampler.getRadial2CenterX1();
1203 GrScalar radius0 = sampler.getRadial2Radius0();
1204
1205 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
1206
1207 float unis[6] = {
1208 GrScalarToFloat(a),
1209 1 / (2.f * unis[0]),
1210 GrScalarToFloat(centerX1),
1211 GrScalarToFloat(radius0),
1212 GrScalarToFloat(GrMul(radius0, radius0)),
1213 sampler.isRadial2PosRoot() ? 1.f : -1.f
1214 };
bsalomon@google.com316f99232011-01-13 21:28:12 +00001215 GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[stage].fRadial2Uni,
1216 6,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001217 unis));
reed@google.comac10a2d2010-12-22 21:39:39 +00001218}
1219
1220void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
1221 ProgramDesc desc;
1222 getProgramDesc(type, &desc);
1223 fProgram = fProgramCache->getProgram(desc);
1224
1225 if (fHWProgramID != fProgram->fProgramID) {
1226 GR_GL(UseProgram(fProgram->fProgramID));
1227 fHWProgramID = fProgram->fProgramID;
1228#if GR_COLLECT_STATS
1229 ++fStats.fProgChngCnt;
1230#endif
1231 }
1232}
1233
1234bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
1235
1236 flushGLStateCommon(type);
1237
1238 if (fRenderTargetChanged) {
1239 // our coords are in pixel space and the GL matrices map to NDC
1240 // so if the viewport changed, our matrix is now wrong.
1241#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001242 fHWDrawState.fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
reed@google.comac10a2d2010-12-22 21:39:39 +00001243#else
1244 // we assume all shader matrices may be wrong after viewport changes
1245 fProgramCache->invalidateViewMatrices();
1246#endif
1247 fRenderTargetChanged = false;
1248 }
1249
1250 flushProgram(type);
1251
1252 if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
1253 // invalidate the immediate mode color
1254 fHWDrawState.fColor = GrColor_ILLEGAL;
1255 } else {
1256 if (fHWDrawState.fColor != fCurrDrawState.fColor) {
1257 // OpenGL ES only supports the float varities of glVertexAttrib
1258 float c[] = {
1259 GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
1260 GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
1261 GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
1262 GrColorUnpackA(fCurrDrawState.fColor) / 255.f
1263 };
1264 GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
1265 fHWDrawState.fColor = fCurrDrawState.fColor;
1266 }
1267 }
1268
1269#if ATTRIBUTE_MATRIX
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001270 GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
reed@google.comac10a2d2010-12-22 21:39:39 +00001271 GrMatrix& currTextureMatrix = fHWDrawState.fMatrixModeCache[kTexture_MatrixMode];
1272 GrGLTexture::Orientation& orientation = fTextureOrientation;
1273#else
1274 GrMatrix& currViewMatrix = fProgram->fViewMatrix;
1275 GrMatrix& currTextureMatrix = fProgram->fTextureMatrix[0];
1276 GrGLTexture::Orientation& orientation = fProgram->fTextureOrientation[0];
1277#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 &&
1288 (currTextureMatrix != fCurrDrawState.fTextureMatrices[s] ||
1289 orientation != texture->orientation())) {
1290 flushTextureMatrix(s);
1291 currTextureMatrix = fCurrDrawState.fTextureMatrices[s];
1292 orientation = texture->orientation();
1293 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001294 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001295
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001296 const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
1297 if (-1 != fProgram->fUniLocations.fStages[s].fRadial2Uni &&
1298 (fProgram->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
1299 fProgram->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
1300 fProgram->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001301
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001302 flushRadial2(s);
reed@google.comac10a2d2010-12-22 21:39:39 +00001303
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001304 fProgram->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
1305 fProgram->fRadial2Radius0[s] = sampler.getRadial2Radius0();
1306 fProgram->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
1307 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001308 }
1309
1310 return true;
1311}
1312
1313void GrGpuGLShaders2::setupGeometry(uint32_t startVertex,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001314 uint32_t startIndex,
1315 uint32_t vertexCount,
1316 uint32_t indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001317
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001318 int newColorOffset;
1319 int newTexCoordOffsets[kMaxTexCoords];
reed@google.comac10a2d2010-12-22 21:39:39 +00001320
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001321 GLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
1322 newTexCoordOffsets,
1323 &newColorOffset);
1324 int oldColorOffset;
1325 int oldTexCoordOffsets[kMaxTexCoords];
1326 GLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
1327 oldTexCoordOffsets,
1328 &oldColorOffset);
reed@google.comac10a2d2010-12-22 21:39:39 +00001329
1330 const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
1331
1332 if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
1333 GrAssert(NULL != fGeometrySrc.fVertexBuffer);
1334 GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
1335 if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
1336 GrGLVertexBuffer* buf =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001337 (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001338 GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
1339 fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
1340 }
1341 } else {
1342 if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
1343 posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
1344 (intptr_t)posPtr);
1345 } else {
1346 GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
1347 posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
1348 }
1349 if (NULL != fHWGeometryState.fVertexBuffer) {
1350 GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
1351 fHWGeometryState.fVertexBuffer = NULL;
1352 }
1353 }
1354
1355 if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
1356 GrAssert(NULL != fGeometrySrc.fIndexBuffer);
1357 GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
1358 if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001359 GrGLIndexBuffer* buf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001360 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
1361 fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
1362 }
1363 } else if (NULL != fHWGeometryState.fIndexBuffer) {
1364 GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
1365 fHWGeometryState.fIndexBuffer = NULL;
1366 }
1367
1368 GLenum scalarType;
1369 bool texCoordNorm;
1370 if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
1371 scalarType = GrGLTextType;
1372 texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
1373 } else {
1374 scalarType = GrGLType;
1375 texCoordNorm = false;
1376 }
1377
1378 bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
1379 bool scalarChange = (GrGLTextType != GrGLType) &&
1380 (kTextFormat_VertexLayoutBit &
1381 (fHWGeometryState.fVertexLayout ^
1382 fGeometrySrc.fVertexLayout));
1383 bool strideChange = newStride != oldStride;
1384 bool posChange = baseChange || scalarChange || strideChange;
1385
1386 if (posChange) {
1387 GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
1388 false, newStride, posPtr));
1389 fHWGeometryState.fPositionPtr = posPtr;
1390 }
1391
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001392 for (int t = 0; t < kMaxTexCoords; ++t) {
1393 if (newTexCoordOffsets[t] > 0) {
1394 GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[t];
1395 if (oldTexCoordOffsets[t] <= 0) {
1396 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
1397 }
1398 if (posChange || newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
1399 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
1400 texCoordNorm, newStride, texCoordPtr));
1401 }
1402 } else if (oldTexCoordOffsets[t] > 0) {
1403 GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
reed@google.comac10a2d2010-12-22 21:39:39 +00001404 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001405 }
1406
1407 if (newColorOffset > 0) {
1408 GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
1409 if (oldColorOffset <= 0) {
1410 GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
1411 }
1412 if (posChange || newColorOffset != oldColorOffset) {
1413 GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
1414 GL_UNSIGNED_BYTE,
1415 true, newStride, colorPtr));
1416 }
1417 } else if (oldColorOffset > 0) {
1418 GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
1419 }
1420
1421 fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
1422}
1423#endif
1424