aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu/src/GrGpuGLShaders2.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-12-22 21:39:39 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-12-22 21:39:39 +0000
commitac10a2d039c5d52eed66e27cbbc503ab523c1cd5 (patch)
treec5be0c3dd15052016e7d32f376507cb1ea7101dd /gpu/src/GrGpuGLShaders2.cpp
parentea8509cd3b1771b36054313d3ccd56679df56044 (diff)
add gpu backend (not hooked up yet)
git-svn-id: http://skia.googlecode.com/svn/trunk@649 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gpu/src/GrGpuGLShaders2.cpp')
-rw-r--r--gpu/src/GrGpuGLShaders2.cpp1388
1 files changed, 1388 insertions, 0 deletions
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
new file mode 100644
index 0000000000..0a15be1c40
--- /dev/null
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -0,0 +1,1388 @@
+/*
+ Copyright 2010 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#include "GrGLConfig.h"
+
+#if GR_SUPPORT_GLES2 || GR_SUPPORT_GLDESKTOP
+
+#include "GrGpuGLShaders2.h"
+#include "GrGpuVertex.h"
+#include "GrMemory.h"
+#include "GrStringBuilder.h"
+
+
+#define ATTRIBUTE_MATRIX 0
+
+#define SKIP_COLOR_MODULATE_OPT 0
+
+#define PRINT_SHADERS 0
+
+#define SKIP_CACHE_CHECK true
+
+#if GR_SUPPORT_GLES2
+ #define GR_PRECISION "mediump"
+ const char GR_SHADER_PRECISION[] = "precision mediump float;\n";
+#else
+ #define GR_PRECISION ""
+ const char GR_SHADER_PRECISION[] = "";
+#endif
+
+#define POS_ATTR_LOCATION 0
+#define TEX_ATTR_LOCATION 1
+#define COL_ATTR_LOCATION 2
+#if ATTRIBUTE_MATRIX
+#define VIEWMAT_ATTR_LOCATION 3
+#define TEXMAT_ATTR_LOCATION(X) (6 + 3 * (X))
+#define BOGUS_MATRIX_UNI_LOCATION 1000
+#endif
+
+const int GrGpuGLShaders2::NUM_STAGES = 1;
+
+struct GrGpuGLShaders2::StageUniLocations {
+ GLint fTextureMatrixUni;
+ GLint fSamplerUni;
+ GLint fRadial2Uni;
+};
+
+struct GrGpuGLShaders2::UniLocations {
+ GLint fViewMatrixUni;
+ StageUniLocations fStages[NUM_STAGES];
+};
+
+// Records per-program information
+// we can specify the attribute locations so that they are constant
+// across our shaders. But the driver determines the uniform locations
+// at link time. We don't need to remember the sampler uniform location
+// because we will bind a texture slot to it and never change it
+// Uniforms are program-local so we can't rely on fHWState to hold the
+// previous uniform state after a program change.
+struct GrGpuGLShaders2::Program {
+ // IDs
+ GLuint fVShaderID;
+ GLuint fFShaderID;
+ GLuint fProgramID;
+
+ // shader uniform locations (-1 if shader doesn't use them)
+ UniLocations fUniLocations;
+
+ // these reflect the current values of uniforms
+ // (GL uniform values travel with program)
+ GrMatrix fViewMatrix;
+ GrMatrix fTextureMatrix[NUM_STAGES];
+ GrGLTexture::Orientation fTextureOrientation[NUM_STAGES];
+ GrScalar fRadial2CenterX1[NUM_STAGES];
+ GrScalar fRadial2Radius0[NUM_STAGES];
+ bool fRadial2PosRoot[NUM_STAGES];
+
+};
+
+// must be tightly packed
+struct GrGpuGLShaders2::StageDesc {
+ enum OptFlagBits {
+ kNoPerspective_OptFlagBit = 0x1,
+ kIdentityMatrix_OptFlagBit = 0x2,
+ };
+ int fOptFlags : 8;
+ bool fEnabled;
+ enum Modulation {
+ kColor_Modulation,
+ kAlpha_Modulation,
+ } fModulation : 8;
+ enum CoordMapping {
+ kIdentity_CoordMapping,
+ kRadialGradient_CoordMapping,
+ kSweepGradient_CoordMapping,
+ kRadial2Gradient_CoordMapping,
+ } fCoordMapping : 8;
+};
+
+// must be tightly packed
+struct GrGpuGLShaders2::ProgramDesc {
+ GrVertexLayout fVertexLayout;
+ enum {
+ kNotPoints_OptFlagBit = 0x1,
+ kVertexColorAllOnes_OptFlagBit = 0x2,
+ };
+ // we're assuming optflags and layout pack into 32 bits
+ GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout));
+ int fOptFlags : 16;
+
+ StageDesc fStages[NUM_STAGES];
+
+ bool operator == (const ProgramDesc& desc) const {
+ // keep 4-byte aligned and tightly packed
+ GR_STATIC_ASSERT(4 == sizeof(StageDesc));
+ GR_STATIC_ASSERT(2 + 2 + 4 * NUM_STAGES == sizeof(ProgramDesc));
+ return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
+ }
+};
+
+#include "GrTHashCache.h"
+
+class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
+private:
+ struct Entry;
+ class HashKey {
+ public:
+ HashKey();
+ HashKey(const ProgramDesc& desc);
+ static const HashKey& GetKey(const Entry&);
+ static bool EQ(const Entry&, const HashKey&);
+ static bool LT(const Entry&, const HashKey&);
+ bool operator <(const HashKey& key) const;
+ bool operator ==(const HashKey& key) const;
+ uint32_t getHash() const;
+ private:
+ ProgramDesc fDesc;
+ uint32_t fHash;
+ };
+
+ struct Entry {
+ Program fProgram;
+ HashKey fKey;
+ uint32_t fLRUStamp;
+ };
+
+ // if hash bits is changed, need to change hash function
+ GrTHashTable<Entry, HashKey, 8> fHashCache;
+
+ static const int MAX_ENTRIES = 16;
+ Entry fEntries[MAX_ENTRIES];
+ int fCount;
+ uint32_t fCurrLRUStamp;
+
+public:
+ ProgramCache() {
+ fCount = 0;
+ fCurrLRUStamp = 0;
+ }
+
+ ~ProgramCache() {
+ for (int i = 0; i < fCount; ++i) {
+ GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
+ }
+ }
+
+ void abandon() {
+ fCount = 0;
+ }
+
+ void invalidateViewMatrices() {
+ for (int i = 0; i < fCount; ++i) {
+ // set to illegal matrix
+ fEntries[i].fProgram.fViewMatrix.setScale(GR_ScalarMax,
+ GR_ScalarMax);
+ }
+ }
+
+ Program* getProgram(const ProgramDesc& desc) {
+ HashKey key(desc);
+ Entry* entry = fHashCache.find(key);
+ if (NULL == entry) {
+ if (fCount < MAX_ENTRIES) {
+ entry = fEntries + fCount;
+ ++fCount;
+ } else {
+ GrAssert(MAX_ENTRIES == fCount);
+ entry = fEntries;
+ for (int i = 1; i < MAX_ENTRIES; ++i) {
+ if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
+ entry = fEntries + i;
+ }
+ }
+ fHashCache.remove(entry->fKey, entry);
+ GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
+ }
+ entry->fKey = key;
+ GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
+ fHashCache.insert(entry->fKey, entry);
+ }
+
+ entry->fLRUStamp = fCurrLRUStamp;
+ if (UINT32_MAX == fCurrLRUStamp) {
+ // wrap around! just trash our LRU, one time hit.
+ for (int i = 0; i < fCount; ++i) {
+ fEntries[i].fLRUStamp = 0;
+ }
+ }
+ ++fCurrLRUStamp;
+ return &entry->fProgram;
+ }
+};
+
+GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
+}
+
+static uint32_t ror(uint32_t x) {
+ return (x >> 8) | (x << 24);
+}
+
+
+GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
+ fDesc = desc;
+ // if you change the size of the desc, need to update the hash function
+ GR_STATIC_ASSERT(8 == sizeof(ProgramDesc));
+
+ uint32_t* d = (uint32_t*) &fDesc;
+ fHash = d[0] ^ ror(d[1]);
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
+ const HashKey& key) {
+ return entry.fKey == key;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
+ const HashKey& key) {
+ return entry.fKey < key;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
+ return fDesc == key.fDesc;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
+ return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
+}
+
+uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
+ return fHash;
+}
+
+
+struct GrGpuGLShaders2::ShaderCodeSegments {
+ GrSStringBuilder<256> fVSUnis;
+ GrSStringBuilder<256> fVSAttrs;
+ GrSStringBuilder<256> fVaryings;
+ GrSStringBuilder<256> fFSUnis;
+ GrSStringBuilder<512> fVSCode;
+ GrSStringBuilder<512> fFSCode;
+};
+// for variable names etc
+typedef GrSStringBuilder<16> GrTokenString;
+
+#if ATTRIBUTE_MATRIX
+ #define VIEW_MATRIX_NAME "aViewM"
+#else
+ #define VIEW_MATRIX_NAME "uViewM"
+#endif
+
+#define POS_ATTR_NAME "aPosition"
+#define COL_ATTR_NAME "aColor"
+#define TEX_ATTR_NAME "aTexture"
+
+static inline const char* float_vector_type(int count) {
+ static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
+ GrAssert(count >= 1 && count < GR_ARRAY_COUNT(FLOAT_VECS));
+ return FLOAT_VECS[count];
+}
+
+static inline const char* vector_homog_coord(int count) {
+ static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
+ GrAssert(count >= 1 && count < GR_ARRAY_COUNT(HOMOGS));
+ return HOMOGS[count];
+}
+
+static inline const char* vector_nonhomog_coords(int count) {
+ static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
+ GrAssert(count >= 1 && count < GR_ARRAY_COUNT(NONHOMOGS));
+ return NONHOMOGS[count];
+}
+
+static inline const char* vector_all_coords(int count) {
+ static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
+ GrAssert(count >= 1 && count < GR_ARRAY_COUNT(ALL));
+ return ALL[count];
+}
+
+static void tex_matrix_name(int stage, GrStringBuilder* s) {
+#if ATTRIBUTE_MATRIX
+ *s = "aTexM";
+#else
+ *s = "uTexM";
+#endif
+ s->appendInt(stage);
+}
+
+static void sampler_name(int stage, GrStringBuilder* s) {
+ *s = "uSampler";
+ s->appendInt(stage);
+}
+
+static void stage_varying_name(int stage, GrStringBuilder* s) {
+ *s = "vStage";
+ s->appendInt(stage);
+}
+
+static void radial2_param_name(int stage, GrStringBuilder* s) {
+ *s = "uRadial2Params";
+ s->appendInt(stage);
+}
+
+static void radial2_varying_name(int stage, GrStringBuilder* s) {
+ *s = "vB";
+ s->appendInt(stage);
+}
+
+#include "GrRandom.h"
+
+void GrGpuGLShaders2::ProgramUnitTest() {
+ static const uint16_t VFORMATS[] = {
+ 0,
+ kSeparateTexCoord_VertexLayoutBit,
+ kPositionAsTexCoord_VertexLayoutBit,
+ kSeparateTexCoord_VertexLayoutBit | kColor_VertexLayoutBit,
+ kPositionAsTexCoord_VertexLayoutBit | kColor_VertexLayoutBit,
+ kTextFormat_VertexLayoutBit
+ };
+ static const int PROG_OPTS[] = {
+ 0,
+ ProgramDesc::kNotPoints_OptFlagBit,
+ ProgramDesc::kVertexColorAllOnes_OptFlagBit,
+ ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
+ };
+ static const int STAGE_OPTS[] = {
+ 0,
+ StageDesc::kNoPerspective_OptFlagBit,
+ StageDesc::kIdentity_CoordMapping
+ };
+ static const int STAGE_MODULATES[] = {
+ StageDesc::kColor_Modulation,
+ StageDesc::kAlpha_Modulation
+ };
+ static const int STAGE_COORD_MAPPINGS[] = {
+ StageDesc::kIdentity_CoordMapping,
+ StageDesc::kRadialGradient_CoordMapping,
+ StageDesc::kSweepGradient_CoordMapping,
+ StageDesc::kRadial2Gradient_CoordMapping
+ };
+ ProgramDesc pdesc;
+ memset(&pdesc, 0, sizeof(pdesc));
+
+ static const int NUM_TESTS = 1024;
+
+ // GrRandoms nextU() values have patterns in the low bits
+ // So using nextU() % array_count might never take some values.
+ GrRandom random;
+ for (int t = 0; t < NUM_TESTS; ++t) {
+ int x = (int)(random.nextF() * GR_ARRAY_COUNT(VFORMATS));
+ pdesc.fVertexLayout = VFORMATS[x];
+ x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
+ pdesc.fOptFlags = PROG_OPTS[x];
+ for (int s = 0; s < NUM_STAGES; ++s) {
+ x = (int)(random.nextF() * 2.f);
+ pdesc.fStages[s].fEnabled = x;
+ x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
+ pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
+ x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
+ pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
+ x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
+ pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
+ }
+ Program program;
+ GenProgram(pdesc, &program);
+ DeleteProgram(&program);
+ }
+}
+
+void GrGpuGLShaders2::GenStageCode(int stageNum,
+ const StageDesc& desc,
+ const char* fsInColor, // NULL means no incoming color
+ const char* fsOutColor,
+ const char* vsInCoord,
+ ShaderCodeSegments* segments,
+ StageUniLocations* locations) {
+
+ GrAssert(stageNum >= 0 && stageNum <= 9);
+
+ GrTokenString varyingName;
+ stage_varying_name(stageNum, &varyingName);
+
+ // First decide how many coords are needed to access the texture
+ // Right now it's always 2 but we could start using 1D textures for
+ // gradients.
+ static const int coordDims = 2;
+ int varyingDims;
+ /// Vertex Shader Stuff
+
+ // decide whether we need a matrix to transform texture coords
+ // and whether the varying needs a perspective coord.
+ GrTokenString texMName;
+ tex_matrix_name(stageNum, &texMName);
+ if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
+ varyingDims = coordDims;
+ } else {
+ #if ATTRIBUTE_MATRIX
+ segments->fVSAttrs += "attribute mat3 ";
+ segments->fVSAttrs += texMName;
+ segments->fVSAttrs += ";\n";
+ #else
+ segments->fVSUnis += "uniform mat3 ";
+ segments->fVSUnis += texMName;
+ segments->fVSUnis += ";\n";
+ locations->fTextureMatrixUni = 1;
+ #endif
+ if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
+ varyingDims = coordDims;
+ } else {
+ varyingDims = coordDims + 1;
+ }
+ }
+
+ GrTokenString samplerName;
+ sampler_name(stageNum, &samplerName);
+ segments->fFSUnis += "uniform sampler2D ";
+ segments->fFSUnis += samplerName;
+ segments->fFSUnis += ";\n";
+ locations->fSamplerUni = 1;
+
+ segments->fVaryings += "varying ";
+ segments->fVaryings += float_vector_type(varyingDims);
+ segments->fVaryings += " ";
+ segments->fVaryings += varyingName;
+ segments->fVaryings += ";\n";
+
+ if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
+ GrAssert(varyingDims == coordDims);
+ segments->fVSCode += "\t";
+ segments->fVSCode += varyingName;
+ segments->fVSCode += " = ";
+ segments->fVSCode += vsInCoord;
+ segments->fVSCode += ";\n";
+ } else {
+ segments->fVSCode += "\t";
+ segments->fVSCode += varyingName;
+ segments->fVSCode += " = (";
+ segments->fVSCode += texMName;
+ segments->fVSCode += " * vec3(";
+ segments->fVSCode += vsInCoord;
+ segments->fVSCode += ", 1))";
+ segments->fVSCode += vector_all_coords(varyingDims);
+ segments->fVSCode += ";\n";
+ }
+
+ GrTokenString radial2ParamsName;
+ radial2_param_name(stageNum, &radial2ParamsName);
+ // for radial grads without perspective we can pass the linear
+ // part of the quadratic as a varying.
+ GrTokenString radial2VaryingName;
+ radial2_varying_name(stageNum, &radial2VaryingName);
+
+ if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
+
+ segments->fVSUnis += "uniform " GR_PRECISION " float ";
+ segments->fVSUnis += radial2ParamsName;
+ segments->fVSUnis += "[6];\n";
+
+ segments->fFSUnis += "uniform " GR_PRECISION " float ";
+ segments->fFSUnis += radial2ParamsName;
+ segments->fFSUnis += "[6];\n";
+ locations->fRadial2Uni = 1;
+
+ // if there is perspective we don't interpolate this
+ if (varyingDims == coordDims) {
+ GrAssert(2 == coordDims);
+ segments->fVaryings += "varying float ";
+ segments->fVaryings += radial2VaryingName;
+ segments->fVaryings += ";\n";
+
+ segments->fVSCode += "\t";
+ segments->fVSCode += radial2VaryingName;
+ segments->fVSCode += " = 2.0 * (";
+ segments->fVSCode += radial2ParamsName;
+ segments->fVSCode += "[2] * ";
+ segments->fVSCode += varyingName;
+ segments->fVSCode += ".x ";
+ segments->fVSCode += " - ";
+ segments->fVSCode += radial2ParamsName;
+ segments->fVSCode += "[3]);\n";
+ }
+ }
+
+ /// Fragment Shader Stuff
+ GrTokenString fsCoordName;
+ // function used to access the shader, may be made projective
+ GrTokenString texFunc("texture2D");
+ if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
+ StageDesc::kNoPerspective_OptFlagBit)) {
+ GrAssert(varyingDims == coordDims);
+ fsCoordName = varyingName;
+ } else {
+ // if we have to do some non-matrix op on the varyings to get
+ // our final tex coords then when in perspective we have to
+ // do an explicit divide
+ if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
+ texFunc += "Proj";
+ fsCoordName = varyingName;
+ } else {
+ fsCoordName = "tCoord";
+ fsCoordName.appendInt(stageNum);
+
+ segments->fFSCode += "\t";
+ segments->fFSCode += float_vector_type(coordDims);
+ segments->fFSCode += " ";
+ segments->fFSCode += fsCoordName;
+ segments->fFSCode += " = ";
+ segments->fFSCode += varyingName;
+ segments->fFSCode += vector_nonhomog_coords(varyingDims);
+ segments->fFSCode += " / ";
+ segments->fFSCode += varyingName;
+ segments->fFSCode += vector_homog_coord(varyingDims);
+ segments->fFSCode += ";\n";
+ }
+ }
+
+ GrSStringBuilder<96> sampleCoords;
+ switch (desc.fCoordMapping) {
+ case StageDesc::kIdentity_CoordMapping:
+ sampleCoords = fsCoordName;
+ break;
+ case StageDesc::kSweepGradient_CoordMapping:
+ sampleCoords = "vec2(atan(-";
+ sampleCoords += fsCoordName;
+ sampleCoords += ".y, -";
+ sampleCoords += fsCoordName;
+ sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
+ break;
+ case StageDesc::kRadialGradient_CoordMapping:
+ sampleCoords = "vec2(length(";
+ sampleCoords += fsCoordName;
+ sampleCoords += ".xy), 0.5)";
+ break;
+ case StageDesc::kRadial2Gradient_CoordMapping: {
+ GrTokenString cName = "c";
+ GrTokenString ac4Name = "ac4";
+ GrTokenString rootName = "root";
+
+ cName.appendInt(stageNum);
+ ac4Name.appendInt(stageNum);
+ rootName.appendInt(stageNum);
+
+ GrTokenString bVar;
+ if (coordDims == varyingDims) {
+ bVar = radial2VaryingName;
+ GrAssert(2 == varyingDims);
+ } else {
+ GrAssert(3 == varyingDims);
+ bVar = "b";
+ bVar.appendInt(stageNum);
+ segments->fFSCode += "\tfloat ";
+ segments->fFSCode += bVar;
+ segments->fFSCode += " = 2.0 * (";
+ segments->fFSCode += radial2ParamsName;
+ segments->fFSCode += "[2] * ";
+ segments->fFSCode += fsCoordName;
+ segments->fFSCode += ".x ";
+ segments->fFSCode += " - ";
+ segments->fFSCode += radial2ParamsName;
+ segments->fFSCode += "[3]);\n";
+ }
+
+ segments->fFSCode += "\tfloat ";
+ segments->fFSCode += cName;
+ segments->fFSCode += " = dot(";
+ segments->fFSCode += fsCoordName;
+ segments->fFSCode += ", ";
+ segments->fFSCode += fsCoordName;
+ segments->fFSCode += ") + ";
+ segments->fFSCode += " - ";
+ segments->fFSCode += radial2ParamsName;
+ segments->fFSCode += "[4];\n";
+
+ segments->fFSCode += "\tfloat ";
+ segments->fFSCode += ac4Name;
+ segments->fFSCode += " = ";
+ segments->fFSCode += radial2ParamsName;
+ segments->fFSCode += "[0] * 4.0 * ";
+ segments->fFSCode += cName;
+ segments->fFSCode += ";\n";
+
+ segments->fFSCode += "\tfloat ";
+ segments->fFSCode += rootName;
+ segments->fFSCode += " = sqrt(abs(";
+ segments->fFSCode += bVar;
+ segments->fFSCode += " * ";
+ segments->fFSCode += bVar;
+ segments->fFSCode += " - ";
+ segments->fFSCode += ac4Name;
+ segments->fFSCode += "));\n";
+
+ sampleCoords = "vec2((-";
+ sampleCoords += bVar;
+ sampleCoords += " + ";
+ sampleCoords += radial2ParamsName;
+ sampleCoords += "[5] * ";
+ sampleCoords += rootName;
+ sampleCoords += ") * ";
+ sampleCoords += radial2ParamsName;
+ sampleCoords += "[1], 0.5)\n";
+ break;}
+ };
+
+ segments->fFSCode += "\t";
+ segments->fFSCode += fsOutColor;
+ segments->fFSCode += " = ";
+ if (NULL != fsInColor) {
+ segments->fFSCode += fsInColor;
+ segments->fFSCode += " * ";
+ }
+ segments->fFSCode += texFunc;
+ segments->fFSCode += "(";
+ segments->fFSCode += samplerName;
+ segments->fFSCode += ", ";
+ segments->fFSCode += sampleCoords;
+ segments->fFSCode += ")";
+ if (desc.fModulation == StageDesc::kAlpha_Modulation) {
+ segments->fFSCode += ".aaaa";
+ }
+ segments->fFSCode += ";\n";
+
+}
+
+void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
+ Program* program) {
+
+ ShaderCodeSegments segments;
+ const uint32_t& layout = desc.fVertexLayout;
+
+ memset(&program->fUniLocations, 0, sizeof(UniLocations));
+
+ bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
+ desc.fOptFlags);
+
+#if ATTRIBUTE_MATRIX
+ segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"
+#else
+ segments.fVSUnis = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
+ segments.fVSAttrs = "";
+#endif
+ segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
+ if (haveColor) {
+ segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
+ segments.fVaryings = "varying vec4 vColor;\n";
+ } else {
+ segments.fVaryings = "";
+ }
+
+ segments.fVSCode = "void main() {\n"
+ "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
+ "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
+ if (haveColor) {
+ segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
+ }
+
+ if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
+ segments.fVSCode += "\tgl_PointSize = 1.0;\n";
+ }
+ segments.fFSCode = "void main() {\n";
+
+ bool textureCoordAttr = false;
+ static const char* IN_COORDS[] = {POS_ATTR_NAME, TEX_ATTR_NAME};
+ const char* inCoords = NULL;
+ if ((kSeparateTexCoord_VertexLayoutBit | kTextFormat_VertexLayoutBit) &
+ layout) {
+ segments.fVSAttrs += "attribute vec2 " TEX_ATTR_NAME ";\n";
+ inCoords = IN_COORDS[1];
+ textureCoordAttr = true;
+ } else if (kPositionAsTexCoord_VertexLayoutBit & layout) {
+ inCoords = IN_COORDS[0];
+ }
+
+ GrTokenString inColor = "vColor";
+ GR_STATIC_ASSERT(NUM_STAGES <= 9);
+ int numActiveStages = 0;
+ for (int i = 0; i < NUM_STAGES; ++i) {
+ if (desc.fStages[i].fEnabled) {
+ ++numActiveStages;
+ }
+ }
+ if (NULL != inCoords && numActiveStages) {
+ int currActiveStage = 0;
+ for (int i = 0; i < NUM_STAGES; ++i) {
+ if (desc.fStages[i].fEnabled) {
+ GrTokenString outColor;
+ if (currActiveStage < (numActiveStages - 1)) {
+ outColor = "color";
+ outColor.appendInt(currActiveStage);
+ segments.fFSCode += "\tvec4 ";
+ segments.fFSCode += outColor;
+ segments.fFSCode += ";\n";
+ } else {
+ outColor = "gl_FragColor";
+ }
+ GenStageCode(i,
+ desc.fStages[i],
+ haveColor ? inColor.cstr() : NULL,
+ outColor.cstr(),
+ inCoords,
+ &segments,
+ &program->fUniLocations.fStages[i]);
+ ++currActiveStage;
+ inColor = outColor;
+ haveColor = true;
+ }
+ }
+ } else {
+ segments.fFSCode += "\tgl_FragColor = ";
+ if (haveColor) {
+ segments.fFSCode += inColor;
+ } else {
+ segments.fFSCode += "vec4(1,1,1,1)";
+ }
+ segments.fFSCode += ";\n";
+ }
+ segments.fFSCode += "}\n";
+ segments.fVSCode += "}\n";
+
+
+ const char* strings[4];
+ int lengths[4];
+ int stringCnt = 0;
+
+ if (segments.fVSUnis.length()) {
+ strings[stringCnt] = segments.fVSUnis.cstr();
+ lengths[stringCnt] = segments.fVSUnis.length();
+ ++stringCnt;
+ }
+ if (segments.fVSAttrs.length()) {
+ strings[stringCnt] = segments.fVSAttrs.cstr();
+ lengths[stringCnt] = segments.fVSAttrs.length();
+ ++stringCnt;
+ }
+ if (segments.fVaryings.length()) {
+ strings[stringCnt] = segments.fVaryings.cstr();
+ lengths[stringCnt] = segments.fVaryings.length();
+ ++stringCnt;
+ }
+
+ GrAssert(segments.fVSCode.length());
+ strings[stringCnt] = segments.fVSCode.cstr();
+ lengths[stringCnt] = segments.fVSCode.length();
+ ++stringCnt;
+
+#if PRINT_SHADERS
+ GrPrintf("%s%s%s%s\n",
+ segments.fVSUnis.cstr(),
+ segments.fVSAttrs.cstr(),
+ segments.fVaryings.cstr(),
+ segments.fVSCode.cstr());
+#endif
+ program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
+ stringCnt,
+ strings,
+ lengths);
+
+ stringCnt = 0;
+
+ if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
+ strings[stringCnt] = GR_SHADER_PRECISION;
+ lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
+ ++stringCnt;
+ }
+ if (segments.fFSUnis.length()) {
+ strings[stringCnt] = segments.fFSUnis.cstr();
+ lengths[stringCnt] = segments.fFSUnis.length();
+ ++stringCnt;
+ }
+ if (segments.fVaryings.length()) {
+ strings[stringCnt] = segments.fVaryings.cstr();
+ lengths[stringCnt] = segments.fVaryings.length();
+ ++stringCnt;
+ }
+
+ GrAssert(segments.fFSCode.length());
+ strings[stringCnt] = segments.fFSCode.cstr();
+ lengths[stringCnt] = segments.fFSCode.length();
+ ++stringCnt;
+
+#if PRINT_SHADERS
+ GrPrintf("%s%s%s%s\n",
+ GR_SHADER_PRECISION,
+ segments.fFSUnis.cstr(),
+ segments.fVaryings.cstr(),
+ segments.fFSCode.cstr());
+#endif
+ program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
+ stringCnt,
+ strings,
+ lengths);
+
+ program->fProgramID = GR_GL(CreateProgram());
+ const GLint& progID = program->fProgramID;
+
+ GR_GL(AttachShader(progID, program->fVShaderID));
+ GR_GL(AttachShader(progID, program->fFShaderID));
+
+ // Bind the attrib locations to same values for all shaders
+ GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
+ if (textureCoordAttr) {
+ GR_GL(BindAttribLocation(progID, TEX_ATTR_LOCATION, TEX_ATTR_NAME));
+ }
+
+#if ATTRIBUTE_MATRIX
+ // set unis to a bogus value so that checks against -1 before
+ // flushing will pass.
+ GR_GL(BindAttribLocation(progID,
+ VIEWMAT_ATTR_LOCATION,
+ VIEW_MATRIX_NAME));
+
+ program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
+
+ for (int i = 0; i < NUM_STAGES; ++i) {
+ if (desc.fStages[i].fEnabled) {
+ GR_GL(BindAttribLocation(progID,
+ TEXMAT_ATTR_LOCATION(i),
+ tex_matrix_name(i).cstr()));
+ program->fUniLocations.fStages[i].fTextureMatrixUni =
+ BOGUS_MATRIX_UNI_LOCATION;
+ }
+ }
+#endif
+
+ GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
+
+ GR_GL(LinkProgram(progID));
+
+ GLint linked;
+ GR_GL(GetProgramiv(progID, GL_LINK_STATUS, &linked));
+ if (!linked) {
+ GLint infoLen;
+ GR_GL(GetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen));
+ GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+ if (infoLen > 0) {
+ GR_GL(GetProgramInfoLog(progID,
+ infoLen+1,
+ NULL,
+ (char*)log.get()));
+ GrPrintf((char*)log.get());
+ }
+ GrAssert(!"Error linking program");
+ GR_GL(DeleteProgram(progID));
+ program->fProgramID = 0;
+ return;
+ }
+
+ // Get uniform locations
+#if !ATTRIBUTE_MATRIX
+ program->fUniLocations.fViewMatrixUni =
+ GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
+ GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
+#endif
+ for (int i = 0; i < NUM_STAGES; ++i) {
+ StageUniLocations& locations = program->fUniLocations.fStages[i];
+ if (desc.fStages[i].fEnabled) {
+#if !ATTRIBUTE_MATRIX
+ if (locations.fTextureMatrixUni) {
+ GrTokenString texMName;
+ tex_matrix_name(i, &texMName);
+ locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
+ progID,
+ texMName.cstr()));
+ GrAssert(-1 != locations.fTextureMatrixUni);
+ } else {
+ locations.fTextureMatrixUni = -1;
+
+ }
+#endif
+
+ if (locations.fSamplerUni) {
+ GrTokenString samplerName;
+ sampler_name(i, &samplerName);
+ locations.fSamplerUni = GR_GL(GetUniformLocation(
+ progID,
+ samplerName.cstr()));
+ GrAssert(-1 != locations.fSamplerUni);
+ } else {
+ locations.fSamplerUni = -1;
+ }
+
+ if (locations.fRadial2Uni) {
+ GrTokenString radial2ParamName;
+ radial2_param_name(i, &radial2ParamName);
+ locations.fRadial2Uni = GR_GL(GetUniformLocation(
+ progID,
+ radial2ParamName.cstr()));
+ GrAssert(-1 != locations.fRadial2Uni);
+ } else {
+ locations.fRadial2Uni = -1;
+ }
+ } else {
+ locations.fSamplerUni = -1;
+ locations.fRadial2Uni = -1;
+ locations.fTextureMatrixUni = -1;
+ }
+ }
+ GR_GL(UseProgram(progID));
+
+ // init sampler unis and set bogus values for state tracking
+ for (int i = 0; i < NUM_STAGES; ++i) {
+ if (-1 != program->fUniLocations.fStages[i].fSamplerUni) {
+ GR_GL(Uniform1i(program->fUniLocations.fStages[i].fSamplerUni, i));
+ }
+ program->fTextureMatrix[i].setScale(GR_ScalarMax, GR_ScalarMax);
+ program->fRadial2CenterX1[i] = GR_ScalarMax;
+ program->fRadial2Radius0[i] = -GR_ScalarMax;
+ }
+ program->fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
+}
+
+void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
+
+ // Must initialize all fields or cache will have false negatives!
+ desc->fVertexLayout = fGeometrySrc.fVertexLayout;
+ desc->fStages[0].fEnabled = VertexHasTexCoords(fGeometrySrc.fVertexLayout);
+ for (int i = 1; i < NUM_STAGES; ++i) {
+ desc->fStages[i].fEnabled = false;
+ desc->fStages[i].fOptFlags = 0;
+ desc->fStages[i].fCoordMapping = 0;
+ desc->fStages[i].fModulation = 0;
+ }
+
+ if (primType != kPoints_PrimitiveType) {
+ desc->fOptFlags = ProgramDesc::kNotPoints_OptFlagBit;
+ } else {
+ desc->fOptFlags = 0;
+ }
+#if SKIP_COLOR_MODULATE_OPT
+ if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
+ (0xffffffff == fCurrDrawState.fColor)) {
+ desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
+ }
+#endif
+
+ StageDesc& stage = desc->fStages[0];
+
+ if (stage.fEnabled) {
+ GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTexture;
+ GrAssert(NULL != texture);
+ // we matrix to invert when orientation is TopDown, so make sure
+ // we aren't in that case before flagging as identity.
+ if (fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].isIdentity() &&
+ GrGLTexture::kTopDown_Orientation == texture->orientation()) {
+ stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
+ } else if (!fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective()) {
+ stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
+ } else {
+ stage.fOptFlags = 0;
+ }
+ switch (fCurrDrawState.fSamplerState.getSampleMode()) {
+ case GrSamplerState::kNormal_SampleMode:
+ stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
+ stage.fModulation = StageDesc::kColor_Modulation;
+ break;
+ case GrSamplerState::kAlphaMod_SampleMode:
+ stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
+ stage.fModulation = StageDesc::kAlpha_Modulation;
+ break;
+ case GrSamplerState::kRadial_SampleMode:
+ stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
+ stage.fModulation = StageDesc::kColor_Modulation;
+ break;
+ case GrSamplerState::kRadial2_SampleMode:
+ stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
+ stage.fModulation = StageDesc::kColor_Modulation;
+ break;
+ case GrSamplerState::kSweep_SampleMode:
+ stage.fCoordMapping = StageDesc::StageDesc::kSweepGradient_CoordMapping;
+ stage.fModulation = StageDesc::kColor_Modulation;
+ break;
+ default:
+ GrAssert(!"Unexpected sample mode!");
+ break;
+ }
+ } else {
+ stage.fOptFlags = 0;
+ stage.fCoordMapping = 0;
+ stage.fModulation = 0;
+ }
+}
+
+GLuint GrGpuGLShaders2::CompileShader(GLenum type,
+ int stringCnt,
+ const char** strings,
+ int* stringLengths) {
+ GLuint shader = GR_GL(CreateShader(type));
+ if (0 == shader) {
+ return 0;
+ }
+
+ GLint compiled;
+ GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
+ GR_GL(CompileShader(shader));
+ GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
+
+ if (!compiled) {
+ GLint infoLen;
+ GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
+ GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+ if (infoLen > 0) {
+ GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
+ for (int i = 0; i < stringCnt; ++i) {
+ if (NULL == stringLengths || stringLengths[i] < 0) {
+ GrPrintf(strings[i]);
+ } else {
+ GrPrintf("%.*s", stringLengths[i], strings[i]);
+ }
+ }
+ GrPrintf("\n%s", log.get());
+ }
+ GrAssert(!"Shader compilation failed!");
+ GR_GL(DeleteShader(shader));
+ return 0;
+ }
+ return shader;
+}
+
+void GrGpuGLShaders2::DeleteProgram(Program* program) {
+ GR_GL(DeleteShader(program->fVShaderID));
+ GR_GL(DeleteShader(program->fFShaderID));
+ GR_GL(DeleteProgram(program->fProgramID));
+ GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
+}
+
+
+GrGpuGLShaders2::GrGpuGLShaders2() {
+
+ resetContextHelper();
+
+ fProgram = NULL;
+ fProgramCache = new ProgramCache();
+
+#if GR_DEBUG
+ ProgramUnitTest();
+#endif
+}
+
+GrGpuGLShaders2::~GrGpuGLShaders2() {
+ delete fProgramCache;
+}
+
+void GrGpuGLShaders2::resetContext() {
+ INHERITED::resetContext();
+ resetContextHelper();
+}
+
+void GrGpuGLShaders2::resetContextHelper() {
+ fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
+
+ fHWGeometryState.fVertexLayout = 0;
+ fHWGeometryState.fPositionPtr = (void*) ~0;
+ GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
+ GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION));
+ GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
+
+ fHWProgramID = 0;
+}
+
+void GrGpuGLShaders2::flushViewMatrix() {
+ GrAssert(NULL != fCurrDrawState.fRenderTarget);
+ GrMatrix m (
+ GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
+ 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
+ 0, 0, GrMatrix::I()[8]);
+ m.setConcat(m, fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode]);
+
+ // ES doesn't allow you to pass true to the transpose param,
+ // so do our own transpose
+ GrScalar mt[] = {
+ m[GrMatrix::kScaleX],
+ m[GrMatrix::kSkewY],
+ m[GrMatrix::kPersp0],
+ m[GrMatrix::kSkewX],
+ m[GrMatrix::kScaleY],
+ m[GrMatrix::kPersp1],
+ m[GrMatrix::kTransX],
+ m[GrMatrix::kTransY],
+ m[GrMatrix::kPersp2]
+ };
+#if ATTRIBUTE_MATRIX
+ glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0);
+ glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3);
+ glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6);
+#else
+ GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
+#endif
+}
+
+void GrGpuGLShaders2::flushTextureMatrix() {
+
+ GrAssert(NULL != fCurrDrawState.fTexture);
+ GrGLTexture::Orientation orientation =
+ ((GrGLTexture*)fCurrDrawState.fTexture)->orientation();
+
+ GrMatrix* m;
+ GrMatrix temp;
+ if (GrGLTexture::kBottomUp_Orientation == orientation) {
+ temp.setAll(
+ GR_Scalar1, 0, 0,
+ 0, -GR_Scalar1, GR_Scalar1,
+ 0, 0, GrMatrix::I()[8]
+ );
+ temp.preConcat(fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode]);
+ m = &temp;
+ } else {
+ GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
+ m = &fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode];
+ }
+
+ // ES doesn't allow you to pass true to the transpose param,
+ // so do our own transpose
+ GrScalar mt[] = {
+ (*m)[GrMatrix::kScaleX],
+ (*m)[GrMatrix::kSkewY],
+ (*m)[GrMatrix::kPersp0],
+ (*m)[GrMatrix::kSkewX],
+ (*m)[GrMatrix::kScaleY],
+ (*m)[GrMatrix::kPersp1],
+ (*m)[GrMatrix::kTransX],
+ (*m)[GrMatrix::kTransY],
+ (*m)[GrMatrix::kPersp2]
+ };
+#if ATTRIBUTE_MATRIX
+ glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0);
+ glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3);
+ glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6);
+#else
+ GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[0].fTextureMatrixUni,
+ 1,
+ false,
+ mt));
+#endif
+}
+
+void GrGpuGLShaders2::flushRadial2() {
+
+ const GrSamplerState& sampler = fCurrDrawState.fSamplerState;
+
+ GrScalar centerX1 = sampler.getRadial2CenterX1();
+ GrScalar radius0 = sampler.getRadial2Radius0();
+
+ GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
+
+ float unis[6] = {
+ GrScalarToFloat(a),
+ 1 / (2.f * unis[0]),
+ GrScalarToFloat(centerX1),
+ GrScalarToFloat(radius0),
+ GrScalarToFloat(GrMul(radius0, radius0)),
+ sampler.isRadial2PosRoot() ? 1.f : -1.f
+ };
+ GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[0].fRadial2Uni, 6, unis));
+}
+
+void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
+ ProgramDesc desc;
+ getProgramDesc(type, &desc);
+ fProgram = fProgramCache->getProgram(desc);
+
+ if (fHWProgramID != fProgram->fProgramID) {
+ GR_GL(UseProgram(fProgram->fProgramID));
+ fHWProgramID = fProgram->fProgramID;
+#if GR_COLLECT_STATS
+ ++fStats.fProgChngCnt;
+#endif
+ }
+}
+
+bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
+
+ flushGLStateCommon(type);
+
+ if (fRenderTargetChanged) {
+ // our coords are in pixel space and the GL matrices map to NDC
+ // so if the viewport changed, our matrix is now wrong.
+#if ATTRIBUTE_MATRIX
+ fHWDrawState.fMatrixModeCache[kModelView_MatrixMode].setScale(GR_ScalarMax,
+ GR_ScalarMax);
+#else
+ // we assume all shader matrices may be wrong after viewport changes
+ fProgramCache->invalidateViewMatrices();
+#endif
+ fRenderTargetChanged = false;
+ }
+
+ flushProgram(type);
+
+ if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
+ // invalidate the immediate mode color
+ fHWDrawState.fColor = GrColor_ILLEGAL;
+ } else {
+ if (fHWDrawState.fColor != fCurrDrawState.fColor) {
+ // OpenGL ES only supports the float varities of glVertexAttrib
+ float c[] = {
+ GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
+ GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
+ GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
+ GrColorUnpackA(fCurrDrawState.fColor) / 255.f
+ };
+ GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
+ fHWDrawState.fColor = fCurrDrawState.fColor;
+ }
+ }
+
+#if ATTRIBUTE_MATRIX
+ GrMatrix& currViewMatrix = fHWDrawState.fMatrixModeCache[kModelView_MatrixMode];
+ GrMatrix& currTextureMatrix = fHWDrawState.fMatrixModeCache[kTexture_MatrixMode];
+ GrGLTexture::Orientation& orientation = fTextureOrientation;
+#else
+ GrMatrix& currViewMatrix = fProgram->fViewMatrix;
+ GrMatrix& currTextureMatrix = fProgram->fTextureMatrix[0];
+ GrGLTexture::Orientation& orientation = fProgram->fTextureOrientation[0];
+#endif
+
+ if (currViewMatrix != fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode]) {
+ flushViewMatrix();
+ currViewMatrix = fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode];
+ }
+
+ GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTexture;
+ if (NULL != texture) {
+ if (-1 != fProgram->fUniLocations.fStages[0].fTextureMatrixUni &&
+ (currTextureMatrix !=
+ fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode] ||
+ orientation != texture->orientation())) {
+ flushTextureMatrix();
+ currTextureMatrix = fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode];
+ orientation = texture->orientation();
+ }
+ }
+
+ const GrSamplerState& sampler = fCurrDrawState.fSamplerState;
+ if (-1 != fProgram->fUniLocations.fStages[0].fRadial2Uni &&
+ (fProgram->fRadial2CenterX1[0] != sampler.getRadial2CenterX1() ||
+ fProgram->fRadial2Radius0[0] != sampler.getRadial2Radius0() ||
+ fProgram->fRadial2PosRoot[0] != sampler.isRadial2PosRoot())) {
+
+ flushRadial2();
+
+ fProgram->fRadial2CenterX1[0] = sampler.getRadial2CenterX1();
+ fProgram->fRadial2Radius0[0] = sampler.getRadial2Radius0();
+ fProgram->fRadial2PosRoot[0] = sampler.isRadial2PosRoot();
+ }
+
+ return true;
+}
+
+void GrGpuGLShaders2::setupGeometry(uint32_t startVertex,
+ uint32_t startIndex,
+ uint32_t vertexCount,
+ uint32_t indexCount) {
+
+ int newColorOffset, newTexCoordOffset;
+
+ GLsizei newStride = VertexSizeAndOffsets(fGeometrySrc.fVertexLayout,
+ &newTexCoordOffset,
+ &newColorOffset);
+ int oldColorOffset, oldTexCoordOffset;
+ GLsizei oldStride = VertexSizeAndOffsets(fHWGeometryState.fVertexLayout,
+ &oldTexCoordOffset,
+ &oldColorOffset);
+
+ const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
+
+ if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+ GrAssert(NULL != fGeometrySrc.fVertexBuffer);
+ GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
+ if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
+ GrGLVertexBuffer* buf =
+ (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
+ GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
+ fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+ }
+ } else {
+ if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+ posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
+ (intptr_t)posPtr);
+ } else {
+ GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
+ posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
+ }
+ if (NULL != fHWGeometryState.fVertexBuffer) {
+ GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
+ fHWGeometryState.fVertexBuffer = NULL;
+ }
+ }
+
+ if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+ GrAssert(NULL != fGeometrySrc.fIndexBuffer);
+ GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
+ if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
+ GrGLIndexBuffer* buf =
+ (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+ GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
+ fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+ }
+ } else if (NULL != fHWGeometryState.fIndexBuffer) {
+ GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+ fHWGeometryState.fIndexBuffer = NULL;
+ }
+
+ GLenum scalarType;
+ bool texCoordNorm;
+ if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
+ scalarType = GrGLTextType;
+ texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
+ } else {
+ scalarType = GrGLType;
+ texCoordNorm = false;
+ }
+
+ bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
+ bool scalarChange = (GrGLTextType != GrGLType) &&
+ (kTextFormat_VertexLayoutBit &
+ (fHWGeometryState.fVertexLayout ^
+ fGeometrySrc.fVertexLayout));
+ bool strideChange = newStride != oldStride;
+ bool posChange = baseChange || scalarChange || strideChange;
+
+ if (posChange) {
+ GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
+ false, newStride, posPtr));
+ fHWGeometryState.fPositionPtr = posPtr;
+ }
+
+ if (newTexCoordOffset > 0) {
+ GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffset;
+ if (oldTexCoordOffset <= 0) {
+ GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION));
+ }
+ if (posChange || newTexCoordOffset != oldTexCoordOffset) {
+ GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION, 2, scalarType,
+ texCoordNorm, newStride, texCoordPtr));
+ }
+ } else if (oldTexCoordOffset > 0) {
+ GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION));
+ }
+
+ if (newColorOffset > 0) {
+ GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+ if (oldColorOffset <= 0) {
+ GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
+ }
+ if (posChange || newColorOffset != oldColorOffset) {
+ GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
+ GL_UNSIGNED_BYTE,
+ true, newStride, colorPtr));
+ }
+ } else if (oldColorOffset > 0) {
+ GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
+ }
+
+ fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+}
+#endif
+