aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/gpu/gl/debug
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2016-03-30 18:56:19 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-30 18:56:20 -0700
commit3724e574a744491b7cfb8187ac865a70ef3d4528 (patch)
treeeb3dd729cbc0adef5ce2b4a2fa048fe21baeb35a /tools/gpu/gl/debug
parent2238c9dbca4b791edc512957728a18ce14d55912 (diff)
Move SkGLContext and some GrGLInterface implementations to skgputest module
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1815823002 CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot Committed: https://skia.googlesource.com/skia/+/fe3456cb006110d045b26ff3f8681b893a757b58 Review URL: https://codereview.chromium.org/1815823002
Diffstat (limited to 'tools/gpu/gl/debug')
-rw-r--r--tools/gpu/gl/debug/DebugGLContext.cpp1256
-rw-r--r--tools/gpu/gl/debug/DebugGLContext.h17
-rw-r--r--tools/gpu/gl/debug/GrBufferObj.cpp31
-rw-r--r--tools/gpu/gl/debug/GrBufferObj.h76
-rw-r--r--tools/gpu/gl/debug/GrFBBindableObj.h88
-rw-r--r--tools/gpu/gl/debug/GrFakeRefObj.h86
-rw-r--r--tools/gpu/gl/debug/GrFrameBufferObj.cpp67
-rw-r--r--tools/gpu/gl/debug/GrFrameBufferObj.h68
-rw-r--r--tools/gpu/gl/debug/GrProgramObj.cpp27
-rw-r--r--tools/gpu/gl/debug/GrProgramObj.h43
-rw-r--r--tools/gpu/gl/debug/GrRenderBufferObj.h40
-rw-r--r--tools/gpu/gl/debug/GrShaderObj.cpp14
-rw-r--r--tools/gpu/gl/debug/GrShaderObj.h36
-rw-r--r--tools/gpu/gl/debug/GrTextureObj.cpp14
-rw-r--r--tools/gpu/gl/debug/GrTextureObj.h57
-rw-r--r--tools/gpu/gl/debug/GrTextureUnitObj.cpp31
-rw-r--r--tools/gpu/gl/debug/GrTextureUnitObj.h44
-rw-r--r--tools/gpu/gl/debug/GrVertexArrayObj.h21
18 files changed, 2016 insertions, 0 deletions
diff --git a/tools/gpu/gl/debug/DebugGLContext.cpp b/tools/gpu/gl/debug/DebugGLContext.cpp
new file mode 100644
index 0000000000..f4cbbea680
--- /dev/null
+++ b/tools/gpu/gl/debug/DebugGLContext.cpp
@@ -0,0 +1,1256 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "DebugGLContext.h"
+
+#include "GrBufferObj.h"
+#include "GrFrameBufferObj.h"
+#include "GrProgramObj.h"
+#include "GrRenderBufferObj.h"
+#include "GrShaderObj.h"
+#include "GrTextureObj.h"
+#include "GrTextureUnitObj.h"
+#include "GrVertexArrayObj.h"
+#include "gl/GrGLTestInterface.h"
+
+#include "SkMutex.h"
+
+namespace {
+
+// Helper macro to make creating an object (where you need to get back a derived type) easier
+#define CREATE(className, classEnum) \
+ reinterpret_cast<className *>(this->createObj(classEnum))
+
+// Helper macro to make creating an object (where you need to get back a derived type) easier
+#define FIND(id, className, classEnum) \
+ reinterpret_cast<className *>(this->findObject(id, classEnum))
+
+class DebugInterface : public GrGLTestInterface {
+public:
+ DebugInterface()
+ : fCurrGenericID(0)
+ , fCurrTextureUnit(0)
+ , fArrayBuffer(nullptr)
+ , fElementArrayBuffer(nullptr)
+ , fVertexArray(nullptr)
+ , fPackRowLength(0)
+ , fUnpackRowLength(0)
+ , fPackAlignment(4)
+ , fFrameBuffer(nullptr)
+ , fRenderBuffer(nullptr)
+ , fProgram(nullptr)
+ , fAbandoned(false) {
+ for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+ fTextureUnits[i] =
+ reinterpret_cast<GrTextureUnitObj*>(this->createObj(kTextureUnit_ObjTypes));
+ fTextureUnits[i]->ref();
+ fTextureUnits[i]->setNumber(i);
+ }
+ this->init(kGL_GrGLStandard);
+ }
+
+ ~DebugInterface() override {
+ // unref & delete the texture units first so they don't show up on the leak report
+ for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+ fTextureUnits[i]->unref();
+ fTextureUnits[i]->deleteAction();
+ }
+ for (int i = 0; i < fObjects.count(); ++i) {
+ delete fObjects[i];
+ }
+ fObjects.reset();
+
+ fArrayBuffer = nullptr;
+ fElementArrayBuffer = nullptr;
+ fVertexArray = nullptr;
+
+ this->report();
+ }
+
+ void abandon() const override { fAbandoned = true; }
+
+ GrGLvoid activeTexture(GrGLenum texture) override {
+ // Ganesh offsets the texture unit indices
+ texture -= GR_GL_TEXTURE0;
+ GrAlwaysAssert(texture < kDefaultMaxTextureUnits);
+ fCurrTextureUnit = texture;
+ }
+
+ GrGLvoid attachShader(GrGLuint programID, GrGLuint shaderID) override {
+
+ GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+ GrAlwaysAssert(program);
+
+ GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
+ GrAlwaysAssert(shader);
+
+ program->AttachShader(shader);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ GrGLvoid bindTexture(GrGLenum target, GrGLuint textureID) override {
+ GrAlwaysAssert(target == GR_GL_TEXTURE_2D ||
+ target == GR_GL_TEXTURE_RECTANGLE ||
+ target == GR_GL_TEXTURE_EXTERNAL);
+
+ // a textureID of 0 is acceptable - it binds to the default texture target
+ GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
+
+ this->setTexture(texture);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data,
+ GrGLenum usage) override {
+ 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);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ default:
+ SkFAIL("Unexpected target to glBufferData");
+ break;
+ }
+
+ GrAlwaysAssert(buffer);
+ GrAlwaysAssert(buffer->getBound());
+
+ buffer->allocate(size, reinterpret_cast<const GrGLchar *>(data));
+ buffer->setUsage(usage);
+ }
+
+
+ GrGLvoid pixelStorei(GrGLenum pname, GrGLint param) override {
+
+ switch (pname) {
+ case GR_GL_UNPACK_ROW_LENGTH:
+ fUnpackRowLength = param;
+ break;
+ case GR_GL_PACK_ROW_LENGTH:
+ fPackRowLength = param;
+ break;
+ case GR_GL_UNPACK_ALIGNMENT:
+ break;
+ case GR_GL_PACK_ALIGNMENT:
+ fPackAlignment = param;
+ break;
+ default:
+ GrAlwaysAssert(false);
+ break;
+ }
+ }
+
+ GrGLvoid readPixels(GrGLint x,
+ GrGLint y,
+ GrGLsizei width,
+ GrGLsizei height,
+ GrGLenum format,
+ GrGLenum type,
+ GrGLvoid* pixels) override {
+
+ GrGLint pixelsInRow = width;
+ if (fPackRowLength > 0) {
+ pixelsInRow = fPackRowLength;
+ }
+
+ GrGLint componentsPerPixel = 0;
+
+ switch (format) {
+ case GR_GL_RGBA:
+ // fallthrough
+ case GR_GL_BGRA:
+ componentsPerPixel = 4;
+ break;
+ case GR_GL_RGB:
+ componentsPerPixel = 3;
+ break;
+ case GR_GL_RED:
+ componentsPerPixel = 1;
+ break;
+ default:
+ GrAlwaysAssert(false);
+ break;
+ }
+
+ GrGLint alignment = fPackAlignment;
+
+ GrGLint componentSize = 0; // size (in bytes) of a single component
+
+ switch (type) {
+ case GR_GL_UNSIGNED_BYTE:
+ componentSize = 1;
+ break;
+ default:
+ GrAlwaysAssert(false);
+ break;
+ }
+
+ GrGLint rowStride = 0; // number of components (not bytes) to skip
+ if (componentSize >= alignment) {
+ rowStride = componentsPerPixel * pixelsInRow;
+ } else {
+ float fTemp =
+ sk_float_ceil(componentSize * componentsPerPixel * pixelsInRow /
+ static_cast<float>(alignment));
+ rowStride = static_cast<GrGLint>(alignment * fTemp / componentSize);
+ }
+
+ GrGLchar *scanline = static_cast<GrGLchar *>(pixels);
+ for (int y = 0; y < height; ++y) {
+ memset(scanline, 0, componentsPerPixel * componentSize * width);
+ scanline += rowStride;
+ }
+ }
+
+ GrGLvoid useProgram(GrGLuint programID) override {
+
+ // A programID of 0 is legal
+ GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+
+ this->useProgram(program);
+ }
+
+ GrGLvoid bindFramebuffer(GrGLenum target, GrGLuint frameBufferID) override {
+
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target ||
+ GR_GL_READ_FRAMEBUFFER == target ||
+ GR_GL_DRAW_FRAMEBUFFER);
+
+ // a frameBufferID of 0 is acceptable - it binds to the default
+ // frame buffer
+ GrFrameBufferObj *frameBuffer = FIND(frameBufferID, GrFrameBufferObj,
+ kFrameBuffer_ObjTypes);
+
+ this->setFrameBuffer(frameBuffer);
+ }
+
+ GrGLvoid bindRenderbuffer(GrGLenum target, GrGLuint renderBufferID) override {
+
+ GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
+
+ // a renderBufferID of 0 is acceptable - it unbinds the bound render buffer
+ GrRenderBufferObj *renderBuffer = FIND(renderBufferID, GrRenderBufferObj,
+ kRenderBuffer_ObjTypes);
+
+ this->setRenderBuffer(renderBuffer);
+ }
+
+ GrGLvoid deleteTextures(GrGLsizei n, const GrGLuint* textures) override {
+ // first potentially unbind the texture
+ for (unsigned int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+ GrTextureUnitObj *pTU = this->getTextureUnit(i);
+
+ if (pTU->getTexture()) {
+ for (int j = 0; j < n; ++j) {
+
+ if (textures[j] == pTU->getTexture()->getID()) {
+ // this ID is the current texture - revert the binding to 0
+ pTU->setTexture(nullptr);
+ }
+ }
+ }
+ }
+
+ // TODO: fuse the following block with DeleteRenderBuffers?
+ // Open GL will remove a deleted render buffer from the active
+ // frame buffer but not from any other frame buffer
+ if (this->getFrameBuffer()) {
+
+ GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
+
+ for (int i = 0; i < n; ++i) {
+
+ if (frameBuffer->getColor() &&
+ textures[i] == frameBuffer->getColor()->getID()) {
+ frameBuffer->setColor(nullptr);
+ }
+ if (frameBuffer->getDepth() &&
+ textures[i] == frameBuffer->getDepth()->getID()) {
+ frameBuffer->setDepth(nullptr);
+ }
+ if (frameBuffer->getStencil() &&
+ textures[i] == frameBuffer->getStencil()->getID()) {
+ frameBuffer->setStencil(nullptr);
+ }
+ }
+ }
+
+ // then actually "delete" the buffers
+ for (int i = 0; i < n; ++i) {
+ GrTextureObj *buffer = FIND(textures[i], GrTextureObj, kTexture_ObjTypes);
+ GrAlwaysAssert(buffer);
+
+ // OpenGL gives no guarantees if a texture is deleted while attached to
+ // something other than the currently bound frame buffer
+ GrAlwaysAssert(!buffer->getBound());
+
+ GrAlwaysAssert(!buffer->getDeleted());
+ buffer->deleteAction();
+ }
+
+ }
+
+ GrGLvoid deleteFramebuffers(GrGLsizei n, const GrGLuint *frameBuffers) override {
+
+ // first potentially unbind the buffers
+ if (this->getFrameBuffer()) {
+ for (int i = 0; i < n; ++i) {
+
+ if (frameBuffers[i] ==
+ this->getFrameBuffer()->getID()) {
+ // this ID is the current frame buffer - rebind to the default
+ this->setFrameBuffer(nullptr);
+ }
+ }
+ }
+
+ // then actually "delete" the buffers
+ for (int i = 0; i < n; ++i) {
+ GrFrameBufferObj *buffer = FIND(frameBuffers[i], GrFrameBufferObj,
+ kFrameBuffer_ObjTypes);
+ GrAlwaysAssert(buffer);
+
+ GrAlwaysAssert(!buffer->getDeleted());
+ buffer->deleteAction();
+ }
+ }
+
+ GrGLvoid deleteRenderbuffers(GrGLsizei n,const GrGLuint *renderBuffers) override {
+
+ // first potentially unbind the buffers
+ if (this->getRenderBuffer()) {
+ for (int i = 0; i < n; ++i) {
+
+ if (renderBuffers[i] ==
+ this->getRenderBuffer()->getID()) {
+ // this ID is the current render buffer - make no
+ // render buffer be bound
+ this->setRenderBuffer(nullptr);
+ }
+ }
+ }
+
+ // TODO: fuse the following block with DeleteTextures?
+ // Open GL will remove a deleted render buffer from the active frame
+ // buffer but not from any other frame buffer
+ if (this->getFrameBuffer()) {
+
+ GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
+
+ for (int i = 0; i < n; ++i) {
+
+ if (frameBuffer->getColor() &&
+ renderBuffers[i] == frameBuffer->getColor()->getID()) {
+ frameBuffer->setColor(nullptr);
+ }
+ if (frameBuffer->getDepth() &&
+ renderBuffers[i] == frameBuffer->getDepth()->getID()) {
+ frameBuffer->setDepth(nullptr);
+ }
+ if (frameBuffer->getStencil() &&
+ renderBuffers[i] == frameBuffer->getStencil()->getID()) {
+ frameBuffer->setStencil(nullptr);
+ }
+ }
+ }
+
+ // then actually "delete" the buffers
+ for (int i = 0; i < n; ++i) {
+ GrRenderBufferObj *buffer = FIND(renderBuffers[i], GrRenderBufferObj,
+ kRenderBuffer_ObjTypes);
+ GrAlwaysAssert(buffer);
+
+ // OpenGL gives no guarantees if a render buffer is deleted
+ // while attached to something other than the currently
+ // bound frame buffer
+ GrAlwaysAssert(!buffer->getColorBound());
+ GrAlwaysAssert(!buffer->getDepthBound());
+ // However, at GrContext destroy time we release all GrRsources and so stencil buffers
+ // may get deleted before FBOs that refer to them.
+ //GrAlwaysAssert(!buffer->getStencilBound());
+
+ GrAlwaysAssert(!buffer->getDeleted());
+ buffer->deleteAction();
+ }
+ }
+
+ GrGLvoid framebufferRenderbuffer(GrGLenum target,
+ GrGLenum attachment,
+ GrGLenum renderbuffertarget,
+ GrGLuint renderBufferID) override {
+
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+ GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
+ GR_GL_DEPTH_ATTACHMENT == attachment ||
+ GR_GL_STENCIL_ATTACHMENT == attachment);
+ GrAlwaysAssert(GR_GL_RENDERBUFFER == renderbuffertarget);
+
+ GrFrameBufferObj *framebuffer = this->getFrameBuffer();
+ // A render buffer cannot be attached to the default framebuffer
+ GrAlwaysAssert(framebuffer);
+
+ // a renderBufferID of 0 is acceptable - it unbinds the current
+ // render buffer
+ GrRenderBufferObj *renderbuffer = FIND(renderBufferID, GrRenderBufferObj,
+ kRenderBuffer_ObjTypes);
+
+ switch (attachment) {
+ case GR_GL_COLOR_ATTACHMENT0:
+ framebuffer->setColor(renderbuffer);
+ break;
+ case GR_GL_DEPTH_ATTACHMENT:
+ framebuffer->setDepth(renderbuffer);
+ break;
+ case GR_GL_STENCIL_ATTACHMENT:
+ framebuffer->setStencil(renderbuffer);
+ break;
+ default:
+ GrAlwaysAssert(false);
+ break;
+ };
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ GrGLvoid framebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget,
+ GrGLuint textureID, GrGLint level) override {
+
+ GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+ GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
+ GR_GL_DEPTH_ATTACHMENT == attachment ||
+ GR_GL_STENCIL_ATTACHMENT == attachment);
+ GrAlwaysAssert(GR_GL_TEXTURE_2D == textarget);
+
+ GrFrameBufferObj *framebuffer = this->getFrameBuffer();
+ // A texture cannot be attached to the default framebuffer
+ GrAlwaysAssert(framebuffer);
+
+ // A textureID of 0 is allowed - it unbinds the currently bound texture
+ GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
+ if (texture) {
+ // The texture shouldn't be bound to a texture unit - this
+ // could lead to a feedback loop
+ GrAlwaysAssert(!texture->getBound());
+ }
+
+ GrAlwaysAssert(0 == level);
+
+ switch (attachment) {
+ case GR_GL_COLOR_ATTACHMENT0:
+ framebuffer->setColor(texture);
+ break;
+ case GR_GL_DEPTH_ATTACHMENT:
+ framebuffer->setDepth(texture);
+ break;
+ case GR_GL_STENCIL_ATTACHMENT:
+ framebuffer->setStencil(texture);
+ break;
+ default:
+ GrAlwaysAssert(false);
+ break;
+ };
+ }
+
+ GrGLuint createProgram() override {
+
+ GrProgramObj *program = CREATE(GrProgramObj, kProgram_ObjTypes);
+
+ return program->getID();
+ }
+
+ GrGLuint createShader(GrGLenum type) override {
+
+ GrAlwaysAssert(GR_GL_VERTEX_SHADER == type ||
+ GR_GL_FRAGMENT_SHADER == type);
+
+ GrShaderObj *shader = CREATE(GrShaderObj, kShader_ObjTypes);
+ shader->setType(type);
+
+ return shader->getID();
+ }
+
+ GrGLenum checkFramebufferStatus(GrGLenum target) override { return GR_GL_FRAMEBUFFER_COMPLETE; }
+
+ GrGLvoid deleteProgram(GrGLuint programID) override {
+
+ GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+ GrAlwaysAssert(program);
+
+ if (program->getRefCount()) {
+ // someone is still using this program so we can't delete it here
+ program->setMarkedForDeletion();
+ } else {
+ program->deleteAction();
+ }
+ }
+
+ GrGLvoid deleteShader(GrGLuint shaderID) override {
+
+ GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
+ GrAlwaysAssert(shader);
+
+ if (shader->getRefCount()) {
+ // someone is still using this shader so we can't delete it here
+ shader->setMarkedForDeletion();
+ } else {
+ shader->deleteAction();
+ }
+ }
+
+ GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override {
+ this->genObjs(kBuffer_ObjTypes, n, ids);
+ }
+
+ GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint* ids) override {
+ this->genObjs(kFrameBuffer_ObjTypes, n, ids);
+ }
+
+ GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint* ids) override {
+ this->genObjs(kRenderBuffer_ObjTypes, n, ids);
+ }
+
+ GrGLvoid genTextures(GrGLsizei n, GrGLuint* ids) override {
+ this->genObjs(kTexture_ObjTypes, n, ids);
+ }
+
+ GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint* ids) override {
+ this->genObjs(kVertexArray_ObjTypes, n, ids);
+ }
+
+ GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); }
+
+ GrGLenum getError() override { return GR_GL_NO_ERROR; }
+
+ GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override {
+ // TODO: remove from Ganesh the #defines for gets we don't use.
+ // We would like to minimize gets overall due to performance issues
+ switch (pname) {
+ case GR_GL_CONTEXT_PROFILE_MASK:
+ *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+ break;
+ case GR_GL_STENCIL_BITS:
+ *params = 8;
+ break;
+ case GR_GL_SAMPLES:
+ *params = 1;
+ break;
+ case GR_GL_FRAMEBUFFER_BINDING:
+ *params = 0;
+ break;
+ case GR_GL_VIEWPORT:
+ params[0] = 0;
+ params[1] = 0;
+ params[2] = 800;
+ params[3] = 600;
+ break;
+ case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
+ case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
+ case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *params = 8;
+ break;
+ case GR_GL_MAX_TEXTURE_COORDS:
+ *params = 8;
+ break;
+ case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
+ *params = kDefaultMaxVertexUniformVectors;
+ break;
+ case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ *params = kDefaultMaxFragmentUniformVectors;
+ break;
+ case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+ *params = 16 * 4;
+ break;
+ case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *params = 0;
+ break;
+ case GR_GL_COMPRESSED_TEXTURE_FORMATS:
+ break;
+ case GR_GL_MAX_TEXTURE_SIZE:
+ *params = 8192;
+ break;
+ case GR_GL_MAX_RENDERBUFFER_SIZE:
+ *params = 8192;
+ break;
+ case GR_GL_MAX_SAMPLES:
+ *params = 32;
+ break;
+ case GR_GL_MAX_VERTEX_ATTRIBS:
+ *params = kDefaultMaxVertexAttribs;
+ break;
+ case GR_GL_MAX_VARYING_VECTORS:
+ *params = kDefaultMaxVaryingVectors;
+ break;
+ case GR_GL_NUM_EXTENSIONS: {
+ GrGLint i = 0;
+ while (kExtensions[i++]);
+ *params = i;
+ break;
+ }
+ default:
+ SkFAIL("Unexpected pname to GetIntegerv");
+ }
+ }
+
+ GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override {
+ val[0] = val[1] = 0.5f;
+ }
+
+ GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override {
+ this->getShaderOrProgramiv(program, pname, params);
+ }
+
+ GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length,
+ char* infolog) override {
+ this->getInfoLog(program, bufsize, length, infolog);
+ }
+
+ GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override {
+ switch (pname) {
+ case GR_GL_CURRENT_QUERY:
+ *params = 0;
+ break;
+ case GR_GL_QUERY_COUNTER_BITS:
+ *params = 32;
+ break;
+ default:
+ SkFAIL("Unexpected pname passed GetQueryiv.");
+ }
+ }
+
+ GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override {
+ this->queryResult(id, pname, params);
+ }
+
+ GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override {
+ this->queryResult(id, pname, params);
+ }
+
+ GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override {
+ this->queryResult(id, pname, params);
+ }
+
+ GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override {
+ this->queryResult(id, pname, params);
+ }
+
+ GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override {
+ this->getShaderOrProgramiv(shader, pname, params);
+ }
+
+ GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length,
+ char* infolog) override {
+ this->getInfoLog(shader, bufsize, length, infolog);
+ }
+
+ const GrGLubyte* getString(GrGLenum name) override {
+ switch (name) {
+ case GR_GL_EXTENSIONS:
+ return CombinedExtensionString();
+ case GR_GL_VERSION:
+ return (const GrGLubyte*)"4.0 Debug GL";
+ case GR_GL_SHADING_LANGUAGE_VERSION:
+ return (const GrGLubyte*)"4.20.8 Debug GLSL";
+ case GR_GL_VENDOR:
+ return (const GrGLubyte*)"Debug Vendor";
+ case GR_GL_RENDERER:
+ return (const GrGLubyte*)"The Debug (Non-)Renderer";
+ default:
+ SkFAIL("Unexpected name passed to GetString");
+ return nullptr;
+ }
+ }
+
+ const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override {
+ switch (name) {
+ case GR_GL_EXTENSIONS: {
+ GrGLint count;
+ this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count);
+ if ((GrGLint)i <= count) {
+ return (const GrGLubyte*) kExtensions[i];
+ } else {
+ return nullptr;
+ }
+ }
+ default:
+ SkFAIL("Unexpected name passed to GetStringi");
+ return nullptr;
+ }
+ }
+
+ GrGLvoid getTexLevelParameteriv(GrGLenum target, GrGLint level, GrGLenum pname,
+ GrGLint* params) override {
+ // we used to use this to query stuff about externally created textures,
+ // now we just require clients to tell us everything about the texture.
+ SkFAIL("Should never query texture parameters.");
+ }
+
+ GrGLvoid deleteVertexArrays(GrGLsizei n, const GrGLuint* ids) override {
+ for (GrGLsizei i = 0; i < n; ++i) {
+ GrVertexArrayObj* array = FIND(ids[i], GrVertexArrayObj, kVertexArray_ObjTypes);
+ GrAlwaysAssert(array);
+
+ // Deleting the current vertex array binds object 0
+ if (this->getVertexArray() == array) {
+ this->setVertexArray(nullptr);
+ }
+
+ if (array->getRefCount()) {
+ // someone is still using this vertex array so we can't delete it here
+ array->setMarkedForDeletion();
+ } else {
+ array->deleteAction();
+ }
+ }
+ }
+
+ GrGLvoid bindVertexArray(GrGLuint id) override {
+ GrVertexArrayObj* array = FIND(id, GrVertexArrayObj, kVertexArray_ObjTypes);
+ GrAlwaysAssert((0 == id) || array);
+ this->setVertexArray(array);
+ }
+
+ GrGLvoid bindBuffer(GrGLenum target, GrGLuint bufferID) override {
+ GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+ GrBufferObj *buffer = FIND(bufferID, GrBufferObj, kBuffer_ObjTypes);
+ // 0 is a permissible bufferID - it unbinds the current buffer
+
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ this->setArrayBuffer(buffer);
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ this->setElementArrayBuffer(buffer);
+ break;
+ default:
+ SkFAIL("Unexpected target to glBindBuffer");
+ break;
+ }
+ }
+
+ // deleting a bound buffer has the side effect of binding 0
+ GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override {
+ // first potentially unbind the buffers
+ for (int i = 0; i < n; ++i) {
+
+ if (this->getArrayBuffer() &&
+ ids[i] == this->getArrayBuffer()->getID()) {
+ // this ID is the current array buffer
+ this->setArrayBuffer(nullptr);
+ }
+ if (this->getElementArrayBuffer() &&
+ ids[i] == this->getElementArrayBuffer()->getID()) {
+ // this ID is the current element array buffer
+ this->setElementArrayBuffer(nullptr);
+ }
+ }
+
+ // then actually "delete" the buffers
+ for (int i = 0; i < n; ++i) {
+ GrBufferObj *buffer = FIND(ids[i], GrBufferObj, kBuffer_ObjTypes);
+ GrAlwaysAssert(buffer);
+
+ GrAlwaysAssert(!buffer->getDeleted());
+ buffer->deleteAction();
+ }
+ }
+
+ // map a buffer to the caller's address space
+ GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length,
+ GrGLbitfield access) override {
+ GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+ GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+ // We only expect read access and we expect that the buffer or range is always invalidated.
+ GrAlwaysAssert(!SkToBool(GR_GL_MAP_READ_BIT & access));
+ GrAlwaysAssert((GR_GL_MAP_INVALIDATE_BUFFER_BIT | GR_GL_MAP_INVALIDATE_RANGE_BIT) & access);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ default:
+ SkFAIL("Unexpected target to glMapBufferRange");
+ break;
+ }
+
+ if (buffer) {
+ GrAlwaysAssert(offset >= 0 && offset + length <= buffer->getSize());
+ GrAlwaysAssert(!buffer->getMapped());
+ buffer->setMapped(offset, length);
+ return buffer->getDataPtr() + offset;
+ }
+
+ GrAlwaysAssert(false);
+ return nullptr; // no buffer bound to the target
+ }
+
+ GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override {
+ GrAlwaysAssert(GR_GL_WRITE_ONLY == access);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ default:
+ SkFAIL("Unexpected target to glMapBuffer");
+ break;
+ }
+
+ return this->mapBufferRange(target, 0, buffer->getSize(),
+ GR_GL_MAP_WRITE_BIT | GR_GL_MAP_INVALIDATE_BUFFER_BIT);
+ }
+
+ // remove a buffer from the caller's address space
+ // TODO: check if the "access" method from "glMapBuffer" was honored
+ GrGLboolean unmapBuffer(GrGLenum target) override {
+ GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+ GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ default:
+ SkFAIL("Unexpected target to glUnmapBuffer");
+ break;
+ }
+
+ if (buffer) {
+ GrAlwaysAssert(buffer->getMapped());
+ buffer->resetMapped();
+ return GR_GL_TRUE;
+ }
+
+ GrAlwaysAssert(false);
+ return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
+ }
+
+ GrGLvoid flushMappedBufferRange(GrGLenum target, GrGLintptr offset,
+ GrGLsizeiptr length) override {
+ GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+ GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ default:
+ SkFAIL("Unexpected target to glUnmapBuffer");
+ break;
+ }
+
+ if (buffer) {
+ GrAlwaysAssert(buffer->getMapped());
+ GrAlwaysAssert(offset >= 0 && (offset + length) <= buffer->getMappedLength());
+ } else {
+ GrAlwaysAssert(false);
+ }
+ }
+
+ GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum value, GrGLint* params) override {
+
+ GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+ GR_GL_ELEMENT_ARRAY_BUFFER == target);
+ GrAlwaysAssert(GR_GL_BUFFER_SIZE == value ||
+ GR_GL_BUFFER_USAGE == value);
+
+ GrBufferObj *buffer = nullptr;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buffer = this->getArrayBuffer();
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buffer = this->getElementArrayBuffer();
+ break;
+ }
+
+ GrAlwaysAssert(buffer);
+
+ switch (value) {
+ case GR_GL_BUFFER_MAPPED:
+ *params = GR_GL_FALSE;
+ if (buffer)
+ *params = buffer->getMapped() ? GR_GL_TRUE : GR_GL_FALSE;
+ break;
+ case GR_GL_BUFFER_SIZE:
+ *params = 0;
+ if (buffer)
+ *params = SkToInt(buffer->getSize());
+ break;
+ case GR_GL_BUFFER_USAGE:
+ *params = GR_GL_STATIC_DRAW;
+ if (buffer)
+ *params = buffer->getUsage();
+ break;
+ default:
+ SkFAIL("Unexpected value to glGetBufferParamateriv");
+ break;
+ }
+ }
+
+private:
+ // 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;
+
+ // the OpenGLES 2.0 spec says this must be >= 2
+ static const GrGLint kDefaultMaxTextureUnits = 8;
+
+ static const char* kExtensions[];
+
+ GrGLuint fCurrGenericID;
+ GrGLuint fCurrTextureUnit;
+ GrTextureUnitObj* fTextureUnits[kDefaultMaxTextureUnits];
+ GrBufferObj* fArrayBuffer;
+ GrBufferObj* fElementArrayBuffer;
+ GrVertexArrayObj* fVertexArray;
+ GrGLint fPackRowLength;
+ GrGLint fUnpackRowLength;
+ GrGLint fPackAlignment;
+ GrFrameBufferObj* fFrameBuffer;
+ GrRenderBufferObj* fRenderBuffer;
+ GrProgramObj* fProgram;
+ mutable bool fAbandoned;
+ // global store of all objects
+ SkTArray<GrFakeRefObj *> fObjects;
+
+ static const GrGLubyte* CombinedExtensionString() {
+ static SkString gExtString;
+ static SkMutex gMutex;
+ gMutex.acquire();
+ if (0 == gExtString.size()) {
+ int i = 0;
+ while (kExtensions[i]) {
+ if (i > 0) {
+ gExtString.append(" ");
+ }
+ gExtString.append(kExtensions[i]);
+ ++i;
+ }
+ }
+ gMutex.release();
+ return (const GrGLubyte*) gExtString.c_str();
+ }
+
+ GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) {
+ for (int i = 0; i < n; ++i) {
+ ids[i] = ++fCurrGenericID;
+ }
+ }
+
+ GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length,
+ char* infolog) {
+ if (length) {
+ *length = 0;
+ }
+ if (bufsize > 0) {
+ *infolog = 0;
+ }
+ }
+
+ GrGLvoid getShaderOrProgramiv(GrGLuint object, GrGLenum pname, GrGLint* params) {
+ switch (pname) {
+ case GR_GL_LINK_STATUS: // fallthru
+ case GR_GL_COMPILE_STATUS:
+ *params = GR_GL_TRUE;
+ break;
+ case GR_GL_INFO_LOG_LENGTH:
+ *params = 0;
+ break;
+ // we don't expect any other pnames
+ default:
+ SkFAIL("Unexpected pname to GetProgramiv");
+ break;
+ }
+ }
+
+ template <typename T>
+ void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) {
+ switch (pname) {
+ case GR_GL_QUERY_RESULT_AVAILABLE:
+ *params = GR_GL_TRUE;
+ break;
+ case GR_GL_QUERY_RESULT:
+ *params = 0;
+ break;
+ default:
+ SkFAIL("Unexpected pname passed to GetQueryObject.");
+ break;
+ }
+ }
+
+ enum ObjTypes {
+ kTexture_ObjTypes = 0,
+ kBuffer_ObjTypes,
+ kRenderBuffer_ObjTypes,
+ kFrameBuffer_ObjTypes,
+ kShader_ObjTypes,
+ kProgram_ObjTypes,
+ kTextureUnit_ObjTypes,
+ kVertexArray_ObjTypes,
+ kObjTypeCount
+ };
+
+ typedef GrFakeRefObj *(*Create)();
+
+ static Create gFactoryFunc[kObjTypeCount];
+
+ GrGLvoid genObjs(ObjTypes type, GrGLsizei n, GrGLuint* ids) {
+ for (int i = 0; i < n; ++i) {
+ GrAlwaysAssert(ids[i] == 0);
+ GrFakeRefObj *obj = this->createObj(type);
+ GrAlwaysAssert(obj);
+ ids[i] = obj->getID();
+ }
+ }
+
+ GrFakeRefObj* createObj(ObjTypes type) {
+ GrFakeRefObj *temp = (*gFactoryFunc[type])();
+
+ fObjects.push_back(temp);
+
+ return temp;
+ }
+
+ GrFakeRefObj* findObject(GrGLuint ID, ObjTypes type) {
+ for (int i = 0; i < fObjects.count(); ++i) {
+ if (fObjects[i]->getID() == ID) { // && fObjects[i]->getType() == type) {
+ // The application shouldn't be accessing objects
+ // that (as far as OpenGL knows) were already deleted
+ GrAlwaysAssert(!fObjects[i]->getDeleted());
+ GrAlwaysAssert(!fObjects[i]->getMarkedForDeletion());
+ return fObjects[i];
+ }
+ }
+ return nullptr;
+ }
+
+ GrTextureUnitObj* getTextureUnit(int unit) {
+ GrAlwaysAssert(0 <= unit && kDefaultMaxTextureUnits > unit);
+
+ return fTextureUnits[unit];
+ }
+
+ 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) {
+ 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; }
+
+ void setVertexArray(GrVertexArrayObj* vertexArray) {
+ if (vertexArray) {
+ SkASSERT(!vertexArray->getDeleted());
+ }
+ SkRefCnt_SafeAssign(fVertexArray, vertexArray);
+ }
+
+ GrVertexArrayObj* getVertexArray() { return fVertexArray; }
+
+ void setTexture(GrTextureObj *texture) {
+ fTextureUnits[fCurrTextureUnit]->setTexture(texture);
+ }
+
+ 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 setRenderBuffer(GrRenderBufferObj *renderBuffer) {
+ if (fRenderBuffer) {
+ GrAlwaysAssert(fRenderBuffer->getBound());
+ fRenderBuffer->resetBound();
+
+ GrAlwaysAssert(!fRenderBuffer->getDeleted());
+ fRenderBuffer->unref();
+ }
+
+ fRenderBuffer = renderBuffer;
+
+ if (fRenderBuffer) {
+ GrAlwaysAssert(!fRenderBuffer->getDeleted());
+ fRenderBuffer->ref();
+
+ GrAlwaysAssert(!fRenderBuffer->getBound());
+ fRenderBuffer->setBound();
+ }
+ }
+ GrRenderBufferObj *getRenderBuffer() { return fRenderBuffer; }
+
+ 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();
+ }
+ }
+
+ void report() const {
+ for (int i = 0; i < fObjects.count(); ++i) {
+ if (!fAbandoned) {
+ GrAlwaysAssert(0 == fObjects[i]->getRefCount());
+ GrAlwaysAssert(fObjects[i]->getDeleted());
+ }
+ }
+ }
+
+ typedef GrGLTestInterface INHERITED;
+};
+
+#undef CREATE
+#undef FIND
+
+DebugInterface::Create DebugInterface::gFactoryFunc[kObjTypeCount] = {
+ GrTextureObj::createGrTextureObj,
+ GrBufferObj::createGrBufferObj,
+ GrRenderBufferObj::createGrRenderBufferObj,
+ GrFrameBufferObj::createGrFrameBufferObj,
+ GrShaderObj::createGrShaderObj,
+ GrProgramObj::createGrProgramObj,
+ GrTextureUnitObj::createGrTextureUnitObj,
+ GrVertexArrayObj::createGrVertexArrayObj,
+};
+
+const char* DebugInterface::kExtensions[] = {
+ "GL_ARB_framebuffer_object",
+ "GL_ARB_blend_func_extended",
+ "GL_ARB_timer_query",
+ "GL_ARB_draw_buffers",
+ "GL_ARB_occlusion_query",
+ "GL_EXT_stencil_wrap",
+ nullptr, // signifies the end of the array.
+};
+
+class DebugGLContext : public sk_gpu_test::GLContext {
+public:
+ DebugGLContext() {
+ this->init(new DebugInterface());
+ }
+
+ ~DebugGLContext() override { this->teardown(); }
+
+private:
+ void onPlatformMakeCurrent() const override {}
+ void onPlatformSwapBuffers() const override {}
+ GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; }
+};
+} // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext* CreateDebugGLContext() {
+ GLContext* ctx = new DebugGLContext();
+ if (ctx->isValid()) {
+ return ctx;
+ }
+ delete ctx;
+ return nullptr;
+}
+}
diff --git a/tools/gpu/gl/debug/DebugGLContext.h b/tools/gpu/gl/debug/DebugGLContext.h
new file mode 100644
index 0000000000..0ac505b632
--- /dev/null
+++ b/tools/gpu/gl/debug/DebugGLContext.h
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DebugGLContext_DEFINED
+#define DebugGLContext_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+GLContext* CreateDebugGLContext();
+} // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/gl/debug/GrBufferObj.cpp b/tools/gpu/gl/debug/GrBufferObj.cpp
new file mode 100644
index 0000000000..37d4438ef6
--- /dev/null
+++ b/tools/gpu/gl/debug/GrBufferObj.cpp
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBufferObj.h"
+
+void GrBufferObj::allocate(GrGLsizeiptr size, const GrGLchar *dataPtr) {
+ GrAlwaysAssert(size >= 0);
+
+ // delete pre-existing data
+ delete[] fDataPtr;
+
+ fSize = size;
+ fDataPtr = new GrGLchar[size];
+ if (dataPtr) {
+ memcpy(fDataPtr, dataPtr, fSize);
+ }
+ // TODO: w/ no dataPtr the data is unitialized - this could be tracked
+}
+
+void GrBufferObj::deleteAction() {
+
+ // buffers are automatically unmapped when deleted
+ this->resetMapped();
+
+ this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrBufferObj.h b/tools/gpu/gl/debug/GrBufferObj.h
new file mode 100644
index 0000000000..96aef6ed0a
--- /dev/null
+++ b/tools/gpu/gl/debug/GrBufferObj.h
@@ -0,0 +1,76 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBufferObj_DEFINED
+#define GrBufferObj_DEFINED
+
+#include "GrFakeRefObj.h"
+#include "gl/GrGLDefines.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrBufferObj : public GrFakeRefObj {
+ GR_DEFINE_CREATOR(GrBufferObj);
+
+public:
+ GrBufferObj()
+ : GrFakeRefObj()
+ , fDataPtr(nullptr)
+ , fMapped(false)
+ , fBound(false)
+ , fSize(0)
+ , fUsage(GR_GL_STATIC_DRAW) {
+ }
+ virtual ~GrBufferObj() {
+ delete[] fDataPtr;
+ }
+
+ void access() {
+ // cannot access the buffer if it is currently mapped
+ GrAlwaysAssert(!fMapped);
+ }
+
+ void setMapped(GrGLintptr offset, GrGLsizeiptr length) {
+ fMapped = true;
+ fMappedOffset = offset;
+ fMappedLength = length;
+ }
+ void resetMapped() { fMapped = false; }
+ bool getMapped() const { return fMapped; }
+ GrGLintptr getMappedOffset() const { return fMappedOffset; }
+ GrGLsizeiptr getMappedLength() const { return fMappedLength; }
+
+ void setBound() { fBound = true; }
+ void resetBound() { fBound = false; }
+ bool getBound() const { return fBound; }
+
+ void allocate(GrGLsizeiptr size, const GrGLchar *dataPtr);
+ GrGLsizeiptr getSize() const { return fSize; }
+ GrGLchar *getDataPtr() { return fDataPtr; }
+
+ void setUsage(GrGLint usage) { fUsage = usage; }
+ GrGLint getUsage() const { return fUsage; }
+
+ void deleteAction() override;
+
+protected:
+private:
+
+ GrGLchar* fDataPtr;
+ bool fMapped; // is the buffer object mapped via "glMapBuffer[Range]"?
+ GrGLintptr fMappedOffset; // the offset of the buffer range that is mapped
+ GrGLsizeiptr fMappedLength; // the size of the buffer range that is mapped
+ bool fBound; // is the buffer object bound via "glBindBuffer"?
+ GrGLsizeiptr fSize; // size in bytes
+ GrGLint fUsage; // one of: GL_STREAM_DRAW,
+ // GL_STATIC_DRAW,
+ // GL_DYNAMIC_DRAW
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFBBindableObj.h b/tools/gpu/gl/debug/GrFBBindableObj.h
new file mode 100644
index 0000000000..e2b43a6a1b
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFBBindableObj.h
@@ -0,0 +1,88 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFBBindableObj_DEFINED
+#define GrFBBindableObj_DEFINED
+
+#include "SkTDArray.h"
+#include "GrFakeRefObj.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// A common base class for render buffers and textures
+class GrFBBindableObj : public GrFakeRefObj {
+
+public:
+ GrFBBindableObj()
+ : GrFakeRefObj() {
+ }
+
+ virtual ~GrFBBindableObj() {
+ GrAlwaysAssert(0 == fColorReferees.count());
+ GrAlwaysAssert(0 == fDepthReferees.count());
+ GrAlwaysAssert(0 == fStencilReferees.count());
+ }
+
+ void setColorBound(GrFakeRefObj *referee) {
+ fColorReferees.append(1, &referee);
+ }
+ void resetColorBound(GrFakeRefObj *referee) {
+ int index = fColorReferees.find(referee);
+ GrAlwaysAssert(0 <= index);
+ fColorReferees.removeShuffle(index);
+ }
+ bool getColorBound(GrFakeRefObj *referee) const {
+ int index = fColorReferees.find(referee);
+ return 0 <= index;
+ }
+ bool getColorBound() const {
+ return 0 != fColorReferees.count();
+ }
+
+ void setDepthBound(GrFakeRefObj *referee) {
+ fDepthReferees.append(1, &referee);
+ }
+ void resetDepthBound(GrFakeRefObj *referee) {
+ int index = fDepthReferees.find(referee);
+ GrAlwaysAssert(0 <= index);
+ fDepthReferees.removeShuffle(index);
+ }
+ bool getDepthBound(GrFakeRefObj *referee) const {
+ int index = fDepthReferees.find(referee);
+ return 0 <= index;
+ }
+ bool getDepthBound() const {
+ return 0 != fDepthReferees.count();
+ }
+
+ void setStencilBound(GrFakeRefObj *referee) {
+ fStencilReferees.append(1, &referee);
+ }
+ void resetStencilBound(GrFakeRefObj *referee) {
+ int index = fStencilReferees.find(referee);
+ GrAlwaysAssert(0 <= index);
+ fStencilReferees.removeShuffle(index);
+ }
+ bool getStencilBound(GrFakeRefObj *referee) const {
+ int index = fStencilReferees.find(referee);
+ return 0 <= index;
+ }
+ bool getStencilBound() const {
+ return 0 != fStencilReferees.count();
+ }
+
+
+protected:
+private:
+ SkTDArray<GrFakeRefObj *> fColorReferees; // frame buffers that use this as a color buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+ SkTDArray<GrFakeRefObj *> fDepthReferees; // frame buffers that use this as a depth buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+ SkTDArray<GrFakeRefObj *> fStencilReferees; // frame buffers that use this as a stencil buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrFBBindableObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFakeRefObj.h b/tools/gpu/gl/debug/GrFakeRefObj.h
new file mode 100644
index 0000000000..30580516fa
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFakeRefObj.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFakeRefObj_DEFINED
+#define GrFakeRefObj_DEFINED
+
+#include "SkTypes.h"
+#include "gl/GrGLInterface.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// 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
+// goes to 0) so that we can detect invalid memory accesses. The refs we
+// are tracking in this class are actually OpenGL's references to the objects
+// not "ours"
+// Each object also gets a unique globally identifying ID
+class GrFakeRefObj : SkNoncopyable {
+public:
+ GrFakeRefObj()
+ : fRef(0)
+ , fMarkedForDeletion(false)
+ , fDeleted(false) {
+
+ // source for globally unique IDs - 0 is reserved!
+ static int fNextID = 0;
+
+ fID = ++fNextID;
+ }
+ virtual ~GrFakeRefObj() {};
+
+ void ref() {
+ 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
+ if (0 == fRef && fMarkedForDeletion) {
+ this->deleteAction();
+ }
+ }
+ int getRefCount() const { return fRef; }
+
+ GrGLuint getID() const { return fID; }
+
+ void setMarkedForDeletion() { fMarkedForDeletion = true; }
+ bool getMarkedForDeletion() const { return fMarkedForDeletion; }
+
+ bool getDeleted() const { return fDeleted; }
+
+ // The deleteAction fires if the object has been marked for deletion but
+ // couldn't be deleted earlier due to refs
+ virtual void deleteAction() {
+ this->setDeleted();
+ }
+
+protected:
+private:
+ int fRef; // ref count
+ GrGLuint fID; // globally unique ID
+ bool fMarkedForDeletion;
+ // The deleted flag is only set when OpenGL thinks the object is deleted
+ // It is obviously still allocated w/in this framework
+ bool fDeleted;
+
+ // setDeleted should only ever appear in the deleteAction method!
+ void setDeleted() { fDeleted = true; }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Each class derived from GrFakeRefObj should use this macro to add a
+// factory creation entry point. This entry point is used by the GrGLDebug
+// object to instantiate the various objects
+// all globally unique IDs
+#define GR_DEFINE_CREATOR(className) \
+public: \
+ static GrFakeRefObj *create##className() { return new className; }
+
+#endif // GrFakeRefObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFrameBufferObj.cpp b/tools/gpu/gl/debug/GrFrameBufferObj.cpp
new file mode 100644
index 0000000000..7dc12acafb
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFrameBufferObj.cpp
@@ -0,0 +1,67 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrFrameBufferObj.h"
+#include "GrFBBindableObj.h"
+
+void GrFrameBufferObj::setColor(GrFBBindableObj *buffer) {
+ if (fColorBuffer) {
+ // automatically break the binding of the old buffer
+ GrAlwaysAssert(fColorBuffer->getColorBound(this));
+ fColorBuffer->resetColorBound(this);
+
+ GrAlwaysAssert(!fColorBuffer->getDeleted());
+ fColorBuffer->unref();
+ }
+ fColorBuffer = buffer;
+ if (fColorBuffer) {
+ GrAlwaysAssert(!fColorBuffer->getDeleted());
+ fColorBuffer->ref();
+
+ GrAlwaysAssert(!fColorBuffer->getColorBound(this));
+ fColorBuffer->setColorBound(this);
+ }
+}
+
+void GrFrameBufferObj::setDepth(GrFBBindableObj *buffer) {
+ if (fDepthBuffer) {
+ // automatically break the binding of the old buffer
+ GrAlwaysAssert(fDepthBuffer->getDepthBound(this));
+ fDepthBuffer->resetDepthBound(this);
+
+ GrAlwaysAssert(!fDepthBuffer->getDeleted());
+ fDepthBuffer->unref();
+ }
+ fDepthBuffer = buffer;
+ if (fDepthBuffer) {
+ GrAlwaysAssert(!fDepthBuffer->getDeleted());
+ fDepthBuffer->ref();
+
+ GrAlwaysAssert(!fDepthBuffer->getDepthBound(this));
+ fDepthBuffer->setDepthBound(this);
+ }
+}
+
+void GrFrameBufferObj::setStencil(GrFBBindableObj *buffer) {
+ if (fStencilBuffer) {
+ // automatically break the binding of the old buffer
+ GrAlwaysAssert(fStencilBuffer->getStencilBound(this));
+ fStencilBuffer->resetStencilBound(this);
+
+ //GrAlwaysAssert(!fStencilBuffer->getDeleted());
+ fStencilBuffer->unref();
+ }
+ fStencilBuffer = buffer;
+ if (fStencilBuffer) {
+ GrAlwaysAssert(!fStencilBuffer->getDeleted());
+ fStencilBuffer->ref();
+
+ GrAlwaysAssert(!fStencilBuffer->getStencilBound(this));
+ fStencilBuffer->setStencilBound(this);
+ }
+}
diff --git a/tools/gpu/gl/debug/GrFrameBufferObj.h b/tools/gpu/gl/debug/GrFrameBufferObj.h
new file mode 100644
index 0000000000..42a0effe07
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFrameBufferObj.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFrameBufferObj_DEFINED
+#define GrFrameBufferObj_DEFINED
+
+#include "GrFakeRefObj.h"
+class GrFBBindableObj;
+
+////////////////////////////////////////////////////////////////////////////////
+// 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 {
+ GR_DEFINE_CREATOR(GrFrameBufferObj);
+
+public:
+ GrFrameBufferObj()
+ : GrFakeRefObj()
+ , fBound(false)
+ , fColorBuffer(nullptr)
+ , fDepthBuffer(nullptr)
+ , fStencilBuffer(nullptr) {
+ }
+
+ virtual ~GrFrameBufferObj() {
+ fColorBuffer = nullptr;
+ fDepthBuffer = nullptr;
+ fStencilBuffer = nullptr;
+ }
+
+ void setBound() { fBound = true; }
+ void resetBound() { fBound = false; }
+ bool getBound() const { return fBound; }
+
+ void setColor(GrFBBindableObj *buffer);
+ GrFBBindableObj *getColor() { return fColorBuffer; }
+
+ void setDepth(GrFBBindableObj *buffer);
+ GrFBBindableObj *getDepth() { return fDepthBuffer; }
+
+ void setStencil(GrFBBindableObj *buffer);
+ GrFBBindableObj *getStencil() { return fStencilBuffer; }
+
+ void deleteAction() override {
+
+ setColor(nullptr);
+ setDepth(nullptr);
+ setStencil(nullptr);
+
+ this->INHERITED::deleteAction();
+ }
+
+protected:
+private:
+ bool fBound; // is this frame buffer currently bound via "glBindFramebuffer"?
+ GrFBBindableObj * fColorBuffer;
+ GrFBBindableObj * fDepthBuffer;
+ GrFBBindableObj * fStencilBuffer;
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrFrameBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrProgramObj.cpp b/tools/gpu/gl/debug/GrProgramObj.cpp
new file mode 100644
index 0000000000..d6cc36bd74
--- /dev/null
+++ b/tools/gpu/gl/debug/GrProgramObj.cpp
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrProgramObj.h"
+#include "GrShaderObj.h"
+
+void GrProgramObj::AttachShader(GrShaderObj *shader) {
+ shader->ref();
+ fShaders.push_back(shader);
+}
+
+void GrProgramObj::deleteAction() {
+
+ // shaders are automatically detached from a deleted program. They will only be
+ // deleted if they were marked for deletion by a prior call to glDeleteShader
+ for (int i = 0; i < fShaders.count(); ++i) {
+ fShaders[i]->unref();
+ }
+ fShaders.reset();
+
+ this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrProgramObj.h b/tools/gpu/gl/debug/GrProgramObj.h
new file mode 100644
index 0000000000..a25341a215
--- /dev/null
+++ b/tools/gpu/gl/debug/GrProgramObj.h
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramObj_DEFINED
+#define GrProgramObj_DEFINED
+
+#include "SkTArray.h"
+#include "GrFakeRefObj.h"
+class GrShaderObj;
+
+////////////////////////////////////////////////////////////////////////////////
+class GrProgramObj : public GrFakeRefObj {
+ GR_DEFINE_CREATOR(GrProgramObj);
+
+public:
+ GrProgramObj()
+ : GrFakeRefObj()
+ , fInUse(false) {}
+
+ void AttachShader(GrShaderObj *shader);
+
+ void deleteAction() override;
+
+ // TODO: this flag system won't work w/ multiple contexts!
+ void setInUse() { fInUse = true; }
+ void resetInUse() { fInUse = false; }
+ bool getInUse() const { return fInUse; }
+
+protected:
+
+private:
+ SkTArray<GrShaderObj *> fShaders;
+ bool fInUse; // has this program been activated by a glUseProgram call?
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrProgramObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrRenderBufferObj.h b/tools/gpu/gl/debug/GrRenderBufferObj.h
new file mode 100644
index 0000000000..8231ef58df
--- /dev/null
+++ b/tools/gpu/gl/debug/GrRenderBufferObj.h
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrRenderBufferObj_DEFINED
+#define GrRenderBufferObj_DEFINED
+
+#include "GrFBBindableObj.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrRenderBufferObj : public GrFBBindableObj {
+ GR_DEFINE_CREATOR(GrRenderBufferObj);
+
+public:
+ GrRenderBufferObj()
+ : GrFBBindableObj()
+ , fBound(false) {
+ }
+
+ void setBound() { fBound = true; }
+ void resetBound() { fBound = false; }
+ bool getBound() const { return fBound; }
+
+ void deleteAction() override {
+
+ this->INHERITED::deleteAction();
+ }
+
+protected:
+private:
+ bool fBound; // is this render buffer currently bound via "glBindRenderbuffer"?
+
+ typedef GrFBBindableObj INHERITED;
+};
+
+#endif // GrRenderBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrShaderObj.cpp b/tools/gpu/gl/debug/GrShaderObj.cpp
new file mode 100644
index 0000000000..8d3caa1e3f
--- /dev/null
+++ b/tools/gpu/gl/debug/GrShaderObj.cpp
@@ -0,0 +1,14 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrShaderObj.h"
+
+void GrShaderObj::deleteAction() {
+
+ this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrShaderObj.h b/tools/gpu/gl/debug/GrShaderObj.h
new file mode 100644
index 0000000000..327bd7f084
--- /dev/null
+++ b/tools/gpu/gl/debug/GrShaderObj.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrShaderObj_DEFINED
+#define GrShaderObj_DEFINED
+
+#include "GrFakeRefObj.h"
+#include "gl/GrGLDefines.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrShaderObj : public GrFakeRefObj {
+ GR_DEFINE_CREATOR(GrShaderObj);
+
+public:
+ GrShaderObj()
+ : GrFakeRefObj()
+ , fType(GR_GL_VERTEX_SHADER) {}
+
+ void setType(GrGLenum type) { fType = type; }
+ GrGLenum getType() { return fType; }
+
+ void deleteAction() override;
+
+protected:
+private:
+ GrGLenum fType; // either GR_GL_VERTEX_SHADER or GR_GL_FRAGMENT_SHADER
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrShaderObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrTextureObj.cpp b/tools/gpu/gl/debug/GrTextureObj.cpp
new file mode 100644
index 0000000000..86063fbc99
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureObj.cpp
@@ -0,0 +1,14 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureObj.h"
+
+void GrTextureObj::deleteAction() {
+
+ this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrTextureObj.h b/tools/gpu/gl/debug/GrTextureObj.h
new file mode 100644
index 0000000000..fcf851db86
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureObj.h
@@ -0,0 +1,57 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureObj_DEFINED
+#define GrTextureObj_DEFINED
+
+#include "GrFBBindableObj.h"
+
+class GrTextureUnitObj;
+
+////////////////////////////////////////////////////////////////////////////////
+class GrTextureObj : public GrFBBindableObj {
+ GR_DEFINE_CREATOR(GrTextureObj);
+
+public:
+ GrTextureObj()
+ : GrFBBindableObj() {
+ }
+
+ virtual ~GrTextureObj() {
+ GrAlwaysAssert(0 == fTextureUnitReferees.count());
+ }
+
+ void setBound(GrTextureUnitObj *referee) {
+ fTextureUnitReferees.append(1, &referee);
+ }
+
+ void resetBound(GrTextureUnitObj *referee) {
+ int index = fTextureUnitReferees.find(referee);
+ GrAlwaysAssert(0 <= index);
+ fTextureUnitReferees.removeShuffle(index);
+ }
+ bool getBound(GrTextureUnitObj *referee) const {
+ int index = fTextureUnitReferees.find(referee);
+ return 0 <= index;
+ }
+ bool getBound() const {
+ return 0 != fTextureUnitReferees.count();
+ }
+
+ void deleteAction() override;
+
+protected:
+
+private:
+ // texture units that bind this texture (via "glBindTexture")
+ SkTDArray<GrTextureUnitObj *> fTextureUnitReferees;
+
+ typedef GrFBBindableObj INHERITED;
+};
+
+#endif // GrTextureObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrTextureUnitObj.cpp b/tools/gpu/gl/debug/GrTextureUnitObj.cpp
new file mode 100644
index 0000000000..316dcecd93
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureUnitObj.cpp
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureUnitObj.h"
+#include "GrTextureObj.h"
+
+void GrTextureUnitObj::setTexture(GrTextureObj *texture) {
+
+ if (fTexture) {
+ GrAlwaysAssert(fTexture->getBound(this));
+ fTexture->resetBound(this);
+
+ GrAlwaysAssert(!fTexture->getDeleted());
+ fTexture->unref();
+ }
+
+ fTexture = texture;
+
+ if (fTexture) {
+ GrAlwaysAssert(!fTexture->getDeleted());
+ fTexture->ref();
+
+ GrAlwaysAssert(!fTexture->getBound(this));
+ fTexture->setBound(this);
+ }
+}
diff --git a/tools/gpu/gl/debug/GrTextureUnitObj.h b/tools/gpu/gl/debug/GrTextureUnitObj.h
new file mode 100644
index 0000000000..5c7a03980b
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureUnitObj.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureUnitObj_DEFINED
+#define GrTextureUnitObj_DEFINED
+
+#include "GrFakeRefObj.h"
+class GrTextureObj;
+
+////////////////////////////////////////////////////////////////////////////////
+// Although texture unit objects are allocated & deallocated like the other
+// GL emulation objects they are derived from GrFakeRefObj to provide some
+// uniformity in how the debug interface class manages resources
+class GrTextureUnitObj : public GrFakeRefObj {
+ GR_DEFINE_CREATOR(GrTextureUnitObj);
+
+public:
+ GrTextureUnitObj()
+ : GrFakeRefObj()
+ , fNumber(0)
+ , fTexture(nullptr) {
+ }
+
+ void setNumber(GrGLenum number) {
+ fNumber = number;
+ }
+ GrGLenum getNumber() const { return fNumber; }
+
+ void setTexture(GrTextureObj *texture);
+ GrTextureObj *getTexture() { return fTexture; }
+
+protected:
+private:
+ GrGLenum fNumber;
+ GrTextureObj *fTexture;
+
+ typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrTextureUnitObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrVertexArrayObj.h b/tools/gpu/gl/debug/GrVertexArrayObj.h
new file mode 100644
index 0000000000..989c610924
--- /dev/null
+++ b/tools/gpu/gl/debug/GrVertexArrayObj.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVertexArrayObj_DEFINED
+#define GrVertexArrayObj_DEFINED
+
+#include "GrFakeRefObj.h"
+
+class GrVertexArrayObj : public GrFakeRefObj {
+ GR_DEFINE_CREATOR(GrVertexArrayObj);
+
+public:
+ GrVertexArrayObj() : GrFakeRefObj() {}
+
+ typedef GrFakeRefObj INHERITED;
+};
+#endif