diff options
author | 2010-12-22 21:39:39 +0000 | |
---|---|---|
committer | 2010-12-22 21:39:39 +0000 | |
commit | ac10a2d039c5d52eed66e27cbbc503ab523c1cd5 (patch) | |
tree | c5be0c3dd15052016e7d32f376507cb1ea7101dd /gpu/src/GrGpuGLShaders2.cpp | |
parent | ea8509cd3b1771b36054313d3ccd56679df56044 (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.cpp | 1388 |
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 + |