michael@0: michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "gl/GrGLInterface.h" michael@0: #include "GrDebugGL.h" michael@0: #include "GrShaderObj.h" michael@0: #include "GrProgramObj.h" michael@0: #include "GrBufferObj.h" michael@0: #include "GrTextureUnitObj.h" michael@0: #include "GrTextureObj.h" michael@0: #include "GrFrameBufferObj.h" michael@0: #include "GrRenderBufferObj.h" michael@0: #include "GrVertexArrayObj.h" michael@0: #include "SkFloatingPoint.h" michael@0: #include "../GrGLNoOpInterface.h" michael@0: michael@0: namespace { // suppress no previous prototype warning michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLActiveTexture(GrGLenum texture) { michael@0: michael@0: // Ganesh offsets the texture unit indices michael@0: texture -= GR_GL_TEXTURE0; michael@0: GrAlwaysAssert(texture < GrDebugGL::getInstance()->getMaxTextureUnits()); michael@0: michael@0: GrDebugGL::getInstance()->setCurTextureUnit(texture); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLAttachShader(GrGLuint programID, michael@0: GrGLuint shaderID) { michael@0: michael@0: GrProgramObj *program = GR_FIND(programID, GrProgramObj, michael@0: GrDebugGL::kProgram_ObjTypes); michael@0: GrAlwaysAssert(program); michael@0: michael@0: GrShaderObj *shader = GR_FIND(shaderID, michael@0: GrShaderObj, michael@0: GrDebugGL::kShader_ObjTypes); michael@0: GrAlwaysAssert(shader); michael@0: michael@0: program->AttachShader(shader); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBeginQuery(GrGLenum target, GrGLuint id) { michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindAttribLocation(GrGLuint program, michael@0: GrGLuint index, michael@0: const char* name) { michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindTexture(GrGLenum target, michael@0: GrGLuint textureID) { michael@0: michael@0: // we don't use cube maps michael@0: GrAlwaysAssert(target == GR_GL_TEXTURE_2D); michael@0: // || target == GR_GL_TEXTURE_CUBE_MAP); michael@0: michael@0: // a textureID of 0 is acceptable - it binds to the default texture target michael@0: GrTextureObj *texture = GR_FIND(textureID, GrTextureObj, michael@0: GrDebugGL::kTexture_ObjTypes); michael@0: michael@0: GrDebugGL::getInstance()->setTexture(texture); michael@0: } michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBufferData(GrGLenum target, michael@0: GrGLsizeiptr size, michael@0: const GrGLvoid* data, michael@0: GrGLenum usage) { michael@0: GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || michael@0: GR_GL_ELEMENT_ARRAY_BUFFER == target); michael@0: GrAlwaysAssert(size >= 0); michael@0: GrAlwaysAssert(GR_GL_STREAM_DRAW == usage || michael@0: GR_GL_STATIC_DRAW == usage || michael@0: GR_GL_DYNAMIC_DRAW == usage); michael@0: michael@0: GrBufferObj *buffer = NULL; michael@0: switch (target) { michael@0: case GR_GL_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getArrayBuffer(); michael@0: break; michael@0: case GR_GL_ELEMENT_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getElementArrayBuffer(); michael@0: break; michael@0: default: michael@0: GrCrash("Unexpected target to glBufferData"); michael@0: break; michael@0: } michael@0: michael@0: GrAlwaysAssert(buffer); michael@0: GrAlwaysAssert(buffer->getBound()); michael@0: michael@0: buffer->allocate(size, reinterpret_cast(data)); michael@0: buffer->setUsage(usage); michael@0: } michael@0: michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLPixelStorei(GrGLenum pname, michael@0: GrGLint param) { michael@0: michael@0: switch (pname) { michael@0: case GR_GL_UNPACK_ROW_LENGTH: michael@0: GrDebugGL::getInstance()->setUnPackRowLength(param); michael@0: break; michael@0: case GR_GL_PACK_ROW_LENGTH: michael@0: GrDebugGL::getInstance()->setPackRowLength(param); michael@0: break; michael@0: case GR_GL_UNPACK_ALIGNMENT: michael@0: break; michael@0: case GR_GL_PACK_ALIGNMENT: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: default: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLReadPixels(GrGLint x, michael@0: GrGLint y, michael@0: GrGLsizei width, michael@0: GrGLsizei height, michael@0: GrGLenum format, michael@0: GrGLenum type, michael@0: GrGLvoid* pixels) { michael@0: michael@0: GrGLint pixelsInRow = width; michael@0: if (0 < GrDebugGL::getInstance()->getPackRowLength()) { michael@0: pixelsInRow = GrDebugGL::getInstance()->getPackRowLength(); michael@0: } michael@0: michael@0: GrGLint componentsPerPixel = 0; michael@0: michael@0: switch (format) { michael@0: case GR_GL_RGBA: michael@0: // fallthrough michael@0: case GR_GL_BGRA: michael@0: componentsPerPixel = 4; michael@0: break; michael@0: case GR_GL_RGB: michael@0: componentsPerPixel = 3; michael@0: break; michael@0: case GR_GL_RED: michael@0: componentsPerPixel = 1; michael@0: break; michael@0: default: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: } michael@0: michael@0: GrGLint alignment = 4; // the pack alignment (one of 1, 2, 4 or 8) michael@0: // Ganesh currently doesn't support setting GR_GL_PACK_ALIGNMENT michael@0: michael@0: GrGLint componentSize = 0; // size (in bytes) of a single component michael@0: michael@0: switch (type) { michael@0: case GR_GL_UNSIGNED_BYTE: michael@0: componentSize = 1; michael@0: break; michael@0: default: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: } michael@0: michael@0: GrGLint rowStride = 0; // number of components (not bytes) to skip michael@0: if (componentSize >= alignment) { michael@0: rowStride = componentsPerPixel * pixelsInRow; michael@0: } else { michael@0: float fTemp = michael@0: sk_float_ceil(componentSize * componentsPerPixel * pixelsInRow / michael@0: static_cast(alignment)); michael@0: rowStride = static_cast(alignment * fTemp / componentSize); michael@0: } michael@0: michael@0: GrGLchar *scanline = static_cast(pixels); michael@0: for (int y = 0; y < height; ++y) { michael@0: memset(scanline, 0, componentsPerPixel * componentSize * width); michael@0: scanline += rowStride; michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLUseProgram(GrGLuint programID) { michael@0: michael@0: // A programID of 0 is legal michael@0: GrProgramObj *program = GR_FIND(programID, michael@0: GrProgramObj, michael@0: GrDebugGL::kProgram_ObjTypes); michael@0: michael@0: GrDebugGL::getInstance()->useProgram(program); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindFramebuffer(GrGLenum target, michael@0: GrGLuint frameBufferID) { michael@0: michael@0: GrAlwaysAssert(GR_GL_FRAMEBUFFER == target || michael@0: GR_GL_READ_FRAMEBUFFER == target || michael@0: GR_GL_DRAW_FRAMEBUFFER); michael@0: michael@0: // a frameBufferID of 0 is acceptable - it binds to the default michael@0: // frame buffer michael@0: GrFrameBufferObj *frameBuffer = GR_FIND(frameBufferID, michael@0: GrFrameBufferObj, michael@0: GrDebugGL::kFrameBuffer_ObjTypes); michael@0: michael@0: GrDebugGL::getInstance()->setFrameBuffer(frameBuffer); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindRenderbuffer(GrGLenum target, GrGLuint renderBufferID) { michael@0: michael@0: GrAlwaysAssert(GR_GL_RENDERBUFFER == target); michael@0: michael@0: // a renderBufferID of 0 is acceptable - it unbinds the bound render buffer michael@0: GrRenderBufferObj *renderBuffer = GR_FIND(renderBufferID, michael@0: GrRenderBufferObj, michael@0: GrDebugGL::kRenderBuffer_ObjTypes); michael@0: michael@0: GrDebugGL::getInstance()->setRenderBuffer(renderBuffer); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteTextures(GrGLsizei n, const GrGLuint* textures) { michael@0: michael@0: // first potentially unbind the texture michael@0: // TODO: move this into GrDebugGL as unBindTexture? michael@0: for (unsigned int i = 0; michael@0: i < GrDebugGL::getInstance()->getMaxTextureUnits(); michael@0: ++i) { michael@0: GrTextureUnitObj *pTU = GrDebugGL::getInstance()->getTextureUnit(i); michael@0: michael@0: if (pTU->getTexture()) { michael@0: for (int j = 0; j < n; ++j) { michael@0: michael@0: if (textures[j] == pTU->getTexture()->getID()) { michael@0: // this ID is the current texture - revert the binding to 0 michael@0: pTU->setTexture(NULL); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // TODO: fuse the following block with DeleteRenderBuffers? michael@0: // Open GL will remove a deleted render buffer from the active michael@0: // frame buffer but not from any other frame buffer michael@0: if (GrDebugGL::getInstance()->getFrameBuffer()) { michael@0: michael@0: GrFrameBufferObj *frameBuffer = GrDebugGL::getInstance()->getFrameBuffer(); michael@0: michael@0: for (int i = 0; i < n; ++i) { michael@0: michael@0: if (NULL != frameBuffer->getColor() && michael@0: textures[i] == frameBuffer->getColor()->getID()) { michael@0: frameBuffer->setColor(NULL); michael@0: } michael@0: if (NULL != frameBuffer->getDepth() && michael@0: textures[i] == frameBuffer->getDepth()->getID()) { michael@0: frameBuffer->setDepth(NULL); michael@0: } michael@0: if (NULL != frameBuffer->getStencil() && michael@0: textures[i] == frameBuffer->getStencil()->getID()) { michael@0: frameBuffer->setStencil(NULL); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // then actually "delete" the buffers michael@0: for (int i = 0; i < n; ++i) { michael@0: GrTextureObj *buffer = GR_FIND(textures[i], michael@0: GrTextureObj, michael@0: GrDebugGL::kTexture_ObjTypes); michael@0: GrAlwaysAssert(buffer); michael@0: michael@0: // OpenGL gives no guarantees if a texture is deleted while attached to michael@0: // something other than the currently bound frame buffer michael@0: GrAlwaysAssert(!buffer->getBound()); michael@0: michael@0: GrAlwaysAssert(!buffer->getDeleted()); michael@0: buffer->deleteAction(); michael@0: } michael@0: michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteFramebuffers(GrGLsizei n, michael@0: const GrGLuint *frameBuffers) { michael@0: michael@0: // first potentially unbind the buffers michael@0: if (GrDebugGL::getInstance()->getFrameBuffer()) { michael@0: for (int i = 0; i < n; ++i) { michael@0: michael@0: if (frameBuffers[i] == michael@0: GrDebugGL::getInstance()->getFrameBuffer()->getID()) { michael@0: // this ID is the current frame buffer - rebind to the default michael@0: GrDebugGL::getInstance()->setFrameBuffer(NULL); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // then actually "delete" the buffers michael@0: for (int i = 0; i < n; ++i) { michael@0: GrFrameBufferObj *buffer = GR_FIND(frameBuffers[i], michael@0: GrFrameBufferObj, michael@0: GrDebugGL::kFrameBuffer_ObjTypes); michael@0: GrAlwaysAssert(buffer); michael@0: michael@0: GrAlwaysAssert(!buffer->getDeleted()); michael@0: buffer->deleteAction(); michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteRenderbuffers(GrGLsizei n, michael@0: const GrGLuint *renderBuffers) { michael@0: michael@0: // first potentially unbind the buffers michael@0: if (GrDebugGL::getInstance()->getRenderBuffer()) { michael@0: for (int i = 0; i < n; ++i) { michael@0: michael@0: if (renderBuffers[i] == michael@0: GrDebugGL::getInstance()->getRenderBuffer()->getID()) { michael@0: // this ID is the current render buffer - make no michael@0: // render buffer be bound michael@0: GrDebugGL::getInstance()->setRenderBuffer(NULL); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // TODO: fuse the following block with DeleteTextures? michael@0: // Open GL will remove a deleted render buffer from the active frame michael@0: // buffer but not from any other frame buffer michael@0: if (GrDebugGL::getInstance()->getFrameBuffer()) { michael@0: michael@0: GrFrameBufferObj *frameBuffer = michael@0: GrDebugGL::getInstance()->getFrameBuffer(); michael@0: michael@0: for (int i = 0; i < n; ++i) { michael@0: michael@0: if (NULL != frameBuffer->getColor() && michael@0: renderBuffers[i] == frameBuffer->getColor()->getID()) { michael@0: frameBuffer->setColor(NULL); michael@0: } michael@0: if (NULL != frameBuffer->getDepth() && michael@0: renderBuffers[i] == frameBuffer->getDepth()->getID()) { michael@0: frameBuffer->setDepth(NULL); michael@0: } michael@0: if (NULL != frameBuffer->getStencil() && michael@0: renderBuffers[i] == frameBuffer->getStencil()->getID()) { michael@0: frameBuffer->setStencil(NULL); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // then actually "delete" the buffers michael@0: for (int i = 0; i < n; ++i) { michael@0: GrRenderBufferObj *buffer = GR_FIND(renderBuffers[i], michael@0: GrRenderBufferObj, michael@0: GrDebugGL::kRenderBuffer_ObjTypes); michael@0: GrAlwaysAssert(buffer); michael@0: michael@0: // OpenGL gives no guarantees if a render buffer is deleted michael@0: // while attached to something other than the currently michael@0: // bound frame buffer michael@0: GrAlwaysAssert(!buffer->getColorBound()); michael@0: GrAlwaysAssert(!buffer->getDepthBound()); michael@0: // However, at GrContext destroy time we release all GrRsources and so stencil buffers michael@0: // may get deleted before FBOs that refer to them. michael@0: //GrAlwaysAssert(!buffer->getStencilBound()); michael@0: michael@0: GrAlwaysAssert(!buffer->getDeleted()); michael@0: buffer->deleteAction(); michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLFramebufferRenderbuffer(GrGLenum target, michael@0: GrGLenum attachment, michael@0: GrGLenum renderbuffertarget, michael@0: GrGLuint renderBufferID) { michael@0: michael@0: GrAlwaysAssert(GR_GL_FRAMEBUFFER == target); michael@0: GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment || michael@0: GR_GL_DEPTH_ATTACHMENT == attachment || michael@0: GR_GL_STENCIL_ATTACHMENT == attachment); michael@0: GrAlwaysAssert(GR_GL_RENDERBUFFER == renderbuffertarget); michael@0: michael@0: GrFrameBufferObj *framebuffer = GrDebugGL::getInstance()->getFrameBuffer(); michael@0: // A render buffer cannot be attached to the default framebuffer michael@0: GrAlwaysAssert(NULL != framebuffer); michael@0: michael@0: // a renderBufferID of 0 is acceptable - it unbinds the current michael@0: // render buffer michael@0: GrRenderBufferObj *renderbuffer = GR_FIND(renderBufferID, michael@0: GrRenderBufferObj, michael@0: GrDebugGL::kRenderBuffer_ObjTypes); michael@0: michael@0: switch (attachment) { michael@0: case GR_GL_COLOR_ATTACHMENT0: michael@0: framebuffer->setColor(renderbuffer); michael@0: break; michael@0: case GR_GL_DEPTH_ATTACHMENT: michael@0: framebuffer->setDepth(renderbuffer); michael@0: break; michael@0: case GR_GL_STENCIL_ATTACHMENT: michael@0: framebuffer->setStencil(renderbuffer); michael@0: break; michael@0: default: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: }; michael@0: michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLFramebufferTexture2D(GrGLenum target, michael@0: GrGLenum attachment, michael@0: GrGLenum textarget, michael@0: GrGLuint textureID, michael@0: GrGLint level) { michael@0: michael@0: GrAlwaysAssert(GR_GL_FRAMEBUFFER == target); michael@0: GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment || michael@0: GR_GL_DEPTH_ATTACHMENT == attachment || michael@0: GR_GL_STENCIL_ATTACHMENT == attachment); michael@0: GrAlwaysAssert(GR_GL_TEXTURE_2D == textarget); michael@0: michael@0: GrFrameBufferObj *framebuffer = GrDebugGL::getInstance()->getFrameBuffer(); michael@0: // A texture cannot be attached to the default framebuffer michael@0: GrAlwaysAssert(NULL != framebuffer); michael@0: michael@0: // A textureID of 0 is allowed - it unbinds the currently bound texture michael@0: GrTextureObj *texture = GR_FIND(textureID, GrTextureObj, michael@0: GrDebugGL::kTexture_ObjTypes); michael@0: if (texture) { michael@0: // The texture shouldn't be bound to a texture unit - this michael@0: // could lead to a feedback loop michael@0: GrAlwaysAssert(!texture->getBound()); michael@0: } michael@0: michael@0: GrAlwaysAssert(0 == level); michael@0: michael@0: switch (attachment) { michael@0: case GR_GL_COLOR_ATTACHMENT0: michael@0: framebuffer->setColor(texture); michael@0: break; michael@0: case GR_GL_DEPTH_ATTACHMENT: michael@0: framebuffer->setDepth(texture); michael@0: break; michael@0: case GR_GL_STENCIL_ATTACHMENT: michael@0: framebuffer->setStencil(texture); michael@0: break; michael@0: default: michael@0: GrAlwaysAssert(false); michael@0: break; michael@0: }; michael@0: } michael@0: michael@0: GrGLuint GR_GL_FUNCTION_TYPE debugGLCreateProgram() { michael@0: michael@0: GrProgramObj *program = GR_CREATE(GrProgramObj, michael@0: GrDebugGL::kProgram_ObjTypes); michael@0: michael@0: return program->getID(); michael@0: } michael@0: michael@0: GrGLuint GR_GL_FUNCTION_TYPE debugGLCreateShader(GrGLenum type) { michael@0: michael@0: GrAlwaysAssert(GR_GL_VERTEX_SHADER == type || michael@0: GR_GL_FRAGMENT_SHADER == type); michael@0: michael@0: GrShaderObj *shader = GR_CREATE(GrShaderObj, GrDebugGL::kShader_ObjTypes); michael@0: shader->setType(type); michael@0: michael@0: return shader->getID(); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteProgram(GrGLuint programID) { michael@0: michael@0: GrProgramObj *program = GR_FIND(programID, michael@0: GrProgramObj, michael@0: GrDebugGL::kProgram_ObjTypes); michael@0: GrAlwaysAssert(program); michael@0: michael@0: if (program->getRefCount()) { michael@0: // someone is still using this program so we can't delete it here michael@0: program->setMarkedForDeletion(); michael@0: } else { michael@0: program->deleteAction(); michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteShader(GrGLuint shaderID) { michael@0: michael@0: GrShaderObj *shader = GR_FIND(shaderID, michael@0: GrShaderObj, michael@0: GrDebugGL::kShader_ObjTypes); michael@0: GrAlwaysAssert(shader); michael@0: michael@0: if (shader->getRefCount()) { michael@0: // someone is still using this shader so we can't delete it here michael@0: shader->setMarkedForDeletion(); michael@0: } else { michael@0: shader->deleteAction(); michael@0: } michael@0: } michael@0: michael@0: GrGLvoid debugGenObjs(GrDebugGL::GrObjTypes type, michael@0: GrGLsizei n, michael@0: GrGLuint* ids) { michael@0: michael@0: for (int i = 0; i < n; ++i) { michael@0: GrFakeRefObj *obj = GrDebugGL::getInstance()->createObj(type); michael@0: GrAlwaysAssert(obj); michael@0: ids[i] = obj->getID(); michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenBuffers(GrGLsizei n, GrGLuint* ids) { michael@0: debugGenObjs(GrDebugGL::kBuffer_ObjTypes, n, ids); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenerateMipmap(GrGLenum level) { michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenFramebuffers(GrGLsizei n, michael@0: GrGLuint* ids) { michael@0: debugGenObjs(GrDebugGL::kFrameBuffer_ObjTypes, n, ids); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenRenderbuffers(GrGLsizei n, michael@0: GrGLuint* ids) { michael@0: debugGenObjs(GrDebugGL::kRenderBuffer_ObjTypes, n, ids); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenTextures(GrGLsizei n, GrGLuint* ids) { michael@0: debugGenObjs(GrDebugGL::kTexture_ObjTypes, n, ids); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGenVertexArrays(GrGLsizei n, GrGLuint* ids) { michael@0: debugGenObjs(GrDebugGL::kVertexArray_ObjTypes, n, ids); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteVertexArrays(GrGLsizei n, const GrGLuint* ids) { michael@0: for (GrGLsizei i = 0; i < n; ++i) { michael@0: GrVertexArrayObj* array = michael@0: GR_FIND(ids[i], GrVertexArrayObj, GrDebugGL::kVertexArray_ObjTypes); michael@0: GrAlwaysAssert(array); michael@0: michael@0: // Deleting the current vertex array binds object 0 michael@0: if (GrDebugGL::getInstance()->getVertexArray() == array) { michael@0: GrDebugGL::getInstance()->setVertexArray(NULL); michael@0: } michael@0: michael@0: if (array->getRefCount()) { michael@0: // someone is still using this vertex array so we can't delete it here michael@0: array->setMarkedForDeletion(); michael@0: } else { michael@0: array->deleteAction(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindVertexArray(GrGLuint id) { michael@0: GrVertexArrayObj* array = GR_FIND(id, GrVertexArrayObj, GrDebugGL::kVertexArray_ObjTypes); michael@0: GrAlwaysAssert((0 == id) || NULL != array); michael@0: GrDebugGL::getInstance()->setVertexArray(array); michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindBuffer(GrGLenum target, GrGLuint bufferID) { michael@0: GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || GR_GL_ELEMENT_ARRAY_BUFFER == target); michael@0: michael@0: GrBufferObj *buffer = GR_FIND(bufferID, michael@0: GrBufferObj, michael@0: GrDebugGL::kBuffer_ObjTypes); michael@0: // 0 is a permissible bufferID - it unbinds the current buffer michael@0: michael@0: switch (target) { michael@0: case GR_GL_ARRAY_BUFFER: michael@0: GrDebugGL::getInstance()->setArrayBuffer(buffer); michael@0: break; michael@0: case GR_GL_ELEMENT_ARRAY_BUFFER: michael@0: GrDebugGL::getInstance()->setElementArrayBuffer(buffer); michael@0: break; michael@0: default: michael@0: GrCrash("Unexpected target to glBindBuffer"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // deleting a bound buffer has the side effect of binding 0 michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteBuffers(GrGLsizei n, const GrGLuint* ids) { michael@0: // first potentially unbind the buffers michael@0: for (int i = 0; i < n; ++i) { michael@0: michael@0: if (GrDebugGL::getInstance()->getArrayBuffer() && michael@0: ids[i] == GrDebugGL::getInstance()->getArrayBuffer()->getID()) { michael@0: // this ID is the current array buffer michael@0: GrDebugGL::getInstance()->setArrayBuffer(NULL); michael@0: } michael@0: if (GrDebugGL::getInstance()->getElementArrayBuffer() && michael@0: ids[i] == michael@0: GrDebugGL::getInstance()->getElementArrayBuffer()->getID()) { michael@0: // this ID is the current element array buffer michael@0: GrDebugGL::getInstance()->setElementArrayBuffer(NULL); michael@0: } michael@0: } michael@0: michael@0: // then actually "delete" the buffers michael@0: for (int i = 0; i < n; ++i) { michael@0: GrBufferObj *buffer = GR_FIND(ids[i], michael@0: GrBufferObj, michael@0: GrDebugGL::kBuffer_ObjTypes); michael@0: GrAlwaysAssert(buffer); michael@0: michael@0: GrAlwaysAssert(!buffer->getDeleted()); michael@0: buffer->deleteAction(); michael@0: } michael@0: } michael@0: michael@0: // map a buffer to the caller's address space michael@0: GrGLvoid* GR_GL_FUNCTION_TYPE debugGLMapBuffer(GrGLenum target, GrGLenum access) { michael@0: michael@0: GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || michael@0: GR_GL_ELEMENT_ARRAY_BUFFER == target); michael@0: // GR_GL_READ_ONLY == access || || GR_GL_READ_WRIT == access); michael@0: GrAlwaysAssert(GR_GL_WRITE_ONLY == access); michael@0: michael@0: GrBufferObj *buffer = NULL; michael@0: switch (target) { michael@0: case GR_GL_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getArrayBuffer(); michael@0: break; michael@0: case GR_GL_ELEMENT_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getElementArrayBuffer(); michael@0: break; michael@0: default: michael@0: GrCrash("Unexpected target to glMapBuffer"); michael@0: break; michael@0: } michael@0: michael@0: if (buffer) { michael@0: GrAlwaysAssert(!buffer->getMapped()); michael@0: buffer->setMapped(); michael@0: return buffer->getDataPtr(); michael@0: } michael@0: michael@0: GrAlwaysAssert(false); michael@0: return NULL; // no buffer bound to the target michael@0: } michael@0: michael@0: // remove a buffer from the caller's address space michael@0: // TODO: check if the "access" method from "glMapBuffer" was honored michael@0: GrGLboolean GR_GL_FUNCTION_TYPE debugGLUnmapBuffer(GrGLenum target) { michael@0: michael@0: GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || michael@0: GR_GL_ELEMENT_ARRAY_BUFFER == target); michael@0: michael@0: GrBufferObj *buffer = NULL; michael@0: switch (target) { michael@0: case GR_GL_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getArrayBuffer(); michael@0: break; michael@0: case GR_GL_ELEMENT_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getElementArrayBuffer(); michael@0: break; michael@0: default: michael@0: GrCrash("Unexpected target to glUnmapBuffer"); michael@0: break; michael@0: } michael@0: michael@0: if (buffer) { michael@0: GrAlwaysAssert(buffer->getMapped()); michael@0: buffer->resetMapped(); michael@0: return GR_GL_TRUE; michael@0: } michael@0: michael@0: GrAlwaysAssert(false); michael@0: return GR_GL_FALSE; // GR_GL_INVALID_OPERATION; michael@0: } michael@0: michael@0: GrGLvoid GR_GL_FUNCTION_TYPE debugGLGetBufferParameteriv(GrGLenum target, michael@0: GrGLenum value, michael@0: GrGLint* params) { michael@0: michael@0: GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || michael@0: GR_GL_ELEMENT_ARRAY_BUFFER == target); michael@0: GrAlwaysAssert(GR_GL_BUFFER_SIZE == value || michael@0: GR_GL_BUFFER_USAGE == value); michael@0: michael@0: GrBufferObj *buffer = NULL; michael@0: switch (target) { michael@0: case GR_GL_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getArrayBuffer(); michael@0: break; michael@0: case GR_GL_ELEMENT_ARRAY_BUFFER: michael@0: buffer = GrDebugGL::getInstance()->getElementArrayBuffer(); michael@0: break; michael@0: } michael@0: michael@0: GrAlwaysAssert(buffer); michael@0: michael@0: switch (value) { michael@0: case GR_GL_BUFFER_MAPPED: michael@0: *params = GR_GL_FALSE; michael@0: if (buffer) michael@0: *params = buffer->getMapped() ? GR_GL_TRUE : GR_GL_FALSE; michael@0: break; michael@0: case GR_GL_BUFFER_SIZE: michael@0: *params = 0; michael@0: if (buffer) michael@0: *params = buffer->getSize(); michael@0: break; michael@0: case GR_GL_BUFFER_USAGE: michael@0: *params = GR_GL_STATIC_DRAW; michael@0: if (buffer) michael@0: *params = buffer->getUsage(); michael@0: break; michael@0: default: michael@0: GrCrash("Unexpected value to glGetBufferParamateriv"); michael@0: break; michael@0: } michael@0: }; michael@0: } // end of namespace michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: struct GrDebugGLInterface : public GrGLInterface { michael@0: michael@0: public: michael@0: SK_DECLARE_INST_COUNT(GrDebugGLInterface) michael@0: michael@0: GrDebugGLInterface() michael@0: : fWrapped(NULL) { michael@0: GrDebugGL::staticRef(); michael@0: } michael@0: michael@0: virtual ~GrDebugGLInterface() { michael@0: GrDebugGL::staticUnRef(); michael@0: } michael@0: michael@0: void setWrapped(GrGLInterface *interface) { michael@0: fWrapped.reset(interface); michael@0: } michael@0: michael@0: // TODO: there are some issues w/ wrapping another GL interface inside the michael@0: // debug interface: michael@0: // Since none of the "gl" methods are member functions they don't get michael@0: // a "this" pointer through which to access "fWrapped" michael@0: // This could be worked around by having all of them access the michael@0: // "glInterface" pointer - i.e., treating the debug interface as a michael@0: // true singleton michael@0: // michael@0: // The problem with this is that we also want to handle OpenGL michael@0: // contexts. The natural way to do this is to have multiple debug michael@0: // interfaces. Each of which represents a separate context. The michael@0: // static ID count would still uniquify IDs across all of them. michael@0: // The problem then is that we couldn't treat the debug GL michael@0: // interface as a singleton (since there would be one for each michael@0: // context). michael@0: // michael@0: // The solution to this is probably to alter SkDebugGlContext's michael@0: // "makeCurrent" method to make a call like "makeCurrent(this)" to michael@0: // the debug GL interface (assuming that the application will create michael@0: // multiple SkGLContextHelper's) to let it switch between the active michael@0: // context. Everything in the GrDebugGL object would then need to be michael@0: // moved to a GrContextObj and the GrDebugGL object would just switch michael@0: // between them. Note that this approach would also require that michael@0: // SkDebugGLContext wrap an arbitrary other context michael@0: // and then pass the wrapped interface to the debug GL interface. michael@0: michael@0: protected: michael@0: private: michael@0: michael@0: SkAutoTUnref fWrapped; michael@0: michael@0: typedef GrGLInterface INHERITED; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: const GrGLInterface* GrGLCreateDebugInterface() { michael@0: GrGLInterface* interface = SkNEW(GrDebugGLInterface); michael@0: michael@0: interface->fStandard = kGL_GrGLStandard; michael@0: michael@0: GrGLInterface::Functions* functions = &interface->fFunctions; michael@0: functions->fActiveTexture = debugGLActiveTexture; michael@0: functions->fAttachShader = debugGLAttachShader; michael@0: functions->fBeginQuery = debugGLBeginQuery; michael@0: functions->fBindAttribLocation = debugGLBindAttribLocation; michael@0: functions->fBindBuffer = debugGLBindBuffer; michael@0: functions->fBindFragDataLocation = noOpGLBindFragDataLocation; michael@0: functions->fBindTexture = debugGLBindTexture; michael@0: functions->fBindVertexArray = debugGLBindVertexArray; michael@0: functions->fBlendColor = noOpGLBlendColor; michael@0: functions->fBlendFunc = noOpGLBlendFunc; michael@0: functions->fBufferData = debugGLBufferData; michael@0: functions->fBufferSubData = noOpGLBufferSubData; michael@0: functions->fClear = noOpGLClear; michael@0: functions->fClearColor = noOpGLClearColor; michael@0: functions->fClearStencil = noOpGLClearStencil; michael@0: functions->fColorMask = noOpGLColorMask; michael@0: functions->fCompileShader = noOpGLCompileShader; michael@0: functions->fCompressedTexImage2D = noOpGLCompressedTexImage2D; michael@0: functions->fCopyTexSubImage2D = noOpGLCopyTexSubImage2D; michael@0: functions->fCreateProgram = debugGLCreateProgram; michael@0: functions->fCreateShader = debugGLCreateShader; michael@0: functions->fCullFace = noOpGLCullFace; michael@0: functions->fDeleteBuffers = debugGLDeleteBuffers; michael@0: functions->fDeleteProgram = debugGLDeleteProgram; michael@0: functions->fDeleteQueries = noOpGLDeleteIds; michael@0: functions->fDeleteShader = debugGLDeleteShader; michael@0: functions->fDeleteTextures = debugGLDeleteTextures; michael@0: functions->fDeleteVertexArrays = debugGLDeleteVertexArrays; michael@0: functions->fDepthMask = noOpGLDepthMask; michael@0: functions->fDisable = noOpGLDisable; michael@0: functions->fDisableVertexAttribArray = noOpGLDisableVertexAttribArray; michael@0: functions->fDrawArrays = noOpGLDrawArrays; michael@0: functions->fDrawBuffer = noOpGLDrawBuffer; michael@0: functions->fDrawBuffers = noOpGLDrawBuffers; michael@0: functions->fDrawElements = noOpGLDrawElements; michael@0: functions->fEnable = noOpGLEnable; michael@0: functions->fEnableVertexAttribArray = noOpGLEnableVertexAttribArray; michael@0: functions->fEndQuery = noOpGLEndQuery; michael@0: functions->fFinish = noOpGLFinish; michael@0: functions->fFlush = noOpGLFlush; michael@0: functions->fFrontFace = noOpGLFrontFace; michael@0: functions->fGenerateMipmap = debugGLGenerateMipmap; michael@0: functions->fGenBuffers = debugGLGenBuffers; michael@0: functions->fGenQueries = noOpGLGenIds; michael@0: functions->fGenTextures = debugGLGenTextures; michael@0: functions->fGetBufferParameteriv = debugGLGetBufferParameteriv; michael@0: functions->fGetError = noOpGLGetError; michael@0: functions->fGetIntegerv = noOpGLGetIntegerv; michael@0: functions->fGetQueryObjecti64v = noOpGLGetQueryObjecti64v; michael@0: functions->fGetQueryObjectiv = noOpGLGetQueryObjectiv; michael@0: functions->fGetQueryObjectui64v = noOpGLGetQueryObjectui64v; michael@0: functions->fGetQueryObjectuiv = noOpGLGetQueryObjectuiv; michael@0: functions->fGetQueryiv = noOpGLGetQueryiv; michael@0: functions->fGetProgramInfoLog = noOpGLGetInfoLog; michael@0: functions->fGetProgramiv = noOpGLGetShaderOrProgramiv; michael@0: functions->fGetShaderInfoLog = noOpGLGetInfoLog; michael@0: functions->fGetShaderiv = noOpGLGetShaderOrProgramiv; michael@0: functions->fGetString = noOpGLGetString; michael@0: functions->fGetStringi = noOpGLGetStringi; michael@0: functions->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv; michael@0: functions->fGetUniformLocation = noOpGLGetUniformLocation; michael@0: functions->fGenVertexArrays = debugGLGenVertexArrays; michael@0: functions->fLoadIdentity = noOpGLLoadIdentity; michael@0: functions->fLoadMatrixf = noOpGLLoadMatrixf; michael@0: functions->fLineWidth = noOpGLLineWidth; michael@0: functions->fLinkProgram = noOpGLLinkProgram; michael@0: functions->fMatrixMode = noOpGLMatrixMode; michael@0: functions->fPixelStorei = debugGLPixelStorei; michael@0: functions->fQueryCounter = noOpGLQueryCounter; michael@0: functions->fReadBuffer = noOpGLReadBuffer; michael@0: functions->fReadPixels = debugGLReadPixels; michael@0: functions->fScissor = noOpGLScissor; michael@0: functions->fShaderSource = noOpGLShaderSource; michael@0: functions->fStencilFunc = noOpGLStencilFunc; michael@0: functions->fStencilFuncSeparate = noOpGLStencilFuncSeparate; michael@0: functions->fStencilMask = noOpGLStencilMask; michael@0: functions->fStencilMaskSeparate = noOpGLStencilMaskSeparate; michael@0: functions->fStencilOp = noOpGLStencilOp; michael@0: functions->fStencilOpSeparate = noOpGLStencilOpSeparate; michael@0: functions->fTexGenfv = noOpGLTexGenfv; michael@0: functions->fTexGeni = noOpGLTexGeni; michael@0: functions->fTexImage2D = noOpGLTexImage2D; michael@0: functions->fTexParameteri = noOpGLTexParameteri; michael@0: functions->fTexParameteriv = noOpGLTexParameteriv; michael@0: functions->fTexSubImage2D = noOpGLTexSubImage2D; michael@0: functions->fTexStorage2D = noOpGLTexStorage2D; michael@0: functions->fDiscardFramebuffer = noOpGLDiscardFramebuffer; michael@0: functions->fUniform1f = noOpGLUniform1f; michael@0: functions->fUniform1i = noOpGLUniform1i; michael@0: functions->fUniform1fv = noOpGLUniform1fv; michael@0: functions->fUniform1iv = noOpGLUniform1iv; michael@0: functions->fUniform2f = noOpGLUniform2f; michael@0: functions->fUniform2i = noOpGLUniform2i; michael@0: functions->fUniform2fv = noOpGLUniform2fv; michael@0: functions->fUniform2iv = noOpGLUniform2iv; michael@0: functions->fUniform3f = noOpGLUniform3f; michael@0: functions->fUniform3i = noOpGLUniform3i; michael@0: functions->fUniform3fv = noOpGLUniform3fv; michael@0: functions->fUniform3iv = noOpGLUniform3iv; michael@0: functions->fUniform4f = noOpGLUniform4f; michael@0: functions->fUniform4i = noOpGLUniform4i; michael@0: functions->fUniform4fv = noOpGLUniform4fv; michael@0: functions->fUniform4iv = noOpGLUniform4iv; michael@0: functions->fUniformMatrix2fv = noOpGLUniformMatrix2fv; michael@0: functions->fUniformMatrix3fv = noOpGLUniformMatrix3fv; michael@0: functions->fUniformMatrix4fv = noOpGLUniformMatrix4fv; michael@0: functions->fUseProgram = debugGLUseProgram; michael@0: functions->fVertexAttrib4fv = noOpGLVertexAttrib4fv; michael@0: functions->fVertexAttribPointer = noOpGLVertexAttribPointer; michael@0: functions->fViewport = noOpGLViewport; michael@0: functions->fBindFramebuffer = debugGLBindFramebuffer; michael@0: functions->fBindRenderbuffer = debugGLBindRenderbuffer; michael@0: functions->fCheckFramebufferStatus = noOpGLCheckFramebufferStatus; michael@0: functions->fDeleteFramebuffers = debugGLDeleteFramebuffers; michael@0: functions->fDeleteRenderbuffers = debugGLDeleteRenderbuffers; michael@0: functions->fFramebufferRenderbuffer = debugGLFramebufferRenderbuffer; michael@0: functions->fFramebufferTexture2D = debugGLFramebufferTexture2D; michael@0: functions->fGenFramebuffers = debugGLGenFramebuffers; michael@0: functions->fGenRenderbuffers = debugGLGenRenderbuffers; michael@0: functions->fGetFramebufferAttachmentParameteriv = michael@0: noOpGLGetFramebufferAttachmentParameteriv; michael@0: functions->fGetRenderbufferParameteriv = noOpGLGetRenderbufferParameteriv; michael@0: functions->fRenderbufferStorage = noOpGLRenderbufferStorage; michael@0: functions->fRenderbufferStorageMultisample = michael@0: noOpGLRenderbufferStorageMultisample; michael@0: functions->fBlitFramebuffer = noOpGLBlitFramebuffer; michael@0: functions->fResolveMultisampleFramebuffer = michael@0: noOpGLResolveMultisampleFramebuffer; michael@0: functions->fMapBuffer = debugGLMapBuffer; michael@0: functions->fUnmapBuffer = debugGLUnmapBuffer; michael@0: functions->fBindFragDataLocationIndexed = michael@0: noOpGLBindFragDataLocationIndexed; michael@0: michael@0: interface->fExtensions.init(kGL_GrGLStandard, functions->fGetString, functions->fGetStringi, michael@0: functions->fGetIntegerv); michael@0: michael@0: return interface; michael@0: }