Added tracking of frame buffer objects to debug GL interface
http://codereview.appspot.com/5866043/
git-svn-id: http://skia.googlecode.com/svn/trunk@3455 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 1e63bb6..bcceb72 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -21,6 +21,7 @@
#include "SkImageEncoder.h"
#include "gl/SkNativeGLContext.h"
#include "gl/SkMesaGLContext.h"
+#include "gl/SkDebugGLContext.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkRefCnt.h"
@@ -606,11 +607,12 @@
SkDebugf(
"%s [-w writePath] [-r readPath] [-d diffPath] [-i resourcePath]\n"
" [--noreplay] [--serialize] [--forceBWtext] [--nopdf] \n"
- " [--nodeferred] [--match substring] [--notexturecache]"
+ " [--nodeferred] [--match substring] [--notexturecache]\n"
+ " "
#if SK_MESA
- " [--mesagl]"
+ "[--mesagl]"
#endif
- "\n\n", argv0);
+ " [--debuggl]\n\n", argv0);
SkDebugf(" writePath: directory to write rendered images in.\n");
SkDebugf(
" readPath: directory to read reference images from;\n"
@@ -627,6 +629,7 @@
#if SK_MESA
SkDebugf(" --mesagl will run using the osmesa sw gl rasterizer.\n");
#endif
+ SkDebugf(" --debuggl will run using the debugging gl utility.\n");
SkDebugf(" --notexturecache: disable the gpu texture cache.\n");
}
@@ -684,6 +687,7 @@
bool doReplay = true;
bool doSerialize = false;
bool useMesa = false;
+ bool useDebugGL = false;
bool doDeferred = true;
bool disableTextureCache = false;
@@ -730,6 +734,8 @@
} else if (strcmp(*argv, "--mesagl") == 0) {
useMesa = true;
#endif
+ } else if (strcmp(*argv, "--debuggl") == 0) {
+ useDebugGL = true;
} else if (strcmp(*argv, "--notexturecache") == 0) {
disableTextureCache = true;
} else {
@@ -763,7 +769,9 @@
glContext.reset(new SkMesaGLContext());
} else
#endif
- {
+ if (useDebugGL) {
+ glContext.reset(new SkDebugGLContext());
+ } else {
glContext.reset(new SkNativeGLContext());
}
@@ -893,5 +901,9 @@
}
printf("Ran %d tests: %d passed, %d failed, %d missing reference images\n",
testsRun, testsPassed, testsFailed, testsMissingReferenceImages);
+
+ SkDELETE(skiagm::gGrContext);
+ skiagm::gGrContext = NULL;
+
return (0 == testsFailed) ? 0 : -1;
}
diff --git a/src/gpu/gl/GrGLCreateDebugInterface.cpp b/src/gpu/gl/GrGLCreateDebugInterface.cpp
index 3b2a376..b6e2e58 100644
--- a/src/gpu/gl/GrGLCreateDebugInterface.cpp
+++ b/src/gpu/gl/GrGLCreateDebugInterface.cpp
@@ -14,6 +14,18 @@
// the OpenGLES 2.0 spec says this must be >= 2
static const GrGLint kDefaultMaxTextureUnits = 8;
+// the OpenGLES 2.0 spec says this must be >= 128
+static const GrGLint kDefaultMaxVertexUniformVectors = 128;
+
+// the OpenGLES 2.0 spec says this must be >=16
+static const GrGLint kDefaultMaxFragmentUniformVectors = 16;
+
+// the OpenGLES 2.0 spec says this must be >= 8
+static const GrGLint kDefaultMaxVertexAttribs = 8;
+
+// the OpenGLES 2.0 spec says this must be >= 8
+static const GrGLint kDefaultMaxVaryingVectors = 8;
+
////////////////////////////////////////////////////////////////////////////////
// This object is used to track the OpenGL objects. We don't use real
// reference counting (i.e., we don't free the objects when their ref count
@@ -26,15 +38,23 @@
public:
GrFakeRefObj(GrGLuint ID)
: fRef(0)
+ , fHighRefCount(0)
, fID(ID)
, fMarkedForDeletion(false)
, fDeleted(false) {
}
virtual ~GrFakeRefObj() {};
- void ref() { fRef++; }
+ void ref() {
+ fRef++;
+ if (fHighRefCount < fRef) {
+ fHighRefCount = fRef;
+ }
+ }
void unref() {
fRef--;
+ GrAlwaysAssert(fRef >= 0);
+
// often in OpenGL a given object may still be in use when the
// delete call is made. In these cases the object is marked
// for deletion and then freed when it is no longer in use
@@ -43,6 +63,7 @@
}
}
int getRefCount() const { return fRef; }
+ int getHighRefCount() const { return fHighRefCount; }
GrGLuint getID() const { return fID; }
@@ -60,6 +81,7 @@
protected:
private:
int fRef;
+ int fHighRefCount; // high water mark of the ref count
GrGLuint fID;
bool fMarkedForDeletion;
// The deleted flag is only set when OpenGL thinks the object is deleted
@@ -96,14 +118,14 @@
void resetBound() { fBound = false; }
bool getBound() const { return fBound; }
- void allocate(GrGLint size, const GrGLvoid *dataPtr) {
+ void allocate(GrGLint size, const GrGLchar *dataPtr) {
GrAlwaysAssert(size >= 0);
// delete pre-existing data
delete fDataPtr;
fSize = size;
- fDataPtr = new char[size];
+ fDataPtr = new GrGLchar[size];
if (dataPtr) {
memcpy(fDataPtr, dataPtr, fSize);
}
@@ -126,7 +148,7 @@
protected:
private:
- GrGLvoid* fDataPtr;
+ GrGLchar* fDataPtr;
bool fMapped; // is the buffer object mapped via "glMapBuffer"?
bool fBound; // is the buffer object bound via "glBindBuffer"?
GrGLint fSize; // size in bytes
@@ -135,6 +157,32 @@
typedef GrFakeRefObj INHERITED;
};
+////////////////////////////////////////////////////////////////////////////////
+// TODO: when a framebuffer obj is bound the GL_SAMPLES query must return 0
+// TODO: GL_STENCIL_BITS must also be redirected to the framebuffer
+class GrFrameBufferObj : public GrFakeRefObj
+{
+public:
+ GrFrameBufferObj(GrGLuint ID)
+ : GrFakeRefObj(ID)
+ , fBound(false) {
+ }
+
+ void setBound() { fBound = true; }
+ void resetBound() { fBound = false; }
+ bool getBound() const { return fBound; }
+
+ virtual void deleteAction() SK_OVERRIDE {
+
+ this->setDeleted();
+ }
+
+protected:
+private:
+ bool fBound; // is this frame buffer currently bound via "glBindFramebuffer"?
+
+ typedef GrFakeRefObj INHERITED;
+};
////////////////////////////////////////////////////////////////////////////////
class GrShaderObj : public GrFakeRefObj
@@ -167,8 +215,7 @@
: GrFakeRefObj(ID)
, fInUse(false) {}
- void AttachShader(GrShaderObj *shader)
- {
+ void AttachShader(GrShaderObj *shader) {
shader->ref();
fShaders.push_back(shader);
}
@@ -185,7 +232,9 @@
this->setDeleted();
}
+ // TODO: this flag system won't work w/ multiple contexts!
void setInUse() { fInUse = true; }
+ void resetInUse() { fInUse = false; }
bool getInUse() const { return fInUse; }
protected:
@@ -203,9 +252,8 @@
class GrDebugGL
{
public:
- // TODO: merge findBuffer, findShader & findProgram??
- GrBufferObj *findBuffer(GrGLuint ID)
- {
+ // TODO: merge findBuffer, findFrameBuffer, findShader & findProgram??
+ GrBufferObj *findBuffer(GrGLuint ID) {
GrFakeRefObj *obj = this->findObject(ID);
if (NULL == obj) {
return NULL;
@@ -214,8 +262,16 @@
return reinterpret_cast<GrBufferObj *>(obj);
}
- GrShaderObj *findShader(GrGLuint ID)
- {
+ GrFrameBufferObj *findFrameBuffer(GrGLuint ID) {
+ GrFakeRefObj *obj = this->findObject(ID);
+ if (NULL == obj) {
+ return NULL;
+ }
+
+ return reinterpret_cast<GrFrameBufferObj *>(obj);
+ }
+
+ GrShaderObj *findShader(GrGLuint ID) {
GrFakeRefObj *obj = this->findObject(ID);
if (NULL == obj) {
return NULL;
@@ -224,8 +280,7 @@
return reinterpret_cast<GrShaderObj *>(obj);
}
- GrProgramObj *findProgram(GrGLuint ID)
- {
+ GrProgramObj *findProgram(GrGLuint ID) {
GrFakeRefObj *obj = this->findObject(ID);
if (NULL == obj) {
return NULL;
@@ -235,8 +290,7 @@
}
// TODO: merge createBuffer, createShader, createProgram??
- GrBufferObj *createBuffer()
- {
+ GrBufferObj *createBuffer() {
GrBufferObj *buffer = new GrBufferObj(++fNextID);
fObjects.push_back(buffer);
@@ -244,8 +298,15 @@
return buffer;
}
- GrShaderObj *createShader(GrGLenum type)
- {
+ GrFrameBufferObj *createFrameBuffer() {
+ GrFrameBufferObj *buffer = new GrFrameBufferObj(++fNextID);
+
+ fObjects.push_back(buffer);
+
+ return buffer;
+ }
+
+ GrShaderObj *createShader(GrGLenum type) {
GrShaderObj *shader = new GrShaderObj(++fNextID, type);
fObjects.push_back(shader);
@@ -253,8 +314,7 @@
return shader;
}
- GrProgramObj *createProgram()
- {
+ GrProgramObj *createProgram() {
GrProgramObj *program = new GrProgramObj(++fNextID);
fObjects.push_back(program);
@@ -262,8 +322,7 @@
return program;
}
- GrFakeRefObj *findObject(GrGLuint ID)
- {
+ GrFakeRefObj *findObject(GrGLuint ID) {
for (int i = 0; i < fObjects.count(); ++i) {
if (fObjects[i]->getID() == ID) {
// The application shouldn't be accessing objects
@@ -284,14 +343,97 @@
void setCurTextureUnit(GrGLuint curTextureUnit) { fCurTextureUnit = curTextureUnit; }
GrGLuint getCurTextureUnit() const { return fCurTextureUnit; }
- void setArrayBuffer(GrBufferObj *arrayBuffer) { fArrayBuffer = arrayBuffer; }
+ void setArrayBuffer(GrBufferObj *arrayBuffer) {
+ if (fArrayBuffer) {
+ // automatically break the binding of the old buffer
+ GrAlwaysAssert(fArrayBuffer->getBound());
+ fArrayBuffer->resetBound();
+
+ GrAlwaysAssert(!fArrayBuffer->getDeleted());
+ fArrayBuffer->unref();
+ }
+
+ fArrayBuffer = arrayBuffer;
+
+ if (fArrayBuffer) {
+ GrAlwaysAssert(!fArrayBuffer->getDeleted());
+ fArrayBuffer->ref();
+
+ GrAlwaysAssert(!fArrayBuffer->getBound());
+ fArrayBuffer->setBound();
+ }
+ }
GrBufferObj *getArrayBuffer() { return fArrayBuffer; }
- void setElementArrayBuffer(GrBufferObj *elementArrayBuffer) { fElementArrayBuffer = elementArrayBuffer; }
+ void setElementArrayBuffer(GrBufferObj *elementArrayBuffer) {
+ if (fElementArrayBuffer) {
+ // automatically break the binding of the old buffer
+ GrAlwaysAssert(fElementArrayBuffer->getBound());
+ fElementArrayBuffer->resetBound();
+
+ GrAlwaysAssert(!fElementArrayBuffer->getDeleted());
+ fElementArrayBuffer->unref();
+ }
+
+ fElementArrayBuffer = elementArrayBuffer;
+
+ if (fElementArrayBuffer) {
+ GrAlwaysAssert(!fElementArrayBuffer->getDeleted());
+ fElementArrayBuffer->ref();
+
+ GrAlwaysAssert(!fElementArrayBuffer->getBound());
+ fElementArrayBuffer->setBound();
+ }
+ }
+
GrBufferObj *getElementArrayBuffer() { return fElementArrayBuffer; }
- static GrDebugGL *getInstance()
- {
+ void setFrameBuffer(GrFrameBufferObj *frameBuffer) {
+ if (fFrameBuffer)
+ {
+ GrAlwaysAssert(fFrameBuffer->getBound());
+ fFrameBuffer->resetBound();
+
+ GrAlwaysAssert(!fFrameBuffer->getDeleted());
+ fFrameBuffer->unref();
+ }
+
+ fFrameBuffer = frameBuffer;
+
+ if (fFrameBuffer)
+ {
+ GrAlwaysAssert(!fFrameBuffer->getDeleted());
+ fFrameBuffer->ref();
+
+ GrAlwaysAssert(!fFrameBuffer->getBound());
+ fFrameBuffer->setBound();
+ }
+ }
+
+ GrFrameBufferObj *getFrameBuffer() { return fFrameBuffer; }
+
+ void useProgram(GrProgramObj *program) {
+ if (fProgram) {
+ GrAlwaysAssert(fProgram->getInUse());
+ fProgram->resetInUse();
+
+ GrAlwaysAssert(!fProgram->getDeleted());
+ fProgram->unref();
+ }
+
+ fProgram = program;
+
+ if (fProgram)
+ {
+ GrAlwaysAssert(!fProgram->getDeleted());
+ fProgram->ref();
+
+ GrAlwaysAssert(!fProgram->getInUse());
+ fProgram->setInUse();
+ }
+ }
+
+ static GrDebugGL *getInstance() {
// static GrDebugGL Obj;
return &Obj;
@@ -299,6 +441,8 @@
void report() const {
for (int i = 0; i < fObjects.count(); ++i) {
+ GrAlwaysAssert(0 == fObjects[i]->getRefCount());
+ GrAlwaysAssert(0 < fObjects[i]->getHighRefCount());
GrAlwaysAssert(fObjects[i]->getDeleted());
}
}
@@ -310,6 +454,8 @@
GrGLuint fCurTextureUnit;
GrBufferObj * fArrayBuffer;
GrBufferObj * fElementArrayBuffer;
+ GrFrameBufferObj *fFrameBuffer;
+ GrProgramObj * fProgram;
static int fNextID; // source for globally unique IDs
@@ -320,10 +466,11 @@
GrDebugGL()
: fMaxTextureUnits(kDefaultMaxTextureUnits)
- , fCurTextureUnit(0)
- , fArrayBuffer(NULL)
- , fElementArrayBuffer(NULL)
- {
+ , fCurTextureUnit(0)
+ , fArrayBuffer(NULL)
+ , fElementArrayBuffer(NULL)
+ , fFrameBuffer(NULL)
+ , fProgram(NULL) {
}
~GrDebugGL() {
@@ -333,8 +480,11 @@
delete fObjects[i];
}
fObjects.reset();
+
fArrayBuffer = NULL;
fElementArrayBuffer = NULL;
+ fFrameBuffer = NULL;
+ fProgram = NULL;
}
};
@@ -342,8 +492,7 @@
GrDebugGL GrDebugGL::Obj;
////////////////////////////////////////////////////////////////////////////////
-GrGLvoid GR_GL_FUNCTION_TYPE debugGLActiveTexture(GrGLenum texture)
-{
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLActiveTexture(GrGLenum texture) {
GrAlwaysAssert(0 <= texture);
// GrAlwaysAssert(texture < GrDebugGL::getInstance()->getMaxTextureUnits());
@@ -352,8 +501,7 @@
}
////////////////////////////////////////////////////////////////////////////////
-GrGLvoid GR_GL_FUNCTION_TYPE debugGLAttachShader(GrGLuint programID, GrGLuint shaderID)
-{
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLAttachShader(GrGLuint programID, GrGLuint shaderID) {
GrProgramObj *program = GrDebugGL::getInstance()->findProgram(programID);
GrAlwaysAssert(program);
@@ -371,8 +519,7 @@
GrGLvoid GR_GL_FUNCTION_TYPE debugGLBlendFunc(GrGLenum sfactor, GrGLenum dfactor) {}
////////////////////////////////////////////////////////////////////////////////
-GrGLvoid GR_GL_FUNCTION_TYPE debugGLBufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage)
-{
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLBufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage) {
GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || GR_GL_ELEMENT_ARRAY_BUFFER == target);
GrAlwaysAssert(size >= 0);
GrAlwaysAssert(GR_GL_STREAM_DRAW == usage || GR_GL_STATIC_DRAW == usage || GR_GL_DYNAMIC_DRAW == usage);
@@ -393,7 +540,7 @@
GrAlwaysAssert(buffer);
GrAlwaysAssert(buffer->getBound());
- buffer->allocate(size, data);
+ buffer->allocate(size, reinterpret_cast<const GrGLchar *>(data));
buffer->setUsage(usage);
}
@@ -458,17 +605,51 @@
GrGLvoid GR_GL_FUNCTION_TYPE debugGLUseProgram(GrGLuint programID) {
+ // A programID of 0 is legal
GrProgramObj *program = GrDebugGL::getInstance()->findProgram(programID);
- GrAlwaysAssert(program);
- program->setInUse();
+ GrDebugGL::getInstance()->useProgram(program);
}
+
GrGLvoid GR_GL_FUNCTION_TYPE debugGLVertexAttrib4fv(GrGLuint indx, const GrGLfloat* values) {}
GrGLvoid GR_GL_FUNCTION_TYPE debugGLVertexAttribPointer(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr) {}
GrGLvoid GR_GL_FUNCTION_TYPE debugGLViewport(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) {}
-GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindFramebuffer(GrGLenum target, GrGLuint framebuffer) {}
+
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindFramebuffer(GrGLenum target, GrGLuint frameBufferID) {
+
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+
+ // a frameBufferID of 0 is acceptable - it binds to the default frame buffer
+ GrFrameBufferObj *framebuffer = GrDebugGL::getInstance()->findFrameBuffer(frameBufferID);
+
+ GrDebugGL::getInstance()->setFrameBuffer(framebuffer);
+}
+
GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindRenderbuffer(GrGLenum target, GrGLuint renderbuffer) {}
-GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteFramebuffers(GrGLsizei n, const GrGLuint *framebuffers) {}
+
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteFramebuffers(GrGLsizei n, const GrGLuint *framebuffers) {
+
+ // first potentially unbind the buffers
+ if (GrDebugGL::getInstance()->getFrameBuffer()) {
+ for (int i = 0; i < n; ++i) {
+
+ if (framebuffers[i] == GrDebugGL::getInstance()->getFrameBuffer()->getID()) {
+ // this ID is the current frame buffer - rebind to the default
+ GrDebugGL::getInstance()->setFrameBuffer(NULL);
+ }
+ }
+ }
+
+ // then actually "delete" the buffers
+ for (int i = 0; i < n; ++i) {
+ GrFrameBufferObj *buffer = GrDebugGL::getInstance()->findFrameBuffer(framebuffers[i]);
+ GrAlwaysAssert(buffer);
+
+ GrAlwaysAssert(!buffer->getDeleted());
+ buffer->deleteAction();
+ }
+}
+
GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteRenderbuffers(GrGLsizei n, const GrGLuint *renderbuffers) {}
GrGLvoid GR_GL_FUNCTION_TYPE debugGLFramebufferRenderbuffer(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer) {}
GrGLvoid GR_GL_FUNCTION_TYPE debugGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
@@ -505,8 +686,6 @@
GrProgramObj *program = GrDebugGL::getInstance()->findProgram(programID);
GrAlwaysAssert(program);
- program->unref();
-
if (program->getRefCount()) {
// someone is still using this program so we can't delete it here
program->setMarkedForDeletion();
@@ -520,8 +699,6 @@
GrShaderObj *shader = GrDebugGL::getInstance()->findShader(shaderID);
GrAlwaysAssert(shader);
- shader->unref();
-
if (shader->getRefCount()) {
// someone is still using this shader so we can't delete it here
shader->setMarkedForDeletion();
@@ -547,6 +724,15 @@
}
}
+GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenFramebuffers(GrGLsizei n, GrGLuint* ids) {
+
+ for (int i = 0; i < n; ++i) {
+ GrFrameBufferObj *buffer = GrDebugGL::getInstance()->createFrameBuffer();
+ GrAlwaysAssert(buffer);
+ ids[i] = buffer->getID();
+ }
+}
+
// same delete function for all glDelete*(GLsize i, const GLuint*) except buffers
GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteIds(GrGLsizei n, const GrGLuint* ids) {}
@@ -560,30 +746,10 @@
switch (target) {
case GR_GL_ARRAY_BUFFER:
- if (GrDebugGL::getInstance()->getArrayBuffer()) {
- // automatically break the binding of the old buffer
- GrDebugGL::getInstance()->getArrayBuffer()->resetBound();
- }
- if (buffer) {
- GrAlwaysAssert(!buffer->getBound());
- }
GrDebugGL::getInstance()->setArrayBuffer(buffer);
- if (buffer) {
- buffer->setBound();
- }
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
- if (GrDebugGL::getInstance()->getElementArrayBuffer()) {
- // automatically break the binding of the old buffer
- GrDebugGL::getInstance()->getElementArrayBuffer()->resetBound();
- }
- if (buffer) {
- GrAlwaysAssert(!buffer->getBound());
- }
GrDebugGL::getInstance()->setElementArrayBuffer(buffer);
- if (buffer) {
- buffer->setBound();
- }
break;
default:
GrCrash("Unexpected target to glBindBuffer");
@@ -599,15 +765,11 @@
if (GrDebugGL::getInstance()->getArrayBuffer() &&
ids[i] == GrDebugGL::getInstance()->getArrayBuffer()->getID()) {
// this ID is the current array buffer
- GrAlwaysAssert(GrDebugGL::getInstance()->getArrayBuffer()->getBound());
- GrDebugGL::getInstance()->getArrayBuffer()->resetBound();
GrDebugGL::getInstance()->setArrayBuffer(NULL);
}
if (GrDebugGL::getInstance()->getElementArrayBuffer() &&
ids[i] == GrDebugGL::getInstance()->getElementArrayBuffer()->getID()) {
// this ID is the current element array buffer
- GrAlwaysAssert(GrDebugGL::getInstance()->getElementArrayBuffer()->getBound());
- GrDebugGL::getInstance()->getElementArrayBuffer()->resetBound();
GrDebugGL::getInstance()->setElementArrayBuffer(NULL);
}
}
@@ -745,8 +907,11 @@
case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
*params = 8;
break;
+ case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
+ *params = kDefaultMaxVertexUniformVectors;
+ break;
case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
- *params = 16;
+ *params = kDefaultMaxFragmentUniformVectors;
break;
case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
*params = 16 * 4;
@@ -766,7 +931,10 @@
*params = 32;
break;
case GR_GL_MAX_VERTEX_ATTRIBS:
- *params = 16;
+ *params = kDefaultMaxVertexAttribs;
+ break;
+ case GR_GL_MAX_VARYING_VECTORS:
+ *params = kDefaultMaxVaryingVectors;
break;
case GR_GL_MAX_TEXTURE_UNITS:
*params = GrDebugGL::getInstance()->getMaxTextureUnits();
@@ -983,7 +1151,7 @@
interface->fDeleteRenderbuffers = debugGLDeleteRenderbuffers;
interface->fFramebufferRenderbuffer = debugGLFramebufferRenderbuffer;
interface->fFramebufferTexture2D = debugGLFramebufferTexture2D;
- interface->fGenFramebuffers = debugGLGenIds;
+ interface->fGenFramebuffers = debugGLGenFramebuffers;
interface->fGenRenderbuffers = debugGLGenIds;
interface->fGetFramebufferAttachmentParameteriv = debugGLGetFramebufferAttachmentParameteriv;
interface->fGetRenderbufferParameteriv = debugGLGetRenderbufferParameteriv;
diff --git a/src/gpu/gl/GrGpuGLShaders.cpp b/src/gpu/gl/GrGpuGLShaders.cpp
index db7e3a7..cb156f7 100644
--- a/src/gpu/gl/GrGpuGLShaders.cpp
+++ b/src/gpu/gl/GrGpuGLShaders.cpp
@@ -125,6 +125,7 @@
void GrGpuGLShaders::abandonResources(){
INHERITED::abandonResources();
fProgramCache->abandon();
+ fHWProgramID = 0;
}
void GrGpuGLShaders::DeleteProgram(const GrGLInterface* gl,
@@ -326,6 +327,13 @@
}
GrGpuGLShaders::~GrGpuGLShaders() {
+
+ if (fProgramData && 0 != fHWProgramID) {
+ // detach the current program so there is no confusion on OpenGL's part
+ // that we want it to be deleted
+ SkASSERT(fHWProgramID == fProgramData->fProgramID);
+ GL_CALL(UseProgram(0));
+ }
delete fProgramCache;
}
diff --git a/src/gpu/gl/SkGLContext.cpp b/src/gpu/gl/SkGLContext.cpp
index 525afe8..9b197ac 100644
--- a/src/gpu/gl/SkGLContext.cpp
+++ b/src/gpu/gl/SkGLContext.cpp
@@ -13,6 +13,11 @@
}
SkGLContext::~SkGLContext() {
+
+ if (fGL) {
+ SK_GL(*this, DeleteFramebuffers(1, &fFBO));
+ }
+
SkSafeUnref(fGL);
}