Refactoring the GrGpuGLShaders2 into 2 classes: GrGpuGLShaders
and GrGLProgram. The change also contains stubs and placeholders for GrEffect (work in progress), which will extend shader and rendering capabilities in Ganesh. The hash keys for the program cache table have been modified to be able to accomodate variable-length keys, which will be required for GrEffect support. Code review: http://codereview.appspot.com/4309045/ git-svn-id: http://skia.googlecode.com/svn/trunk@1031 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
772813afa6
commit
f93e717c7f
@ -328,6 +328,10 @@ inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); }
|
||||
#define GR_DUMP_TEXTURE_UPLOAD 0
|
||||
#endif
|
||||
|
||||
#ifndef GR_USE_NEW_GLSHADERS
|
||||
#define GR_USE_NEW_GLSHADERS 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GR_COLLECT_STATS controls whether the GrGpu class collects stats.
|
||||
* If not already defined then collect in debug build but not release.
|
||||
|
@ -30,6 +30,7 @@ class GrTexture;
|
||||
class GrClipIterator;
|
||||
class GrVertexBuffer;
|
||||
class GrIndexBuffer;
|
||||
class GrEffect;
|
||||
|
||||
class GrDrawTarget : public GrRefCnt {
|
||||
public:
|
||||
@ -138,6 +139,7 @@ protected:
|
||||
GrBlendCoeff fDstBlend;
|
||||
GrColor fBlendConstant;
|
||||
GrTexture* fTextures[kNumStages];
|
||||
GrEffect* fEffects[kNumStages];
|
||||
GrSamplerState fSamplerStates[kNumStages];
|
||||
GrRenderTarget* fRenderTarget;
|
||||
GrColor fColor;
|
||||
|
221
gpu/src/GrBinHashKey.h
Normal file
221
gpu/src/GrBinHashKey.h
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef GrBinHashKey_DEFINED
|
||||
#define GrBinHashKey_DEFINED
|
||||
|
||||
#include "GrTypes.h"
|
||||
|
||||
/**
|
||||
* Abstract base class that presents the building interface of GrBinHashKey.
|
||||
* This base class allows builder methods to not know the exact template
|
||||
* parameters of GrBinHashKey
|
||||
*/
|
||||
class GrBinHashKeyBuilder {
|
||||
public:
|
||||
GrBinHashKeyBuilder() {}
|
||||
virtual ~GrBinHashKeyBuilder() {}
|
||||
virtual void keyData(const uint8_t *dataToAdd, size_t len) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash function class than can take a data stream of indeterminate length.
|
||||
* It also has the ability to recieve data in several chunks (steamed). The
|
||||
* hash function used is Adler-32.
|
||||
*
|
||||
* Keys are built in two passes the first pass builds the key until the
|
||||
* allocated storage for the key runs out, raw data accumulation stops, but
|
||||
* the calculation of the 32-bit hash value and total key length continue.
|
||||
* The second pass is only necessary if storage ran-out during the first pass.
|
||||
* If that is the case, the heap storage portion of the key will be
|
||||
* re-allocated so that the entire key can be stored in the second pass.
|
||||
*
|
||||
* Code for building a key:
|
||||
*
|
||||
* GrBinHashKey<MyEntryStruct, MyStackSize> MyKey;
|
||||
* while( MyKey->doPass() )
|
||||
* {
|
||||
* MyObject->buildKey(&MyKey); //invoke a builder method
|
||||
* }
|
||||
*
|
||||
* All the builder method needs to do is make calls to the keyData method to
|
||||
* append binary data to the key.
|
||||
*/
|
||||
template<typename Entry, size_t StackSize>
|
||||
class GrBinHashKey : public GrBinHashKeyBuilder {
|
||||
public:
|
||||
GrBinHashKey()
|
||||
: fA(1)
|
||||
, fB(0)
|
||||
, fLength(0)
|
||||
, fHeapData(NULL)
|
||||
, fPhysicalSize(StackSize)
|
||||
, fUseHeap(false)
|
||||
, fPass(0)
|
||||
#if GR_DEBUG
|
||||
, fIsValid(true)
|
||||
#endif
|
||||
{}
|
||||
|
||||
private:
|
||||
// Illegal: must choose explicitly between copyAndTakeOwnership
|
||||
// and deepCopyFrom.
|
||||
// Not inheriting GrNoncopyable, because it causes very obscure compiler
|
||||
// errors with template classes, which are hard to trace back to the use
|
||||
// of assignment.
|
||||
GrBinHashKey(const GrBinHashKey<Entry, StackSize>&) {}
|
||||
GrBinHashKey<Entry, StackSize>& operator=(const GrBinHashKey<Entry,
|
||||
StackSize>&) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public:
|
||||
void copyAndTakeOwnership(GrBinHashKey<Entry, StackSize>& key) {
|
||||
memcpy(this, &key, sizeof(*this));
|
||||
GrAssert(key.fIsValid);
|
||||
if (fUseHeap) {
|
||||
key.fHeapData = NULL; // ownership transfer
|
||||
}
|
||||
// Consistency Checking
|
||||
// To avoid the overhead of copying or ref-counting the dynamically
|
||||
// allocated portion of the key, we use ownership transfer
|
||||
// Key usability is only tracked in debug builds.
|
||||
GR_DEBUGCODE(key.fIsValid = false;)
|
||||
}
|
||||
|
||||
void deepCopyFrom(const GrBinHashKey<Entry, StackSize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
memcpy(this, &key, sizeof(key));
|
||||
if (fUseHeap) {
|
||||
fHeapData = reinterpret_cast<uint8_t*>(
|
||||
GrMalloc(sizeof(uint8_t) * fPhysicalSize));
|
||||
memcpy(fHeapData, key.fHeapData, fLength);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~GrBinHashKey() {
|
||||
if (fUseHeap) {
|
||||
GrFree(fHeapData);
|
||||
}
|
||||
}
|
||||
|
||||
bool doPass() {
|
||||
GrAssert(fIsValid);
|
||||
if (0 == fPass) {
|
||||
fPass++;
|
||||
return true;
|
||||
}
|
||||
if (1 == fPass) {
|
||||
bool passNeeded = false;
|
||||
if (fLength > fPhysicalSize) {
|
||||
// If the first pass ran out of space the we need to
|
||||
// re-allocate and perform a second pass
|
||||
GrFree(fHeapData);
|
||||
fHeapData = reinterpret_cast<uint8_t*>(
|
||||
GrMalloc(sizeof(uint8_t) * fLength));
|
||||
fPhysicalSize = fLength;
|
||||
fUseHeap = true;
|
||||
passNeeded = true;
|
||||
fLength = 0;
|
||||
}
|
||||
fPass++;
|
||||
return passNeeded;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void keyData(const uint8_t *dataToAdd, size_t len) {
|
||||
GrAssert(fIsValid);
|
||||
GrAssert(fPass);
|
||||
if (fUseHeap) {
|
||||
GrAssert(fHeapData);
|
||||
GrAssert(fLength + len <= fPhysicalSize);
|
||||
memcpy(&fHeapData[fLength], dataToAdd, len );
|
||||
} else {
|
||||
if (fLength + len <= StackSize) {
|
||||
memcpy(&fStackData[fLength], dataToAdd, len);
|
||||
} else {
|
||||
GrAssert(1 == fPass);
|
||||
}
|
||||
}
|
||||
|
||||
fLength += len;
|
||||
|
||||
if (1 == fPass) {
|
||||
// update the 32-bit hash
|
||||
while (len) {
|
||||
fA = (fA + *dataToAdd) % kBigPrime;
|
||||
fB = (fB + fA) % kBigPrime;
|
||||
dataToAdd++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int compare(const GrBinHashKey<Entry, StackSize>& key) const {
|
||||
GrAssert(fIsValid);
|
||||
if (fLength == key.fLength) {
|
||||
GrAssert(fUseHeap == key.fUseHeap);
|
||||
if(fUseHeap) {
|
||||
return memcmp(fHeapData, key.fHeapData, fLength);
|
||||
} else {
|
||||
return memcmp(fStackData, key.fStackData, fLength);
|
||||
}
|
||||
}
|
||||
|
||||
return (fLength - key.fLength);
|
||||
}
|
||||
|
||||
static bool
|
||||
EQ(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return 0 == entry.compare(key);
|
||||
}
|
||||
|
||||
static bool
|
||||
LT(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return entry.compare(key) < 0;
|
||||
}
|
||||
|
||||
uint32_t getHash() const {
|
||||
GrAssert(fIsValid);
|
||||
return (fB << 16) | fA;
|
||||
}
|
||||
|
||||
private:
|
||||
// For computing the Adler-32 hash
|
||||
enum Constants {
|
||||
kBigPrime = 65521 // largest prime smaller than 2^16
|
||||
};
|
||||
uint32_t fA;
|
||||
uint32_t fB;
|
||||
|
||||
// For accumulating the variable length binary key
|
||||
size_t fLength; // length of data accumulated so far
|
||||
uint8_t fStackData[StackSize]; //Buffer for key storage
|
||||
uint8_t* fHeapData; //Dynamically allocated extended key storage
|
||||
size_t fPhysicalSize; //Total size available for key storage
|
||||
bool fUseHeap; //Using a dynamically allocated key storage
|
||||
int fPass; //Key generation pass counter
|
||||
|
||||
#if GR_DEBUG
|
||||
public:
|
||||
bool fIsValid;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
52
gpu/src/GrGLEffect.h
Normal file
52
gpu/src/GrGLEffect.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef GrGLEffect_DEFINED
|
||||
#define GrGLEffect_DEFINED
|
||||
|
||||
#include "GrGLInterface.h"
|
||||
#include "GrStringBuilder.h"
|
||||
|
||||
class GrEffect;
|
||||
|
||||
struct ShaderCodeSegments {
|
||||
GrSStringBuilder<256> fVSUnis;
|
||||
GrSStringBuilder<256> fVSAttrs;
|
||||
GrSStringBuilder<256> fVaryings;
|
||||
GrSStringBuilder<256> fFSUnis;
|
||||
GrSStringBuilder<512> fVSCode;
|
||||
GrSStringBuilder<512> fFSCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is currently a stub. This will be a base class for "effects",
|
||||
* which extend the data model of GrPaint and extend the capability of
|
||||
* GrGLProgram in a modular fashion.
|
||||
*/
|
||||
class GrGLEffect {
|
||||
protected:
|
||||
GrGLEffect(GrEffect* effect) {}
|
||||
public:
|
||||
virtual ~GrGLEffect() {}
|
||||
static GrGLEffect* Create(GrEffect* effect) { return NULL; }
|
||||
void genShaderCode(ShaderCodeSegments* segments) {}
|
||||
bool doGLSetup(GrPrimitiveType type, GrGLint program) { return true; }
|
||||
bool doGLPost() { return true; }
|
||||
void buildKey(GrBinHashKeyBuilder& key) const {}
|
||||
GrGLEffect* nextEffect() { return NULL; }
|
||||
};
|
||||
|
||||
#endif
|
784
gpu/src/GrGLProgram.cpp
Normal file
784
gpu/src/GrGLProgram.cpp
Normal file
@ -0,0 +1,784 @@
|
||||
/*
|
||||
Copyright 2011 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 "GrGLProgram.h"
|
||||
|
||||
#include "GrBinHashKey.h"
|
||||
#include "GrGLConfig.h"
|
||||
#include "GrGLEffect.h"
|
||||
#include "GrMemory.h"
|
||||
#include "GrStringBuilder.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char* GrPrecision() {
|
||||
if (GR_GL_SUPPORT_ES2) {
|
||||
return "mediump";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char* GrShaderPrecision() {
|
||||
if (GR_GL_SUPPORT_ES2) {
|
||||
return "precision mediump float;\n";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#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"
|
||||
|
||||
// for variable names etc
|
||||
typedef GrSStringBuilder<16> GrTokenString;
|
||||
|
||||
static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
|
||||
*s = "aTexCoord";
|
||||
s->appendInt(coordIdx);
|
||||
}
|
||||
|
||||
static inline const char* float_vector_type(int count) {
|
||||
static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
|
||||
GrAssert(count >= 1 && count < (int)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 < (int)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 < (int)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 < (int)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);
|
||||
}
|
||||
|
||||
GrGLProgram::GrGLProgram() {
|
||||
for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
|
||||
fStageEffects[stage] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GrGLProgram::~GrGLProgram() {
|
||||
|
||||
}
|
||||
|
||||
void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
|
||||
// Add stage configuration to the key
|
||||
key.keyData(reinterpret_cast<const uint8_t*>(&fProgramDesc), sizeof(ProgramDesc));
|
||||
|
||||
for(int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
|
||||
// First pass: count effects and write the count to the key.
|
||||
// This may seem like we are adding redundant data to the
|
||||
// key, but in ensures the one key cannot be a prefix of
|
||||
// another key, or identical to the key of a different program.
|
||||
GrGLEffect* currentEffect = fStageEffects[stage];
|
||||
uint8_t effectCount = 0;
|
||||
while (currentEffect) {
|
||||
GrAssert(effectCount < 255); // overflow detection
|
||||
++effectCount;
|
||||
currentEffect = currentEffect->nextEffect();
|
||||
}
|
||||
key.keyData(reinterpret_cast<const uint8_t*>(&effectCount), sizeof(uint8_t));
|
||||
|
||||
// Second pass: continue building key using the effects
|
||||
currentEffect = fStageEffects[stage];
|
||||
while (currentEffect) {
|
||||
fStageEffects[stage]->buildKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGLProgram::doGLSetup(GrPrimitiveType type,
|
||||
GrGLProgram::CachedData* programData) const {
|
||||
for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
|
||||
GrGLEffect* effect = fStageEffects[stage];
|
||||
if (effect) {
|
||||
if (!effect->doGLSetup(type, programData->fProgramID)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrGLProgram::doGLPost() const {
|
||||
for (int stage = 0; stage < GrDrawTarget::kNumStages; ++stage) {
|
||||
GrGLEffect* effect = fStageEffects[stage];
|
||||
if (effect) {
|
||||
effect->doGLPost();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLProgram::genProgram(GrGLProgram::CachedData* programData,
|
||||
const GrDrawTarget* target) const {
|
||||
|
||||
ShaderCodeSegments segments;
|
||||
const uint32_t& layout = fProgramDesc.fVertexLayout;
|
||||
|
||||
memset(&programData->fUniLocations, 0, sizeof(UniLocations));
|
||||
|
||||
bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
|
||||
fProgramDesc.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 (!(fProgramDesc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)) {
|
||||
segments.fVSCode += "\tgl_PointSize = 1.0;\n";
|
||||
}
|
||||
segments.fFSCode = "void main() {\n";
|
||||
|
||||
// add texture coordinates that are used to the list of vertex attr decls
|
||||
GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords];
|
||||
for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
|
||||
if (target->VertexUsesTexCoordIdx(t, layout)) {
|
||||
tex_attr_name(t, texCoordAttrs + t);
|
||||
|
||||
segments.fVSAttrs += "attribute vec2 ";
|
||||
segments.fVSAttrs += texCoordAttrs[t];
|
||||
segments.fVSAttrs += ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
// for each enabled stage figure out what the input coordinates are
|
||||
// and count the number of stages in use.
|
||||
const char* stageInCoords[GrDrawTarget::kNumStages];
|
||||
int numActiveStages = 0;
|
||||
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
if (fProgramDesc.fStages[s].fEnabled) {
|
||||
if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
|
||||
stageInCoords[s] = POS_ATTR_NAME;
|
||||
} else {
|
||||
int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
|
||||
// we better have input tex coordinates if stage is enabled.
|
||||
GrAssert(tcIdx >= 0);
|
||||
GrAssert(texCoordAttrs[tcIdx].length());
|
||||
stageInCoords[s] = texCoordAttrs[tcIdx].cstr();
|
||||
}
|
||||
++numActiveStages;
|
||||
}
|
||||
}
|
||||
|
||||
GrTokenString inColor = "vColor";
|
||||
|
||||
// if we have active stages string them together, feeding the output color
|
||||
// of each to the next and generating code for each stage.
|
||||
if (numActiveStages) {
|
||||
int currActiveStage = 0;
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
if (fProgramDesc.fStages[s].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(s,
|
||||
fProgramDesc.fStages[s],
|
||||
haveColor ? inColor.cstr() : NULL,
|
||||
outColor.cstr(),
|
||||
stageInCoords[s],
|
||||
&segments,
|
||||
&programData->fUniLocations.fStages[s]);
|
||||
++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
|
||||
programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
|
||||
stringCnt,
|
||||
strings,
|
||||
lengths);
|
||||
|
||||
stringCnt = 0;
|
||||
|
||||
if (strlen(GrShaderPrecision()) > 1) {
|
||||
strings[stringCnt] = GrShaderPrecision();
|
||||
lengths[stringCnt] = strlen(GrShaderPrecision());
|
||||
++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
|
||||
programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
|
||||
stringCnt,
|
||||
strings,
|
||||
lengths);
|
||||
|
||||
programData->fProgramID = GR_GL(CreateProgram());
|
||||
const GrGLint& progID = programData->fProgramID;
|
||||
|
||||
GR_GL(AttachShader(progID, programData->fVShaderID));
|
||||
GR_GL(AttachShader(progID, programData->fFShaderID));
|
||||
|
||||
// Bind the attrib locations to same values for all shaders
|
||||
GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
|
||||
for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
|
||||
if (texCoordAttrs[t].length()) {
|
||||
GR_GL(BindAttribLocation(progID,
|
||||
TEX_ATTR_LOCATION(t),
|
||||
texCoordAttrs[t].cstr()));
|
||||
}
|
||||
}
|
||||
|
||||
#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 s = 0; s < kNumStages; ++s) {
|
||||
if (fProgramDesc.fStages[s].fEnabled) {
|
||||
GrStringBuilder matName;
|
||||
tex_matrix_name(s, &matName);
|
||||
GR_GL(BindAttribLocation(progID,
|
||||
TEXMAT_ATTR_LOCATION(s),
|
||||
matName.cstr()));
|
||||
program->fUniLocations.fStages[s].fTextureMatrixUni =
|
||||
BOGUS_MATRIX_UNI_LOCATION;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
|
||||
|
||||
GR_GL(LinkProgram(progID));
|
||||
|
||||
GrGLint linked = GR_GL_INIT_ZERO;
|
||||
GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
|
||||
if (!linked) {
|
||||
GrGLint infoLen = GR_GL_INIT_ZERO;
|
||||
GR_GL(GetProgramiv(progID, GR_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));
|
||||
programData->fProgramID = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get uniform locations
|
||||
#if !ATTRIBUTE_MATRIX
|
||||
programData->fUniLocations.fViewMatrixUni =
|
||||
GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
|
||||
GrAssert(-1 != programData->fUniLocations.fViewMatrixUni);
|
||||
#endif
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
StageUniLocations& locations = programData->fUniLocations.fStages[s];
|
||||
if (fProgramDesc.fStages[s].fEnabled) {
|
||||
#if !ATTRIBUTE_MATRIX
|
||||
if (locations.fTextureMatrixUni) {
|
||||
GrTokenString texMName;
|
||||
tex_matrix_name(s, &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(s, &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(s, &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 s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
if (-1 != programData->fUniLocations.fStages[s].fSamplerUni) {
|
||||
GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
|
||||
}
|
||||
programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
|
||||
programData->fRadial2CenterX1[s] = GR_ScalarMax;
|
||||
programData->fRadial2Radius0[s] = -GR_ScalarMax;
|
||||
}
|
||||
programData->fViewMatrix = GrMatrix::InvalidMatrix();
|
||||
}
|
||||
|
||||
GrGLuint GrGLProgram::CompileShader(GrGLenum type,
|
||||
int stringCnt,
|
||||
const char** strings,
|
||||
int* stringLengths) {
|
||||
GrGLuint shader = GR_GL(CreateShader(type));
|
||||
if (0 == shader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GrGLint compiled = GR_GL_INIT_ZERO;
|
||||
GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
|
||||
GR_GL(CompileShader(shader));
|
||||
GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
|
||||
|
||||
if (!compiled) {
|
||||
GrGLint infoLen = GR_GL_INIT_ZERO;
|
||||
GR_GL(GetShaderiv(shader, GR_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;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Stage code generation
|
||||
//============================================================================
|
||||
|
||||
void GrGLProgram::genStageCode(int stageNum,
|
||||
const GrGLProgram::ProgramDesc::StageDesc& desc,
|
||||
const char* fsInColor, // NULL means no incoming color
|
||||
const char* fsOutColor,
|
||||
const char* vsInCoord,
|
||||
ShaderCodeSegments* segments,
|
||||
StageUniLocations* locations) const {
|
||||
|
||||
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 & ProgramDesc::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 & ProgramDesc::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 & ProgramDesc::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 (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
|
||||
|
||||
segments->fVSUnis += "uniform ";
|
||||
segments->fVSUnis += GrPrecision();
|
||||
segments->fVSUnis += " float ";
|
||||
segments->fVSUnis += radial2ParamsName;
|
||||
segments->fVSUnis += "[6];\n";
|
||||
|
||||
segments->fFSUnis += "uniform ";
|
||||
segments->fFSUnis += GrPrecision();
|
||||
segments->fFSUnis += " 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 & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
|
||||
ProgramDesc::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 (ProgramDesc::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 ProgramDesc::StageDesc::kIdentity_CoordMapping:
|
||||
sampleCoords = fsCoordName;
|
||||
break;
|
||||
case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
|
||||
sampleCoords = "vec2(atan(-";
|
||||
sampleCoords += fsCoordName;
|
||||
sampleCoords += ".y, -";
|
||||
sampleCoords += fsCoordName;
|
||||
sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
|
||||
break;
|
||||
case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
|
||||
sampleCoords = "vec2(length(";
|
||||
sampleCoords += fsCoordName;
|
||||
sampleCoords += ".xy), 0.5)";
|
||||
break;
|
||||
case ProgramDesc::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 == ProgramDesc::StageDesc::kAlpha_Modulation) {
|
||||
segments->fFSCode += ".aaaa";
|
||||
}
|
||||
segments->fFSCode += ";\n";
|
||||
|
||||
if(fStageEffects[stageNum]) {
|
||||
fStageEffects[stageNum]->genShaderCode(segments);
|
||||
}
|
||||
}
|
||||
|
215
gpu/src/GrGLProgram.h
Normal file
215
gpu/src/GrGLProgram.h
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef GrGLProgram_DEFINED
|
||||
#define GrGLProgram_DEFINED
|
||||
|
||||
#include "GrGLInterface.h"
|
||||
|
||||
#define POS_ATTR_LOCATION 0
|
||||
#define TEX_ATTR_LOCATION(X) (1 + (X))
|
||||
#define COL_ATTR_LOCATION (2 + GrDrawTarget::kMaxTexCoords)
|
||||
|
||||
#include "GrDrawTarget.h"
|
||||
|
||||
class GrBinHashKeyBuilder;
|
||||
class GrGLEffect;
|
||||
struct ShaderCodeSegments;
|
||||
|
||||
/**
|
||||
* This class manages a GPU program and 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.
|
||||
*/
|
||||
class GrGLProgram {
|
||||
public:
|
||||
class CachedData;
|
||||
|
||||
GrGLProgram();
|
||||
~GrGLProgram();
|
||||
|
||||
/**
|
||||
* Streams data that can uniquely identifies the generated
|
||||
* gpu program into a key, for cache indexing purposes.
|
||||
*
|
||||
* @param key The key object to receive the key data
|
||||
*/
|
||||
void buildKey(GrBinHashKeyBuilder& key) const;
|
||||
|
||||
/**
|
||||
* This is the heavy initilization routine for building a GLProgram.
|
||||
* The result of heavy init is not stored in datamembers of GrGLProgam,
|
||||
* but in a separate cacheable container.
|
||||
*/
|
||||
void genProgram(CachedData* programData, const GrDrawTarget* target) const;
|
||||
|
||||
/**
|
||||
* Routine that is called before rendering. Sets-up all the state and
|
||||
* other initializations required for the Gpu Program to run.
|
||||
*/
|
||||
bool doGLSetup(GrPrimitiveType type, CachedData* programData) const;
|
||||
|
||||
/**
|
||||
* Routine that is called after rendering. Performs state restoration.
|
||||
* May perform secondary render passes.
|
||||
*/
|
||||
void doGLPost() const;
|
||||
|
||||
/**
|
||||
* Configures the GrGLProgram based on the state of a GrDrawTarget
|
||||
* object. This is the fast and light initialization. Retrieves all the
|
||||
* state that is required for performing the heavy init (i.e. genProgram),
|
||||
* or for retrieving heavy init results from cache.
|
||||
*/
|
||||
void buildFromTarget(const GrDrawTarget* target);
|
||||
|
||||
private:
|
||||
|
||||
//Parameters that affect code generation
|
||||
struct ProgramDesc {
|
||||
GrVertexLayout fVertexLayout;
|
||||
|
||||
enum {
|
||||
kNotPoints_OptFlagBit = 0x1,
|
||||
kVertexColorAllOnes_OptFlagBit = 0x2,
|
||||
};
|
||||
// we're assuming optflags and layout pack into 32 bits
|
||||
// VS 2010 seems to require short rather than just unsigned
|
||||
// for this to pack
|
||||
unsigned short fOptFlags : 16;
|
||||
|
||||
struct StageDesc {
|
||||
enum OptFlagBits {
|
||||
kNoPerspective_OptFlagBit = 0x1,
|
||||
kIdentityMatrix_OptFlagBit = 0x2
|
||||
};
|
||||
|
||||
unsigned fOptFlags : 8;
|
||||
unsigned fEnabled : 8;
|
||||
|
||||
enum Modulation {
|
||||
kColor_Modulation,
|
||||
kAlpha_Modulation
|
||||
} fModulation : 8;
|
||||
|
||||
enum CoordMapping {
|
||||
kIdentity_CoordMapping,
|
||||
kRadialGradient_CoordMapping,
|
||||
kSweepGradient_CoordMapping,
|
||||
kRadial2Gradient_CoordMapping
|
||||
} fCoordMapping : 8;
|
||||
} fStages[GrDrawTarget::kNumStages];
|
||||
} fProgramDesc;
|
||||
|
||||
public:
|
||||
struct StageUniLocations {
|
||||
GrGLint fTextureMatrixUni;
|
||||
GrGLint fSamplerUni;
|
||||
GrGLint fRadial2Uni;
|
||||
};
|
||||
|
||||
struct UniLocations {
|
||||
GrGLint fViewMatrixUni;
|
||||
StageUniLocations fStages[GrDrawTarget::kNumStages];
|
||||
};
|
||||
|
||||
class CachedData : public ::GrNoncopyable {
|
||||
public:
|
||||
CachedData() {
|
||||
GR_DEBUGCODE(fEffectUniCount = 0;)
|
||||
fEffectUniLocationsExtended = NULL;
|
||||
}
|
||||
|
||||
~CachedData() {
|
||||
GrFree(fEffectUniLocationsExtended);
|
||||
}
|
||||
|
||||
void copyAndTakeOwnership(CachedData& other) {
|
||||
memcpy(this, &other, sizeof(this));
|
||||
other.fEffectUniLocationsExtended = NULL; // ownership transfer
|
||||
GR_DEBUGCODE(other.fEffectUniCount = 0;)
|
||||
}
|
||||
|
||||
void setEffectUniformCount(size_t effectUniforms) {
|
||||
GR_DEBUGCODE(fEffectUniCount = effectUniforms;)
|
||||
GrFree(fEffectUniLocationsExtended);
|
||||
if (effectUniforms > kUniLocationPreAllocSize) {
|
||||
fEffectUniLocationsExtended = (GrGLint*)GrMalloc(sizeof(GrGLint)*(effectUniforms-kUniLocationPreAllocSize));
|
||||
} else {
|
||||
fEffectUniLocationsExtended = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GrGLint& effectUniLocation(size_t index) {
|
||||
GrAssert(index < fEffectUniCount);
|
||||
return (index < kUniLocationPreAllocSize) ?
|
||||
fEffectUniLocations[index] :
|
||||
fEffectUniLocationsExtended[index - kUniLocationPreAllocSize];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// IDs
|
||||
GrGLuint fVShaderID;
|
||||
GrGLuint fFShaderID;
|
||||
GrGLuint fProgramID;
|
||||
// shader uniform locations (-1 if shader doesn't use them)
|
||||
UniLocations fUniLocations;
|
||||
|
||||
GrMatrix fViewMatrix;
|
||||
|
||||
// these reflect the current values of uniforms
|
||||
// (GL uniform values travel with program)
|
||||
GrMatrix fTextureMatrices[GrDrawTarget::kNumStages];
|
||||
GrScalar fRadial2CenterX1[GrDrawTarget::kNumStages];
|
||||
GrScalar fRadial2Radius0[GrDrawTarget::kNumStages];
|
||||
bool fRadial2PosRoot[GrDrawTarget::kNumStages];
|
||||
|
||||
private:
|
||||
enum Constants {
|
||||
kUniLocationPreAllocSize = 8
|
||||
};
|
||||
|
||||
GrGLint fEffectUniLocations[kUniLocationPreAllocSize];
|
||||
GrGLint* fEffectUniLocationsExtended;
|
||||
GR_DEBUGCODE(size_t fEffectUniCount;)
|
||||
}; // CachedData
|
||||
|
||||
GrGLEffect* fStageEffects[GrDrawTarget::kNumStages];
|
||||
|
||||
private:
|
||||
void genStageCode(int stageNum,
|
||||
const ProgramDesc::StageDesc& desc,
|
||||
const char* fsInColor, // NULL means no incoming color
|
||||
const char* fsOutColor,
|
||||
const char* vsInCoord,
|
||||
ShaderCodeSegments* segments,
|
||||
StageUniLocations* locations) const;
|
||||
|
||||
// Compiles a GL shader, returns shader ID or 0 if failed
|
||||
// params have same meaning as glShaderSource
|
||||
static GrGLuint CompileShader(GrGLenum type, int stringCnt,
|
||||
const char** strings,
|
||||
int* stringLengths);
|
||||
|
||||
friend class GrGpuGLShaders;
|
||||
};
|
||||
|
||||
#endif
|
@ -14,7 +14,6 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "GrTypes.h"
|
||||
|
||||
// must be before GrGLConfig.h
|
||||
@ -24,10 +23,10 @@
|
||||
|
||||
#include "GrGLConfig.h"
|
||||
|
||||
#include "GrGpuGLFixed.h"
|
||||
#include "GrGpuGLShaders2.h"
|
||||
|
||||
#include "GrGpu.h"
|
||||
#include "GrGpuGLFixed.h"
|
||||
#include "GrGpuGLShaders.h"
|
||||
#include "GrGpuGLShaders2.h"
|
||||
|
||||
GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) {
|
||||
// If no GL bindings have been installed, fall-back to calling the
|
||||
@ -40,7 +39,13 @@ GrGpu* GrGpu::Create(Engine engine, Platform3DContext context3D) {
|
||||
switch (engine) {
|
||||
case kOpenGL_Shaders_Engine:
|
||||
GrAssert(NULL == context3D);
|
||||
gpu = new GrGpuGLShaders2;
|
||||
{
|
||||
#if GR_USE_NEW_GLSHADERS
|
||||
gpu = new GrGpuGLShaders;
|
||||
#else
|
||||
gpu = new GrGpuGLShaders2;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case kOpenGL_Fixed_Engine:
|
||||
GrAssert(NULL == context3D);
|
||||
|
533
gpu/src/GrGpuGLShaders.cpp
Normal file
533
gpu/src/GrGpuGLShaders.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
/*
|
||||
Copyright 2011 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 "GrBinHashKey.h"
|
||||
#include "GrGLEffect.h"
|
||||
#include "GrGLProgram.h"
|
||||
#include "GrGpuGLShaders.h"
|
||||
#include "GrGpuVertex.h"
|
||||
#include "GrMemory.h"
|
||||
#include "GrNoncopyable.h"
|
||||
#include "GrStringBuilder.h"
|
||||
|
||||
#define ATTRIBUTE_MATRIX 0
|
||||
#define PRINT_SHADERS 0
|
||||
#define SKIP_CACHE_CHECK true
|
||||
#define GR_UINT32_MAX static_cast<uint32_t>(-1)
|
||||
|
||||
#if ATTRIBUTE_MATRIX
|
||||
#define VIEWMAT_ATTR_LOCATION (3 + GrDrawTarget::kMaxTexCoords)
|
||||
#define TEXMAT_ATTR_LOCATION(X) (6 + GrDrawTarget::kMaxTexCoords + 3 * (X))
|
||||
#define BOGUS_MATRIX_UNI_LOCATION 1000
|
||||
#endif
|
||||
|
||||
#include "GrTHashCache.h"
|
||||
|
||||
class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
|
||||
private:
|
||||
class Entry;
|
||||
|
||||
#if GR_DEBUG
|
||||
typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
|
||||
#else
|
||||
typedef GrBinHashKey<Entry, 32> ProgramHashKey;
|
||||
#endif
|
||||
|
||||
class Entry : public ::GrNoncopyable {
|
||||
public:
|
||||
Entry() {}
|
||||
private:
|
||||
void copyAndTakeOwnership(Entry& entry) {
|
||||
fProgramData.copyAndTakeOwnership(entry.fProgramData);
|
||||
fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
|
||||
fLRUStamp = entry.fLRUStamp;
|
||||
}
|
||||
|
||||
public:
|
||||
int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
|
||||
|
||||
public:
|
||||
GrGLProgram::CachedData fProgramData;
|
||||
ProgramHashKey fKey;
|
||||
unsigned int fLRUStamp;
|
||||
};
|
||||
|
||||
GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
|
||||
|
||||
enum {
|
||||
kMaxEntries = 32
|
||||
};
|
||||
Entry fEntries[kMaxEntries];
|
||||
int fCount;
|
||||
unsigned int fCurrLRUStamp;
|
||||
|
||||
public:
|
||||
ProgramCache()
|
||||
: fCount(0)
|
||||
, fCurrLRUStamp(0) {
|
||||
}
|
||||
|
||||
~ProgramCache() {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
|
||||
}
|
||||
}
|
||||
|
||||
void abandon() {
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
void invalidateViewMatrices() {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
// set to illegal matrix
|
||||
fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc,
|
||||
const GrDrawTarget* target) {
|
||||
ProgramHashKey key;
|
||||
while (key.doPass()) {
|
||||
desc.buildKey(key);
|
||||
}
|
||||
Entry* entry = fHashCache.find(key);
|
||||
if (NULL == entry) {
|
||||
if (fCount < kMaxEntries) {
|
||||
entry = fEntries + fCount;
|
||||
++fCount;
|
||||
} else {
|
||||
GrAssert(kMaxEntries == fCount);
|
||||
entry = fEntries;
|
||||
for (int i = 1; i < kMaxEntries; ++i) {
|
||||
if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
|
||||
entry = fEntries + i;
|
||||
}
|
||||
}
|
||||
fHashCache.remove(entry->fKey, entry);
|
||||
GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
|
||||
}
|
||||
entry->fKey.copyAndTakeOwnership(key);
|
||||
desc.genProgram(&entry->fProgramData, target);
|
||||
fHashCache.insert(entry->fKey, entry);
|
||||
}
|
||||
|
||||
entry->fLRUStamp = fCurrLRUStamp;
|
||||
if (GR_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->fProgramData;
|
||||
}
|
||||
};
|
||||
|
||||
void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
|
||||
GR_GL(DeleteShader(programData->fVShaderID));
|
||||
GR_GL(DeleteShader(programData->fFShaderID));
|
||||
GR_GL(DeleteProgram(programData->fProgramID));
|
||||
GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
|
||||
}
|
||||
|
||||
|
||||
GrGpuGLShaders::GrGpuGLShaders() {
|
||||
|
||||
resetContextHelper();
|
||||
|
||||
fProgramData = NULL;
|
||||
fProgramCache = new ProgramCache();
|
||||
}
|
||||
|
||||
GrGpuGLShaders::~GrGpuGLShaders() {
|
||||
delete fProgramCache;
|
||||
}
|
||||
|
||||
const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
|
||||
#if ATTRIBUTE_MATRIX
|
||||
return fHWDrawState.fSamplerStates[stage].getMatrix();
|
||||
#else
|
||||
GrAssert(fProgramData);
|
||||
return fProgramData->fTextureMatrices[stage];
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
|
||||
#if ATTRIBUTE_MATRIX
|
||||
fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
|
||||
#else
|
||||
GrAssert(fProgramData);
|
||||
fProgramData->fTextureMatrices[stage] = matrix;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::resetContext() {
|
||||
INHERITED::resetContext();
|
||||
resetContextHelper();
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::resetContextHelper() {
|
||||
fHWGeometryState.fVertexLayout = 0;
|
||||
fHWGeometryState.fVertexOffset = ~0;
|
||||
GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
|
||||
for (int t = 0; t < kMaxTexCoords; ++t) {
|
||||
GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
|
||||
}
|
||||
GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
|
||||
|
||||
fHWProgramID = 0;
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::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.fViewMatrix);
|
||||
|
||||
// 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
|
||||
GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
|
||||
GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
|
||||
GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
|
||||
#else
|
||||
GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,1,false,mt));
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::flushTextureMatrix(int stage) {
|
||||
GrAssert(NULL != fCurrDrawState.fTextures[stage]);
|
||||
|
||||
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[stage];
|
||||
|
||||
GrMatrix m = getSamplerMatrix(stage);
|
||||
GrSamplerState::SampleMode mode =
|
||||
fCurrDrawState.fSamplerStates[0].getSampleMode();
|
||||
AdjustTextureMatrix(texture, mode, &m);
|
||||
|
||||
// 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
|
||||
GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0));
|
||||
GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3));
|
||||
GR_GL(VertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6));
|
||||
#else
|
||||
GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni,
|
||||
1, false, mt));
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::flushRadial2(int stage) {
|
||||
|
||||
const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[stage];
|
||||
|
||||
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(fProgramData->fUniLocations.fStages[stage].fRadial2Uni,
|
||||
6,
|
||||
unis));
|
||||
}
|
||||
|
||||
bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
|
||||
if (!flushGLStateCommon(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fDirtyFlags.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.fViewMatrix = GrMatrix::InvalidMatrix();
|
||||
#else
|
||||
// we assume all shader matrices may be wrong after viewport changes
|
||||
fProgramCache->invalidateViewMatrices();
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
buildProgram(type);
|
||||
fProgramData = fProgramCache->getProgramData(fCurrentProgram, this);
|
||||
|
||||
if (fHWProgramID != fProgramData->fProgramID) {
|
||||
GR_GL(UseProgram(fProgramData->fProgramID));
|
||||
fHWProgramID = fProgramData->fProgramID;
|
||||
}
|
||||
|
||||
if (!fCurrentProgram.doGLSetup(type, fProgramData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ATTRIBUTE_MATRIX
|
||||
GrMatrix& currViewMatrix = fHWDrawState.fViewMatrix;
|
||||
#else
|
||||
GrMatrix& currViewMatrix = fProgramData->fViewMatrix;
|
||||
#endif
|
||||
|
||||
if (currViewMatrix != fCurrDrawState.fViewMatrix) {
|
||||
flushViewMatrix();
|
||||
currViewMatrix = fCurrDrawState.fViewMatrix;
|
||||
}
|
||||
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
|
||||
if (NULL != texture) {
|
||||
if (-1 != fProgramData->fUniLocations.fStages[s].fTextureMatrixUni &&
|
||||
(((1 << s) & fDirtyFlags.fTextureChangedMask) ||
|
||||
getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
|
||||
flushTextureMatrix(s);
|
||||
recordHWSamplerMatrix(s, getSamplerMatrix(s));
|
||||
}
|
||||
}
|
||||
|
||||
const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
|
||||
if (-1 != fProgramData->fUniLocations.fStages[s].fRadial2Uni &&
|
||||
(fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
|
||||
fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
|
||||
fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
|
||||
|
||||
flushRadial2(s);
|
||||
|
||||
fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
|
||||
fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
|
||||
fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
|
||||
}
|
||||
}
|
||||
resetDirtyFlags();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::postDraw() {
|
||||
fCurrentProgram.doGLPost();
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::setupGeometry(int* startVertex,
|
||||
int* startIndex,
|
||||
int vertexCount,
|
||||
int indexCount) {
|
||||
|
||||
int newColorOffset;
|
||||
int newTexCoordOffsets[kMaxTexCoords];
|
||||
|
||||
GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
|
||||
newTexCoordOffsets,
|
||||
&newColorOffset);
|
||||
int oldColorOffset;
|
||||
int oldTexCoordOffsets[kMaxTexCoords];
|
||||
GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
|
||||
oldTexCoordOffsets,
|
||||
&oldColorOffset);
|
||||
bool indexed = NULL != startIndex;
|
||||
|
||||
int extraVertexOffset;
|
||||
int extraIndexOffset;
|
||||
setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
|
||||
|
||||
GrGLenum scalarType;
|
||||
bool texCoordNorm;
|
||||
if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
|
||||
scalarType = GrGLTextType;
|
||||
texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
|
||||
} else {
|
||||
scalarType = GrGLType;
|
||||
texCoordNorm = false;
|
||||
}
|
||||
|
||||
size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
|
||||
*startVertex = 0;
|
||||
if (indexed) {
|
||||
*startIndex += extraIndexOffset;
|
||||
}
|
||||
|
||||
// all the Pointers must be set if any of these are true
|
||||
bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
|
||||
vertexOffset != fHWGeometryState.fVertexOffset ||
|
||||
newStride != oldStride;
|
||||
|
||||
// position and tex coord offsets change if above conditions are true
|
||||
// or the type/normalization changed based on text vs nontext type coords.
|
||||
bool posAndTexChange = allOffsetsChange ||
|
||||
(((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
|
||||
(kTextFormat_VertexLayoutBit &
|
||||
(fHWGeometryState.fVertexLayout ^
|
||||
fGeometrySrc.fVertexLayout)));
|
||||
|
||||
if (posAndTexChange) {
|
||||
GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
|
||||
false, newStride, (GrGLvoid*)vertexOffset));
|
||||
fHWGeometryState.fVertexOffset = vertexOffset;
|
||||
}
|
||||
|
||||
for (int t = 0; t < kMaxTexCoords; ++t) {
|
||||
if (newTexCoordOffsets[t] > 0) {
|
||||
GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
|
||||
if (oldTexCoordOffsets[t] <= 0) {
|
||||
GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
|
||||
GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
|
||||
texCoordNorm, newStride, texCoordOffset));
|
||||
} else if (posAndTexChange ||
|
||||
newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
|
||||
GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
|
||||
texCoordNorm, newStride, texCoordOffset));
|
||||
}
|
||||
} else if (oldTexCoordOffsets[t] > 0) {
|
||||
GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION(t)));
|
||||
}
|
||||
}
|
||||
|
||||
if (newColorOffset > 0) {
|
||||
GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
|
||||
if (oldColorOffset <= 0) {
|
||||
GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
|
||||
GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
|
||||
GR_GL_UNSIGNED_BYTE,
|
||||
true, newStride, colorOffset));
|
||||
} else if (allOffsetsChange || newColorOffset != oldColorOffset) {
|
||||
GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
|
||||
GR_GL_UNSIGNED_BYTE,
|
||||
true, newStride, colorOffset));
|
||||
}
|
||||
} else if (oldColorOffset > 0) {
|
||||
GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
|
||||
}
|
||||
|
||||
fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
|
||||
fHWGeometryState.fArrayPtrsDirty = false;
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
// Must initialize all fields or cache will have false negatives!
|
||||
fCurrentProgram.fProgramDesc.fVertexLayout = fGeometrySrc.fVertexLayout;
|
||||
|
||||
fCurrentProgram.fProgramDesc.fOptFlags = 0;
|
||||
if (kPoints_PrimitiveType != type) {
|
||||
fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kNotPoints_OptFlagBit;
|
||||
}
|
||||
#if GR_AGGRESSIVE_SHADER_OPTS
|
||||
if (!(fCurrentProgram.fProgramDesc.fVertexLayout & kColor_VertexLayoutBit) &&
|
||||
(0xffffffff == fCurrDrawState.fColor)) {
|
||||
fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kVertexColorAllOnes_OptFlagBit;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
GrGLProgram::ProgramDesc::StageDesc& stage = fCurrentProgram.fProgramDesc.fStages[s];
|
||||
|
||||
stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout);
|
||||
|
||||
if (stage.fEnabled) {
|
||||
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
|
||||
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 (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
|
||||
stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
|
||||
} else if (!getSamplerMatrix(s).hasPerspective()) {
|
||||
stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
|
||||
} else {
|
||||
stage.fOptFlags = 0;
|
||||
}
|
||||
switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
|
||||
case GrSamplerState::kNormal_SampleMode:
|
||||
stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
|
||||
break;
|
||||
case GrSamplerState::kRadial_SampleMode:
|
||||
stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
|
||||
break;
|
||||
case GrSamplerState::kRadial2_SampleMode:
|
||||
stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
|
||||
break;
|
||||
case GrSamplerState::kSweep_SampleMode:
|
||||
stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
|
||||
break;
|
||||
default:
|
||||
GrAssert(!"Unexpected sample mode!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
|
||||
stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
|
||||
} else {
|
||||
stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
|
||||
}
|
||||
|
||||
if (fCurrDrawState.fEffects[s]) {
|
||||
fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]);
|
||||
} else {
|
||||
delete fCurrentProgram.fStageEffects[s];
|
||||
fCurrentProgram.fStageEffects[s] = NULL;
|
||||
}
|
||||
} else {
|
||||
stage.fOptFlags = 0;
|
||||
stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
|
||||
stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
|
||||
fCurrentProgram.fStageEffects[s] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
77
gpu/src/GrGpuGLShaders.h
Normal file
77
gpu/src/GrGpuGLShaders.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright 2011 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrGpuGLShaders_DEFINED
|
||||
#define GrGpuGLShaders_DEFINED
|
||||
|
||||
#include "GrGpuGL.h"
|
||||
#include "GrGLProgram.h"
|
||||
|
||||
class GrGpuGLProgram;
|
||||
|
||||
// Programmable OpenGL or OpenGL ES 2.0
|
||||
class GrGpuGLShaders : public GrGpuGL {
|
||||
public:
|
||||
GrGpuGLShaders();
|
||||
virtual ~GrGpuGLShaders();
|
||||
|
||||
virtual void resetContext();
|
||||
|
||||
protected:
|
||||
// overrides from GrGpu
|
||||
virtual bool flushGraphicsState(GrPrimitiveType type);
|
||||
virtual void setupGeometry(int* startVertex,
|
||||
int* startIndex,
|
||||
int vertexCount,
|
||||
int indexCount);
|
||||
virtual void postDraw();
|
||||
|
||||
private:
|
||||
|
||||
class ProgramCache;
|
||||
|
||||
void resetContextHelper();
|
||||
|
||||
// Helpers to make code more readable
|
||||
const GrMatrix& getHWSamplerMatrix(int stage);
|
||||
void recordHWSamplerMatrix(int stage, const GrMatrix& matrix);
|
||||
|
||||
// sets the texture matrix uniform for currently bound program
|
||||
void flushTextureMatrix(int stage);
|
||||
|
||||
// sets the MVP matrix uniform for currently bound program
|
||||
void flushViewMatrix();
|
||||
|
||||
// flushes the parameters to two point radial gradient
|
||||
void flushRadial2(int stage);
|
||||
|
||||
static void DeleteProgram(GrGLProgram::CachedData* programData);
|
||||
|
||||
void ProgramUnitTest();
|
||||
|
||||
void buildProgram(GrPrimitiveType type);
|
||||
|
||||
ProgramCache* fProgramCache;
|
||||
GrGLProgram::CachedData* fProgramData;
|
||||
GrGLuint fHWProgramID;
|
||||
GrGLProgram fCurrentProgram;
|
||||
|
||||
typedef GrGpuGL INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@ SOURCE := \
|
||||
GrDrawTarget.cpp \
|
||||
GrGLIndexBuffer.cpp \
|
||||
GrGLInterface.cpp \
|
||||
GrGLProgram.cpp \
|
||||
GrGLTexture.cpp \
|
||||
GrGLVertexBuffer.cpp \
|
||||
GrGpu.cpp \
|
||||
@ -15,6 +16,7 @@ SOURCE := \
|
||||
GrGpuFactory.cpp \
|
||||
GrGLUtil.cpp \
|
||||
GrGpuGL.cpp \
|
||||
GrGpuGLShaders.cpp \
|
||||
GrInOrderDrawBuffer.cpp \
|
||||
GrMatrix.cpp \
|
||||
GrMemory.cpp \
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "GrMatrix.h"
|
||||
#include "GrRedBlackTree.h"
|
||||
#include "GrPath.h"
|
||||
#include "GrBinHashKey.h"
|
||||
|
||||
static void dump(const GrTDArray<int>& array) {
|
||||
#if 0
|
||||
@ -74,9 +75,84 @@ static void test_bsearch() {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_binHashKey()
|
||||
{
|
||||
const char* testStringA = "abcdA";
|
||||
const char* testStringB = "abcdB";
|
||||
enum {
|
||||
kDataLenUsedForKey = 5
|
||||
};
|
||||
|
||||
class Entry {
|
||||
// bogus empty class
|
||||
};
|
||||
|
||||
typedef GrBinHashKey<Entry, kDataLenUsedForKey> KeyType;
|
||||
|
||||
KeyType keyA;
|
||||
int passCnt = 0;
|
||||
while (keyA.doPass()) {
|
||||
++passCnt;
|
||||
keyA.keyData(reinterpret_cast<const uint8_t*>(testStringA), kDataLenUsedForKey);
|
||||
}
|
||||
GrAssert(passCnt == 1); //We expect the static allocation to suffice
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey-1> keyBust;
|
||||
passCnt = 0;
|
||||
while (keyBust.doPass()) {
|
||||
++passCnt;
|
||||
// Exceed static storage by 1
|
||||
keyBust.keyData(reinterpret_cast<const uint8_t*>(testStringA), kDataLenUsedForKey);
|
||||
}
|
||||
GrAssert(passCnt == 2); //We expect dynamic allocation to be necessary
|
||||
GrAssert(keyA.getHash() == keyBust.getHash());
|
||||
|
||||
// Test that adding keyData in chunks gives
|
||||
// the same hash as with one chunk
|
||||
KeyType keyA2;
|
||||
while (keyA2.doPass()) {
|
||||
keyA2.keyData(reinterpret_cast<const uint8_t*>(testStringA), 2);
|
||||
keyA2.keyData(&reinterpret_cast<const uint8_t*>(testStringA)[2], kDataLenUsedForKey-2);
|
||||
}
|
||||
GrAssert(keyA.getHash() == keyA2.getHash());
|
||||
|
||||
KeyType keyB;
|
||||
while (keyB.doPass()){
|
||||
keyB.keyData(reinterpret_cast<const uint8_t*>(testStringB), kDataLenUsedForKey);
|
||||
}
|
||||
GrAssert(keyA.compare(keyB) < 0);
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
|
||||
//Test ownership tranfer and copying
|
||||
keyB.copyAndTakeOwnership(keyA);
|
||||
GrAssert(keyA.fIsValid == false);
|
||||
GrAssert(keyB.fIsValid);
|
||||
GrAssert(keyB.getHash() == keyA2.getHash());
|
||||
GrAssert(keyB.compare(keyA2) == 0);
|
||||
keyA.deepCopyFrom(keyB);
|
||||
GrAssert(keyA.fIsValid);
|
||||
GrAssert(keyB.fIsValid);
|
||||
GrAssert(keyA.getHash() == keyA2.getHash());
|
||||
GrAssert(keyA.compare(keyA2) == 0);
|
||||
|
||||
//Test ownership tranfer and copying with key on heap
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey-1> keyBust2;
|
||||
keyBust2.deepCopyFrom(keyBust);
|
||||
GrAssert(keyBust.fIsValid);
|
||||
GrAssert(keyBust2.fIsValid);
|
||||
GrAssert(keyBust.getHash() == keyBust2.getHash());
|
||||
GrAssert(keyBust.compare(keyBust2) == 0);
|
||||
GrBinHashKey<Entry, kDataLenUsedForKey-1> keyBust3;
|
||||
keyBust3.deepCopyFrom(keyBust);
|
||||
GrAssert(keyBust.fIsValid == false);
|
||||
GrAssert(keyBust3.fIsValid);
|
||||
GrAssert(keyBust3.getHash() == keyBust2.getHash());
|
||||
GrAssert(keyBust3.compare(keyBust2) == 0);
|
||||
}
|
||||
|
||||
void gr_run_unittests() {
|
||||
test_tdarray();
|
||||
test_bsearch();
|
||||
test_binHashKey();
|
||||
GrMatrix::UnitTest();
|
||||
GrRedBlackTree<int>::UnitTest();
|
||||
GrPath::ConvexUnitTest();
|
||||
|
@ -948,14 +948,18 @@
|
||||
|
||||
'../gpu/src/GrAllocPool.cpp',
|
||||
'../gpu/src/GrAtlas.cpp',
|
||||
'../gpu/src/GrBinHashKey.h',
|
||||
'../gpu/src/GrBufferAllocPool.cpp',
|
||||
'../gpu/src/GrBufferAllocPool.h',
|
||||
'../gpu/src/GrClip.cpp',
|
||||
'../gpu/src/GrContext.cpp',
|
||||
'../gpu/src/GrCreatePathRenderer_none.cpp',
|
||||
'../gpu/src/GrDrawTarget.cpp',
|
||||
'../gpu/src/GrGLEffect.h',
|
||||
'../gpu/src/GrGLIndexBuffer.cpp',
|
||||
'../gpu/src/GrGLInterface.cpp',
|
||||
'../gpu/src/GrGLProgram.cpp',
|
||||
'../gpu/src/GrGLProgram.h',
|
||||
'../gpu/src/GrGLTexture.cpp',
|
||||
'../gpu/src/GrGLUtil.cpp',
|
||||
'../gpu/src/GrGLVertexBuffer.cpp',
|
||||
@ -965,6 +969,8 @@
|
||||
'../gpu/src/GrGpuGL.h',
|
||||
'../gpu/src/GrGpuGLFixed.cpp',
|
||||
'../gpu/src/GrGpuGLFixed.h',
|
||||
'../gpu/src/GrGpuGLShaders.cpp',
|
||||
'../gpu/src/GrGpuGLShaders.h',
|
||||
'../gpu/src/GrGpuGLShaders2.cpp',
|
||||
'../gpu/src/GrGpuGLShaders2.h',
|
||||
'../gpu/src/GrInOrderDrawBuffer.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user