aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--src/gpu/gl/GrGLBufferImpl.cpp5
-rw-r--r--src/gpu/gl/GrGLShaderBuilder.cpp4
-rw-r--r--src/gpu/gl/GrGLVertexArray.cpp123
-rw-r--r--src/gpu/gl/GrGLVertexArray.h147
-rw-r--r--src/gpu/gl/GrGpuGL.cpp154
-rw-r--r--src/gpu/gl/GrGpuGL.h211
-rw-r--r--src/gpu/gl/GrGpuGL_program.cpp77
-rw-r--r--src/gpu/gl/debug/GrGLCreateDebugInterface.cpp2
-rw-r--r--src/gpu/gl/mac/SkNativeGLContext_mac.cpp3
-rw-r--r--src/gpu/gl/win/SkNativeGLContext_win.cpp2
11 files changed, 472 insertions, 258 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index a2644b7b75..41f0f09ee2 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -175,6 +175,8 @@
'<(skia_src_path)/gpu/gl/GrGLUniformManager.cpp',
'<(skia_src_path)/gpu/gl/GrGLUniformManager.h',
'<(skia_src_path)/gpu/gl/GrGLUniformHandle.h',
+ '<(skia_src_path)/gpu/gl/GrGLVertexArray.cpp',
+ '<(skia_src_path)/gpu/gl/GrGLVertexArray.h',
'<(skia_src_path)/gpu/gl/GrGLVertexBuffer.cpp',
'<(skia_src_path)/gpu/gl/GrGLVertexBuffer.h',
'<(skia_src_path)/gpu/gl/GrGpuGL.cpp',
diff --git a/src/gpu/gl/GrGLBufferImpl.cpp b/src/gpu/gl/GrGLBufferImpl.cpp
index d9a8a8eca8..04c90725ae 100644
--- a/src/gpu/gl/GrGLBufferImpl.cpp
+++ b/src/gpu/gl/GrGLBufferImpl.cpp
@@ -57,12 +57,11 @@ void GrGLBufferImpl::abandon() {
void GrGLBufferImpl::bind(GrGpuGL* gpu) const {
VALIDATE();
- GL_CALL(gpu, BindBuffer(fBufferType, fDesc.fID));
if (GR_GL_ARRAY_BUFFER == fBufferType) {
- gpu->notifyVertexBufferBind(fDesc.fID);
+ gpu->bindVertexBuffer(fDesc.fID);
} else {
GrAssert(GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType);
- gpu->notifyIndexBufferBind(fDesc.fID);
+ gpu->bindIndexBufferAndDefaultVertexArray(fDesc.fID);
}
}
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 08ef28e02a..02d6d383b7 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -308,7 +308,9 @@ const char* GrGLShaderBuilder::fragmentPosition() {
#if 1
if (fCtxInfo.caps().fragCoordConventionsSupport()) {
if (!fSetupFragPosition) {
- fFSHeader.append("#extension GL_ARB_fragment_coord_conventions: require\n");
+ if (fCtxInfo.glslGeneration() < k150_GrGLSLGeneration) {
+ fFSHeader.append("#extension GL_ARB_fragment_coord_conventions: require\n");
+ }
fFSInputs.push_back().set(kVec4f_GrSLType,
GrGLShaderVar::kIn_TypeModifier,
"gl_FragCoord",
diff --git a/src/gpu/gl/GrGLVertexArray.cpp b/src/gpu/gl/GrGLVertexArray.cpp
new file mode 100644
index 0000000000..ded4a9a5d2
--- /dev/null
+++ b/src/gpu/gl/GrGLVertexArray.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLVertexArray.h"
+#include "GrGpuGL.h"
+
+#define GPUGL static_cast<GrGpuGL*>(this->getGpu())
+#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X);
+
+void GrGLAttribArrayState::set(const GrGpuGL* gpu,
+ int index,
+ GrGLVertexBuffer* buffer,
+ GrGLint size,
+ GrGLenum type,
+ GrGLboolean normalized,
+ GrGLsizei stride,
+ GrGLvoid* offset) {
+ GrAssert(index >= 0 && index < fAttribArrayStates.count());
+ AttribArrayState* array = &fAttribArrayStates[index];
+ if (!array->fEnableIsValid || !array->fEnabled) {
+ GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(index));
+ array->fEnableIsValid = true;
+ array->fEnabled = true;
+ }
+ if (!array->fAttribPointerIsValid ||
+ array->fVertexBufferID != buffer->bufferID() ||
+ array->fSize != size ||
+ array->fNormalized != normalized ||
+ array->fStride != stride ||
+ array->fOffset != offset) {
+
+ buffer->bind();
+ GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
+ size,
+ type,
+ normalized,
+ stride,
+ offset));
+ array->fAttribPointerIsValid = true;
+ array->fVertexBufferID = buffer->bufferID();
+ array->fSize = size;
+ array->fNormalized = normalized;
+ array->fStride = stride;
+ array->fOffset = offset;
+ }
+}
+
+void GrGLAttribArrayState::disableUnusedAttribArrays(const GrGpuGL* gpu, uint64_t usedMask) {
+ int count = fAttribArrayStates.count();
+ for (int i = 0; i < count; ++i) {
+ if (!(usedMask & 0x1)) {
+ if (!fAttribArrayStates[i].fEnableIsValid || fAttribArrayStates[i].fEnabled) {
+ GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(i));
+ fAttribArrayStates[i].fEnableIsValid = true;
+ fAttribArrayStates[i].fEnabled = false;
+ }
+ }
+ // if the count is greater than 64 then this will become 0 and we will disable arrays 64+.
+ usedMask >>= 1;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+GrGLVertexArray::GrGLVertexArray(GrGpuGL* gpu, GrGLint id, int attribCount)
+ : GrResource(gpu, false)
+ , fID(id)
+ , fAttribArrays(attribCount)
+ , fIndexBufferIDIsValid(false) {
+}
+
+void GrGLVertexArray::onAbandon() {
+ fID = 0;
+ INHERITED::onAbandon();
+}
+
+void GrGLVertexArray::onRelease() {
+ if (0 != fID) {
+ GL_CALL(DeleteVertexArrays(1, &fID));
+ GPUGL->notifyVertexArrayDelete(fID);
+ fID = 0;
+ }
+ INHERITED::onRelease();
+}
+
+GrGLAttribArrayState* GrGLVertexArray::bind() {
+ if (0 == fID) {
+ return NULL;
+ }
+ GPUGL->bindVertexArray(fID);
+ return &fAttribArrays;
+}
+
+GrGLAttribArrayState* GrGLVertexArray::bindWithIndexBuffer(const GrGLIndexBuffer* buffer) {
+ GrGLAttribArrayState* state = this->bind();
+ if (NULL != state && NULL != buffer) {
+ GrGLuint bufferID = buffer->bufferID();
+ if (!fIndexBufferIDIsValid || bufferID != fIndexBufferID) {
+ GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, bufferID));
+ fIndexBufferIDIsValid = true;
+ fIndexBufferID = bufferID;
+ }
+ }
+ return state;
+}
+
+void GrGLVertexArray::notifyIndexBufferDelete(GrGLuint bufferID) {
+ if (fIndexBufferIDIsValid && bufferID == fIndexBufferID) {
+ fIndexBufferID = 0;
+ }
+ }
+
+void GrGLVertexArray::invalidateCachedState() {
+ int count = fAttribArrays.count();
+ for (int i = 0; i < count; ++i) {
+ fAttribArrays.invalidate();
+ }
+ fIndexBufferIDIsValid = false;
+}
diff --git a/src/gpu/gl/GrGLVertexArray.h b/src/gpu/gl/GrGLVertexArray.h
new file mode 100644
index 0000000000..b68e71dbe8
--- /dev/null
+++ b/src/gpu/gl/GrGLVertexArray.h
@@ -0,0 +1,147 @@
+/*
+ * 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 GrGLVertexArray_DEFINED
+#define GrGLVertexArray_DEFINED
+
+#include "GrResource.h"
+#include "gl/GrGLFunctions.h"
+
+#include "SkTArray.h"
+
+class GrGLVertexBuffer;
+class GrGLIndexBuffer;
+class GrGpuGL;
+
+/**
+ * This sets and tracks the vertex attribute array state. It is used internally by GrGLVertexArray
+ * (below) but is separate because it is also used to track the state of vertex array object 0.
+ */
+class GrGLAttribArrayState {
+public:
+ explicit GrGLAttribArrayState(int arrayCount = 0) { this->resize(arrayCount); }
+
+ void resize(int newCount) {
+ fAttribArrayStates.resize_back(newCount);
+ for (int i = 0; i < newCount; ++i) {
+ fAttribArrayStates[i].invalidate();
+ }
+ }
+
+ /**
+ * This function enables and sets vertex attrib state for the specified attrib index. It is
+ * assumed that the GrGLAttribArrayState is tracking the state of the currently bound vertex
+ * array object.
+ */
+ void set(const GrGpuGL*,
+ int index,
+ GrGLVertexBuffer*,
+ GrGLint size,
+ GrGLenum type,
+ GrGLboolean normalized,
+ GrGLsizei stride,
+ GrGLvoid* offset);
+
+ /**
+ * This function disables vertex attribs not present in the mask. It is assumed that the
+ * GrGLAttribArrayState is tracking the state of the currently bound vertex array object.
+ */
+ void disableUnusedAttribArrays(const GrGpuGL*, uint64_t usedAttribArrayMask);
+
+ void invalidate() {
+ int count = fAttribArrayStates.count();
+ for (int i = 0; i < count; ++i) {
+ fAttribArrayStates[i].invalidate();
+ }
+ }
+
+ void notifyVertexBufferDelete(GrGLuint id) {
+ int count = fAttribArrayStates.count();
+ for (int i = 0; i < count; ++i) {
+ if (id == fAttribArrayStates[i].fVertexBufferID) {
+ fAttribArrayStates[i].invalidate();
+ }
+ }
+ }
+
+ /**
+ * The number of attrib arrays that this object is configured to track.
+ */
+ int count() const { return fAttribArrayStates.count(); }
+
+private:
+ /**
+ * Tracks the state of glVertexAttribArray for an attribute index.
+ */
+ struct AttribArrayState {
+ void invalidate() {
+ fEnableIsValid = false;
+ fAttribPointerIsValid = false;
+ }
+
+ bool fEnableIsValid;
+ bool fAttribPointerIsValid;
+ bool fEnabled;
+ GrGLuint fVertexBufferID;
+ GrGLint fSize;
+ GrGLenum fType;
+ GrGLboolean fNormalized;
+ GrGLsizei fStride;
+ GrGLvoid* fOffset;
+ };
+
+ SkSTArray<16, AttribArrayState, true> fAttribArrayStates;
+};
+
+/**
+ * This class represents an OpenGL vertex array object. It manages the lifetime of the vertex array
+ * and is used to track the state of the vertex array to avoid redundant GL calls.
+ */
+class GrGLVertexArray : public GrResource {
+public:
+ GrGLVertexArray(GrGpuGL* gpu, GrGLint id, int attribCount);
+
+ /**
+ * Binds this vertex array. If the ID has been deleted or abandoned then NULL is returned.
+ * Otherwise, the GrGLAttribArrayState that is tracking this vertex array's attrib bindings is
+ * returned.
+ */
+ GrGLAttribArrayState* bind();
+
+ /**
+ * This is a version of the above function that also binds an index buffer to the vertex
+ * array object.
+ */
+ GrGLAttribArrayState* bindWithIndexBuffer(const GrGLIndexBuffer* indexBuffer);
+
+ void notifyIndexBufferDelete(GrGLuint bufferID);
+
+ void notifyVertexBufferDelete(GrGLuint id) {
+ fAttribArrays.notifyVertexBufferDelete(id);
+ }
+
+ GrGLuint arrayID() const { return fID; }
+
+ void invalidateCachedState();
+
+ virtual size_t sizeInBytes() const SK_OVERRIDE { return 0; }
+
+protected:
+ virtual void onAbandon() SK_OVERRIDE;
+
+ virtual void onRelease() SK_OVERRIDE;
+
+private:
+ GrGLuint fID;
+ GrGLAttribArrayState fAttribArrays;
+ GrGLuint fIndexBufferID;
+ bool fIndexBufferIDIsValid;
+
+ typedef GrResource INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 42e83b0435..343cae39f0 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -180,8 +180,6 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context)
fProgramCache = SkNEW_ARGS(ProgramCache, (this->glContext()));
- fHWGeometryState.setMaxAttribArrays(this->glCaps().maxVertexAttributes());
-
GrAssert(this->glCaps().maxVertexAttributes() >= GrDrawState::kVertexAttribCnt);
GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kColorOverrideAttribIndexValue);
GrAssert(this->glCaps().maxVertexAttributes() > GrDrawState::kCoverageOverrideAttribIndexValue);
@@ -423,6 +421,8 @@ void GrGpuGL::onResetContext() {
GL_CALL(Disable(GR_GL_INDEX_LOGIC_OP));
}
if (this->glCaps().imagingSupport()) {
+ // This produces a GL error on the windows NVIDIA driver when using a core profile but
+ // I think that is a driver bug since GL_ARB_imaging is in the extension string.
GL_CALL(Disable(GR_GL_COLOR_TABLE));
}
GL_CALL(Disable(GR_GL_POLYGON_OFFSET_FILL));
@@ -1246,8 +1246,7 @@ GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
} else {
GL_CALL(GenBuffers(1, &desc.fID));
if (desc.fID) {
- GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, desc.fID));
- fHWGeometryState.setVertexBufferID(desc.fID);
+ fHWGeometryState.setVertexBufferID(this, desc.fID);
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
// make sure driver can allocate memory for this buffer
GL_ALLOC_CALL(this->glInterface(),
@@ -1257,8 +1256,7 @@ GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
GL_CALL(DeleteBuffers(1, &desc.fID));
- // deleting bound buffer does implicit bind to 0
- fHWGeometryState.setVertexBufferID(0);
+ this->notifyVertexBufferDelete(desc.fID);
return NULL;
}
GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this, desc));
@@ -1281,8 +1279,7 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
} else {
GL_CALL(GenBuffers(1, &desc.fID));
if (desc.fID) {
- GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, desc.fID));
- fHWGeometryState.setIndexBufferID(desc.fID);
+ fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, desc.fID);
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
// make sure driver can allocate memory for this buffer
GL_ALLOC_CALL(this->glInterface(),
@@ -1292,8 +1289,7 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
desc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
if (CHECK_ALLOC_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
GL_CALL(DeleteBuffers(1, &desc.fID));
- // deleting bound buffer does implicit bind to 0
- fHWGeometryState.setIndexBufferID(0);
+ this->notifyIndexBufferDelete(desc.fID);
return NULL;
}
GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer, (this, desc));
@@ -2165,22 +2161,6 @@ void GrGpuGL::flushMiscFixedFunctionState() {
}
}
-void GrGpuGL::notifyVertexBufferBind(GrGLuint id) {
- fHWGeometryState.setVertexBufferID(id);
-}
-
-void GrGpuGL::notifyVertexBufferDelete(GrGLuint id) {
- fHWGeometryState.notifyVertexBufferDelete(id);
-}
-
-void GrGpuGL::notifyIndexBufferBind(GrGLuint id) {
- fHWGeometryState.setIndexBufferID(id);
-}
-
-void GrGpuGL::notifyIndexBufferDelete(GrGLuint id) {
- fHWGeometryState.notifyIndexBufferDelete(id);
-}
-
void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
GrAssert(NULL != renderTarget);
if (fHWBoundRenderTarget == renderTarget) {
@@ -2323,105 +2303,35 @@ void GrGpuGL::setSpareTextureUnit() {
}
}
-GrGLVertexBuffer* GrGpuGL::setBuffers(bool indexed,
- size_t* vertexOffsetInBytes,
- size_t* indexOffsetInBytes) {
-
- GrAssert(NULL != vertexOffsetInBytes);
-
- const GeometryPoolState& geoPoolState = this->getGeomPoolState();
-
- GrGLVertexBuffer* vbuf;
- switch (this->getGeomSrc().fVertexSrc) {
- case kBuffer_GeometrySrcType:
- *vertexOffsetInBytes = 0;
- vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
- break;
- case kArray_GeometrySrcType:
- case kReserved_GeometrySrcType:
- this->finalizeReservedVertices();
- *vertexOffsetInBytes = geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize;
- vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
- break;
- default:
- vbuf = NULL; // suppress warning
- GrCrash("Unknown geometry src type!");
- }
-
- GrAssert(NULL != vbuf);
- GrAssert(!vbuf->isLocked());
- *vertexOffsetInBytes += vbuf->baseOffset();
-
- if (indexed) {
- GrAssert(NULL != indexOffsetInBytes);
+///////////////////////////////////////////////////////////////////////////////
- GrGLIndexBuffer* ibuf;
- switch (this->getGeomSrc().fIndexSrc) {
- case kBuffer_GeometrySrcType:
- *indexOffsetInBytes = 0;
- ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
- break;
- case kArray_GeometrySrcType:
- case kReserved_GeometrySrcType:
- this->finalizeReservedIndices();
- *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort);
- ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
- break;
- default:
- ibuf = NULL; // suppress warning
- GrCrash("Unknown geometry src type!");
+GrGLAttribArrayState* GrGpuGL::HWGeometryState::bindArrayAndBuffersToDraw(
+ GrGpuGL* gpu,
+ const GrGLVertexBuffer* vbuffer,
+ const GrGLIndexBuffer* ibuffer) {
+ GrAssert(NULL != vbuffer);
+ GrGLAttribArrayState* attribState = &fDefaultVertexArrayAttribState;
+ // We use a vertex array if we're on a core profile and the verts are in a VBO.
+ if (gpu->glCaps().isCoreProfile() && !vbuffer->isCPUBacked()) {
+ if (NULL == fVBOVertexArray || !fVBOVertexArray->isValid()) {
+ SkSafeUnref(fVBOVertexArray);
+ GrGLuint arrayID;
+ GR_GL_CALL(gpu->glInterface(), GenVertexArrays(1, &arrayID));
+ int attrCount = gpu->glCaps().maxVertexAttributes();
+ fVBOVertexArray = SkNEW_ARGS(GrGLVertexArray, (gpu, arrayID, attrCount));
}
-
- GrAssert(NULL != ibuf);
- GrAssert(!ibuf->isLocked());
- *indexOffsetInBytes += ibuf->baseOffset();
- if (!fHWGeometryState.isIndexBufferIDBound(ibuf->bufferID())) {
- ibuf->bind();
- fHWGeometryState.setIndexBufferID(ibuf->bufferID());
+ attribState = fVBOVertexArray->bindWithIndexBuffer(ibuffer);
+ } else {
+ if (NULL != ibuffer) {
+ this->setIndexBufferIDOnDefaultVertexArray(gpu, ibuffer->bufferID());
+ } else {
+ this->setVertexArrayID(gpu, 0);
}
- }
- return vbuf;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrGpuGL::HWGeometryState::AttribArray::set(const GrGpuGL* gpu,
- HWGeometryState* geoState,
- int index,
- GrGLVertexBuffer* buffer,
- GrGLint size,
- GrGLenum type,
- GrGLboolean normalized,
- GrGLsizei stride,
- GrGLvoid* offset) {
- if (!fEnableIsValid || !fEnabled) {
- GR_GL_CALL(gpu->glInterface(), EnableVertexAttribArray(index));
- fEnableIsValid = true;
- fEnabled = true;
- }
- if (!fAttribPointerIsValid ||
- fVertexBufferID != buffer->bufferID() ||
- fSize != size ||
- fNormalized != normalized ||
- fStride != stride ||
- offset != fOffset) {
-
- GrGLuint bufferID = buffer->bufferID();
- if (!geoState->isVertexBufferIDBound(bufferID)) {
- buffer->bind();
- geoState->setVertexBufferID(bufferID);
+ int attrCount = gpu->glCaps().maxVertexAttributes();
+ if (fDefaultVertexArrayAttribState.count() != attrCount) {
+ fDefaultVertexArrayAttribState.resize(attrCount);
}
- GR_GL_CALL(gpu->glInterface(), VertexAttribPointer(index,
- size,
- type,
- normalized,
- stride,
- offset));
- fAttribPointerIsValid = true;
- fVertexBufferID = bufferID;
- fSize = size;
- fNormalized = normalized;
- fStride = stride;
- fOffset = offset;
+ attribState = &fDefaultVertexArrayAttribState;
}
+ return attribState;
}
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index a0194151c7..e4c7197690 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -20,6 +20,7 @@
#include "GrGLProgram.h"
#include "GrGLStencilBuffer.h"
#include "GrGLTexture.h"
+#include "GrGLVertexArray.h"
#include "GrGLVertexBuffer.h"
#include "../GrTHashCache.h"
@@ -54,11 +55,29 @@ public:
const GrGLCaps& glCaps() const { return fGLContext.info().caps(); }
- // Callbacks to update state tracking when related GL objects are bound or deleted
- void notifyVertexBufferBind(GrGLuint id);
- void notifyVertexBufferDelete(GrGLuint id);
- void notifyIndexBufferBind(GrGLuint id);
- void notifyIndexBufferDelete(GrGLuint id);
+ // These functions should be used to bind GL objects. They track the GL state and skip redundant
+ // bindings. Making the equivalent glBind calls directly will confuse the state tracking.
+ void bindVertexArray(GrGLuint id) {
+ fHWGeometryState.setVertexArrayID(this, id);
+ }
+ void bindIndexBufferAndDefaultVertexArray(GrGLuint id) {
+ fHWGeometryState.setIndexBufferIDOnDefaultVertexArray(this, id);
+ }
+ void bindVertexBuffer(GrGLuint id) {
+ fHWGeometryState.setVertexBufferID(this, id);
+ }
+
+ // These callbacks update state tracking when GL objects are deleted. They are called from
+ // GrGLResource onRelease functions.
+ void notifyVertexArrayDelete(GrGLuint id) {
+ fHWGeometryState.notifyVertexArrayDelete(id);
+ }
+ void notifyVertexBufferDelete(GrGLuint id) {
+ fHWGeometryState.notifyVertexBufferDelete(id);
+ }
+ void notifyIndexBufferDelete(GrGLuint id) {
+ fHWGeometryState.notifyIndexBufferDelete(id);
+ }
void notifyTextureDelete(GrGLTexture* texture);
void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
@@ -121,12 +140,6 @@ private:
// an into the index buffer. It does not account for drawInfo.startIndex() but rather the start
// index is relative to the returned offset.
void setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes);
- // binds appropriate vertex and index buffers. It also returns offsets for the vertex and index
- // buffers. These offsets account for placement within a pool buffer or CPU-side addresses for
- // use with buffer 0. They do not account for start values in the DrawInfo (which is not passed
- // here). The vertex buffer that contains the vertex data is returned. It is not necessarily
- // bound.
- GrGLVertexBuffer* setBuffers(bool indexed, size_t* vertexOffsetInBytes, size_t* indexOffsetInBytes);
// Subclasses should call this to flush the blend state.
// The params should be the final coefficients to apply
@@ -268,134 +281,104 @@ private:
*/
class HWGeometryState {
public:
- HWGeometryState() { fAttribArrayCount = 0; this->invalidate();}
-
- void setMaxAttribArrays(int max) {
- fAttribArrayCount = max;
- fAttribArrays.reset(max);
- for (int i = 0; i < fAttribArrayCount; ++i) {
- fAttribArrays[i].invalidate();
- }
- }
+ HWGeometryState() { fVBOVertexArray = NULL; this->invalidate(); }
+
+ ~HWGeometryState() { SkSafeUnref(fVBOVertexArray); }
void invalidate() {
+ fBoundVertexArrayIDIsValid = false;
fBoundVertexBufferIDIsValid = false;
- fBoundIndexBufferIDIsValid = false;
- for (int i = 0; i < fAttribArrayCount; ++i) {
- fAttribArrays[i].invalidate();
- }
+ fDefaultVertexArrayBoundIndexBufferID = false;
+ fDefaultVertexArrayBoundIndexBufferIDIsValid = false;
+ fDefaultVertexArrayAttribState.invalidate();
}
- void notifyVertexBufferDelete(GrGLuint id) {
- if (0 != id) {
- if (this->isVertexBufferIDBound(id)) {
- // deleting bound buffer does implied bind to 0
- this->setVertexBufferID(0);
- }
- for (int i = 0; i < fAttribArrayCount; ++i) {
- if (fAttribArrays[i].isVertexBufferIDBound(id)) {
- fAttribArrays[i].invalidate();
- }
- }
+ void notifyVertexArrayDelete(GrGLuint id) {
+ if (fBoundVertexArrayIDIsValid && fBoundVertexArrayID == id) {
+ // Does implicit bind to 0
+ fBoundVertexArrayID = 0;
}
}
- void notifyIndexBufferDelete(GrGLuint id) {
- if (0 != id) {
- if (this->isIndexBufferIDBound(id)) {
- // deleting bound buffer does implied bind to 0
- this->setIndexBufferID(0);
- }
+ void setVertexArrayID(GrGpuGL* gpu, GrGLuint arrayID) {
+ if (!gpu->glCaps().vertexArrayObjectSupport()) {
+ GrAssert(0 == arrayID);
+ return;
+ }
+ if (!fBoundVertexArrayIDIsValid || arrayID != fBoundVertexArrayID) {
+ GR_GL_CALL(gpu->glInterface(), BindVertexArray(arrayID));
+ fBoundVertexArrayIDIsValid = true;
+ fBoundVertexArrayID = arrayID;
}
}
- void setVertexBufferID(GrGLuint id) {
- fBoundVertexBufferIDIsValid = true;
- fBoundVertexBufferID = id;
- }
-
- void setIndexBufferID(GrGLuint id) {
- fBoundIndexBufferIDIsValid = true;
- fBoundIndexBufferID = id;
- }
-
- bool isVertexBufferIDBound(GrGLuint id) const {
- return fBoundVertexBufferIDIsValid && id == fBoundVertexBufferID;
+ void notifyVertexBufferDelete(GrGLuint id) {
+ if (fBoundVertexBufferIDIsValid && id == fBoundVertexBufferID) {
+ fBoundVertexBufferID = 0;
+ }
+ if (NULL != fVBOVertexArray) {
+ fVBOVertexArray->notifyVertexBufferDelete(id);
+ }
+ fDefaultVertexArrayAttribState.notifyVertexBufferDelete(id);
}
- bool isIndexBufferIDBound(GrGLuint id) const {
- return fBoundIndexBufferIDIsValid && id == fBoundIndexBufferID;
+ void notifyIndexBufferDelete(GrGLuint id) {
+ if (fDefaultVertexArrayBoundIndexBufferIDIsValid &&
+ id == fDefaultVertexArrayBoundIndexBufferID) {
+ fDefaultVertexArrayBoundIndexBufferID = 0;
+ }
+ if (NULL != fVBOVertexArray) {
+ fVBOVertexArray->notifyIndexBufferDelete(id);
+ }
}
- void setAttribArray(const GrGpuGL* gpu,
- int index,
- GrGLVertexBuffer* vertexBuffer,
- GrGLint size,
- GrGLenum type,
- GrGLboolean normalized,
- GrGLsizei stride,
- GrGLvoid* offset) {
- GrAssert(index >= 0 && index < fAttribArrayCount);
- AttribArray* attrib = fAttribArrays.get() + index;
- attrib->set(gpu, this, index, vertexBuffer, size, type, normalized, stride, offset);
+ void setVertexBufferID(GrGpuGL* gpu, GrGLuint id) {
+ if (!fBoundVertexBufferIDIsValid || id != fBoundVertexBufferID) {
+ GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ARRAY_BUFFER, id));
+ fBoundVertexBufferIDIsValid = true;
+ fBoundVertexBufferID = id;
+ }
}
- void disableUnusedAttribArrays(const GrGpuGL* gpu,
- uint32_t usedAttribIndexMask) {
- for (int i = 0; i < fAttribArrayCount; ++i) {
- if (!(usedAttribIndexMask & (1 << i))) {
- fAttribArrays[i].disable(gpu, i);
- }
+ /**
+ * Binds the default vertex array and binds the index buffer. This is used when binding
+ * an index buffer in order to update it.
+ */
+ void setIndexBufferIDOnDefaultVertexArray(GrGpuGL* gpu, GrGLuint id) {
+ this->setVertexArrayID(gpu, 0);
+ if (!fDefaultVertexArrayBoundIndexBufferIDIsValid ||
+ id != fDefaultVertexArrayBoundIndexBufferID) {
+ GR_GL_CALL(gpu->glInterface(), BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, id));
+ fDefaultVertexArrayBoundIndexBufferIDIsValid = true;
+ fDefaultVertexArrayBoundIndexBufferID = id;
}
}
+ /**
+ * Binds the vertex array object that should be used to render from the vertex buffer.
+ * The vertex array is bound and its attrib array state object is returned. The vertex
+ * buffer is bound. The index buffer (if non-NULL) is bound to the vertex array. The
+ * returned GrGLAttribArrayState should be used to set vertex attribute arrays.
+ */
+ GrGLAttribArrayState* bindArrayAndBuffersToDraw(GrGpuGL* gpu,
+ const GrGLVertexBuffer* vbuffer,
+ const GrGLIndexBuffer* ibuffer);
+
private:
+ GrGLuint fBoundVertexArrayID;
GrGLuint fBoundVertexBufferID;
- GrGLuint fBoundIndexBufferID;
+ bool fBoundVertexArrayIDIsValid;
bool fBoundVertexBufferIDIsValid;
- bool fBoundIndexBufferIDIsValid;
- struct AttribArray {
- public:
- void set(const GrGpuGL* gpu,
- HWGeometryState* geoState,
- int index,
- GrGLVertexBuffer* vertexBuffer,
- GrGLint size,
- GrGLenum type,
- GrGLboolean normalized,
- GrGLsizei stride,
- GrGLvoid* offset);
-
- void disable(const GrGpuGL* gpu, int index) {
- if (!fEnableIsValid || fEnabled) {
- GR_GL_CALL(gpu->glInterface(), DisableVertexAttribArray(index));
- fEnableIsValid = true;
- fEnabled = false;
- }
- }
-
- void invalidate() {
- fEnableIsValid = false;
- fAttribPointerIsValid = false;
- }
+ GrGLuint fDefaultVertexArrayBoundIndexBufferID;
+ bool fDefaultVertexArrayBoundIndexBufferIDIsValid;
+ // We return a non-const pointer to this from bindArrayAndBuffersToDraw when vertex array 0
+ // is bound. However, this class is internal to GrGpuGL and this object never leaks out of
+ // GrGpuGL.
+ GrGLAttribArrayState fDefaultVertexArrayAttribState;
- bool isVertexBufferIDBound(GrGLuint id) const {
- return fAttribPointerIsValid && id == fVertexBufferID;
- }
- private:
- bool fEnableIsValid;
- bool fAttribPointerIsValid;
- bool fEnabled;
- GrGLuint fVertexBufferID;
- GrGLint fSize;
- GrGLenum fType;
- GrGLboolean fNormalized;
- GrGLsizei fStride;
- GrGLvoid* fOffset;
- };
- SkAutoTArray<AttribArray> fAttribArrays;
- int fAttribArrayCount;
+ // This is used when we're using a core profile and the vertices are in a VBO.
+ GrGLVertexArray* fVBOVertexArray;
} fHWGeometryState;
struct {
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index c65f0b6957..c087073ff7 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -217,9 +217,56 @@ void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
GrGLsizei stride = this->getDrawState().getVertexSize();
- size_t vertexOffset;
- GrGLVertexBuffer* vb= this->setBuffers(info.isIndexed(), &vertexOffset, indexOffsetInBytes);
- vertexOffset += stride * info.startVertex();
+ size_t vertexOffsetInBytes = stride * info.startVertex();
+
+ const GeometryPoolState& geoPoolState = this->getGeomPoolState();
+
+ GrGLVertexBuffer* vbuf;
+ switch (this->getGeomSrc().fVertexSrc) {
+ case kBuffer_GeometrySrcType:
+ vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
+ break;
+ case kArray_GeometrySrcType:
+ case kReserved_GeometrySrcType:
+ this->finalizeReservedVertices();
+ vertexOffsetInBytes += geoPoolState.fPoolStartVertex * this->getGeomSrc().fVertexSize;
+ vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
+ break;
+ default:
+ vbuf = NULL; // suppress warning
+ GrCrash("Unknown geometry src type!");
+ }
+
+ GrAssert(NULL != vbuf);
+ GrAssert(!vbuf->isLocked());
+ vertexOffsetInBytes += vbuf->baseOffset();
+
+ GrGLIndexBuffer* ibuf = NULL;
+ if (info.isIndexed()) {
+ GrAssert(NULL != indexOffsetInBytes);
+
+ switch (this->getGeomSrc().fIndexSrc) {
+ case kBuffer_GeometrySrcType:
+ *indexOffsetInBytes = 0;
+ ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
+ break;
+ case kArray_GeometrySrcType:
+ case kReserved_GeometrySrcType:
+ this->finalizeReservedIndices();
+ *indexOffsetInBytes = geoPoolState.fPoolStartIndex * sizeof(GrGLushort);
+ ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
+ break;
+ default:
+ ibuf = NULL; // suppress warning
+ GrCrash("Unknown geometry src type!");
+ }
+
+ GrAssert(NULL != ibuf);
+ GrAssert(!ibuf->isLocked());
+ *indexOffsetInBytes += ibuf->baseOffset();
+ }
+ GrGLAttribArrayState* attribState =
+ fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf);
uint32_t usedAttribArraysMask = 0;
const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs();
@@ -229,16 +276,16 @@ void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) {
usedAttribArraysMask |= (1 << vertexAttribIndex);
GrVertexAttribType attribType = vertexAttrib->fType;
- fHWGeometryState.setAttribArray(this,
- vertexAttribIndex,
- vb,
- GrGLProgram::kAttribLayouts[attribType].fCount,
- GrGLProgram::kAttribLayouts[attribType].fType,
- GrGLProgram::kAttribLayouts[attribType].fNormalized,
- stride,
- reinterpret_cast<GrGLvoid*>(
- vertexOffset + vertexAttrib->fOffset));
- }
-
- fHWGeometryState.disableUnusedAttribArrays(this, usedAttribArraysMask);
+ attribState->set(this,
+ vertexAttribIndex,
+ vbuf,
+ GrGLProgram::kAttribLayouts[attribType].fCount,
+ GrGLProgram::kAttribLayouts[attribType].fType,
+ GrGLProgram::kAttribLayouts[attribType].fNormalized,
+ stride,
+ reinterpret_cast<GrGLvoid*>(
+ vertexOffsetInBytes + vertexAttrib->fOffset));
+ }
+
+ attribState->disableUnusedAttribArrays(this, usedAttribArraysMask);
}
diff --git a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
index f8c5b1fdcc..1cf9b53442 100644
--- a/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
+++ b/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp
@@ -559,7 +559,7 @@ GrGLvoid GR_GL_FUNCTION_TYPE debugGLDeleteVertexArrays(GrGLsizei n, const GrGLui
GrGLvoid GR_GL_FUNCTION_TYPE debugGLBindVertexArray(GrGLuint id) {
GrVertexArrayObj* array = GR_FIND(id, GrVertexArrayObj, GrDebugGL::kVertexArray_ObjTypes);
- GrAlwaysAssert(array);
+ GrAlwaysAssert((0 == id) || NULL != array);
GrDebugGL::getInstance()->setVertexArray(array);
}
diff --git a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
index b821f3dc11..2c43c3d2d4 100644
--- a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
+++ b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
@@ -6,6 +6,7 @@
* found in the LICENSE file.
*/
#include "gl/SkNativeGLContext.h"
+#include "AvailabilityMacros.h"
SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
fOldCGLContext = CGLGetCurrentContext();
@@ -35,7 +36,7 @@ const GrGLInterface* SkNativeGLContext::createGLContext() {
SkASSERT(NULL == fContext);
CGLPixelFormatAttribute attributes[] = {
-#if 0
+#if MAC_OS_X_VERSION_10_7
kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
#endif
(CGLPixelFormatAttribute)0
diff --git a/src/gpu/gl/win/SkNativeGLContext_win.cpp b/src/gpu/gl/win/SkNativeGLContext_win.cpp
index b5a6053b92..4c736994fe 100644
--- a/src/gpu/gl/win/SkNativeGLContext_win.cpp
+++ b/src/gpu/gl/win/SkNativeGLContext_win.cpp
@@ -86,7 +86,7 @@ const GrGLInterface* SkNativeGLContext::createGLContext() {
return NULL;
}
- if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, false))) {
+ if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, true))) {
SkDebugf("Could not create rendering context.\n");
this->destroyGLContext();
return NULL;