diff options
author | robertphillips <robertphillips@google.com> | 2016-03-30 09:26:24 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-30 09:26:24 -0700 |
commit | 6f70d43719d0583d486a000f66e915c10a6b83a2 (patch) | |
tree | 6f9511faa88ca6d44932e1a247fc10c0f297a3e0 /src/gpu/gl/debug | |
parent | fe3456cb006110d045b26ff3f8681b893a757b58 (diff) |
Revert of Move SkGLContext and some GrGLInterface implementations to skgputest module (patchset #13 id:240001 of https://codereview.chromium.org/1815823002/ )
Reason for revert:
red bots
Original issue's description:
> 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
TBR=jvanverth@google.com,bsalomon@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review URL: https://codereview.chromium.org/1845473004
Diffstat (limited to 'src/gpu/gl/debug')
-rw-r--r-- | src/gpu/gl/debug/GrBufferObj.cpp | 30 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrBufferObj.h | 75 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrFBBindableObj.h | 87 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrFakeRefObj.h | 86 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrFrameBufferObj.cpp | 66 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrFrameBufferObj.h | 67 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrGLCreateDebugInterface.cpp | 1236 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrProgramObj.cpp | 26 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrProgramObj.h | 42 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrRenderBufferObj.h | 39 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrShaderObj.cpp | 13 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrShaderObj.h | 35 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrTextureObj.cpp | 13 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrTextureObj.h | 56 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrTextureUnitObj.cpp | 30 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrTextureUnitObj.h | 44 | ||||
-rw-r--r-- | src/gpu/gl/debug/GrVertexArrayObj.h | 21 | ||||
-rw-r--r-- | src/gpu/gl/debug/SkDebugGLContext.cpp | 16 | ||||
-rw-r--r-- | src/gpu/gl/debug/SkDebugGLContext.h | 27 |
19 files changed, 2009 insertions, 0 deletions
diff --git a/src/gpu/gl/debug/GrBufferObj.cpp b/src/gpu/gl/debug/GrBufferObj.cpp new file mode 100644 index 0000000000..ee0993d6da --- /dev/null +++ b/src/gpu/gl/debug/GrBufferObj.cpp @@ -0,0 +1,30 @@ +/* + * 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/src/gpu/gl/debug/GrBufferObj.h b/src/gpu/gl/debug/GrBufferObj.h new file mode 100644 index 0000000000..5b5015be96 --- /dev/null +++ b/src/gpu/gl/debug/GrBufferObj.h @@ -0,0 +1,75 @@ +/* + * 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 "../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/src/gpu/gl/debug/GrFBBindableObj.h b/src/gpu/gl/debug/GrFBBindableObj.h new file mode 100644 index 0000000000..2d490ef08b --- /dev/null +++ b/src/gpu/gl/debug/GrFBBindableObj.h @@ -0,0 +1,87 @@ +/* + * 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/src/gpu/gl/debug/GrFakeRefObj.h b/src/gpu/gl/debug/GrFakeRefObj.h new file mode 100644 index 0000000000..30580516fa --- /dev/null +++ b/src/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/src/gpu/gl/debug/GrFrameBufferObj.cpp b/src/gpu/gl/debug/GrFrameBufferObj.cpp new file mode 100644 index 0000000000..a8acc3de23 --- /dev/null +++ b/src/gpu/gl/debug/GrFrameBufferObj.cpp @@ -0,0 +1,66 @@ +/* + * 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/src/gpu/gl/debug/GrFrameBufferObj.h b/src/gpu/gl/debug/GrFrameBufferObj.h new file mode 100644 index 0000000000..40e123e49f --- /dev/null +++ b/src/gpu/gl/debug/GrFrameBufferObj.h @@ -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. + */ + +#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/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp new file mode 100644 index 0000000000..02b5cf704d --- /dev/null +++ b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp @@ -0,0 +1,1236 @@ +/* + * 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 "gl/GrGLInterface.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. +}; + +} // anonymous namespace + +//////////////////////////////////////////////////////////////////////////////// + +const GrGLInterface* GrGLCreateDebugInterface() { return new DebugInterface; } diff --git a/src/gpu/gl/debug/GrProgramObj.cpp b/src/gpu/gl/debug/GrProgramObj.cpp new file mode 100644 index 0000000000..d45bd1c113 --- /dev/null +++ b/src/gpu/gl/debug/GrProgramObj.cpp @@ -0,0 +1,26 @@ +/* + * 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/src/gpu/gl/debug/GrProgramObj.h b/src/gpu/gl/debug/GrProgramObj.h new file mode 100644 index 0000000000..6e5ec65d9d --- /dev/null +++ b/src/gpu/gl/debug/GrProgramObj.h @@ -0,0 +1,42 @@ +/* + * 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/src/gpu/gl/debug/GrRenderBufferObj.h b/src/gpu/gl/debug/GrRenderBufferObj.h new file mode 100644 index 0000000000..dae08f5c78 --- /dev/null +++ b/src/gpu/gl/debug/GrRenderBufferObj.h @@ -0,0 +1,39 @@ +/* + * 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/src/gpu/gl/debug/GrShaderObj.cpp b/src/gpu/gl/debug/GrShaderObj.cpp new file mode 100644 index 0000000000..67cca3ed72 --- /dev/null +++ b/src/gpu/gl/debug/GrShaderObj.cpp @@ -0,0 +1,13 @@ +/* + * 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/src/gpu/gl/debug/GrShaderObj.h b/src/gpu/gl/debug/GrShaderObj.h new file mode 100644 index 0000000000..871494ac8d --- /dev/null +++ b/src/gpu/gl/debug/GrShaderObj.h @@ -0,0 +1,35 @@ +/* + * 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 "../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/src/gpu/gl/debug/GrTextureObj.cpp b/src/gpu/gl/debug/GrTextureObj.cpp new file mode 100644 index 0000000000..62cb399245 --- /dev/null +++ b/src/gpu/gl/debug/GrTextureObj.cpp @@ -0,0 +1,13 @@ +/* + * 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/src/gpu/gl/debug/GrTextureObj.h b/src/gpu/gl/debug/GrTextureObj.h new file mode 100644 index 0000000000..bc649f3b38 --- /dev/null +++ b/src/gpu/gl/debug/GrTextureObj.h @@ -0,0 +1,56 @@ +/* + * 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/src/gpu/gl/debug/GrTextureUnitObj.cpp b/src/gpu/gl/debug/GrTextureUnitObj.cpp new file mode 100644 index 0000000000..8de0b092cd --- /dev/null +++ b/src/gpu/gl/debug/GrTextureUnitObj.cpp @@ -0,0 +1,30 @@ +/* + * 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/src/gpu/gl/debug/GrTextureUnitObj.h b/src/gpu/gl/debug/GrTextureUnitObj.h new file mode 100644 index 0000000000..5c7a03980b --- /dev/null +++ b/src/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/src/gpu/gl/debug/GrVertexArrayObj.h b/src/gpu/gl/debug/GrVertexArrayObj.h new file mode 100644 index 0000000000..989c610924 --- /dev/null +++ b/src/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 diff --git a/src/gpu/gl/debug/SkDebugGLContext.cpp b/src/gpu/gl/debug/SkDebugGLContext.cpp new file mode 100644 index 0000000000..ecb27db95d --- /dev/null +++ b/src/gpu/gl/debug/SkDebugGLContext.cpp @@ -0,0 +1,16 @@ +/* + * 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 "gl/debug/SkDebugGLContext.h" + +SkDebugGLContext::SkDebugGLContext() { + this->init(GrGLCreateDebugInterface()); +} + +SkDebugGLContext::~SkDebugGLContext() { + this->teardown(); +} diff --git a/src/gpu/gl/debug/SkDebugGLContext.h b/src/gpu/gl/debug/SkDebugGLContext.h new file mode 100644 index 0000000000..1ea7b62931 --- /dev/null +++ b/src/gpu/gl/debug/SkDebugGLContext.h @@ -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. + */ +#ifndef SkDebugGLContext_DEFINED +#define SkDebugGLContext_DEFINED + +#include "gl/SkGLContext.h" + +class SkDebugGLContext : public SkGLContext { +public: + ~SkDebugGLContext() override; + + static SkDebugGLContext* Create() { + return new SkDebugGLContext; + } +private: + void onPlatformMakeCurrent() const override {} + void onPlatformSwapBuffers() const override {} + GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; } + + SkDebugGLContext(); +}; + +#endif |