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:
junov@google.com 2011-03-31 21:26:24 +00:00
parent 772813afa6
commit f93e717c7f
12 changed files with 1982 additions and 5 deletions

View File

@ -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.

View File

@ -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
View 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
View 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
View 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
View 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

View File

@ -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
View 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
View 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

View File

@ -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 \

View File

@ -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();

View File

@ -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',