Add support for vertex data rendered from CPU arrays.

Review URL: https://codereview.appspot.com/7380044

git-svn-id: http://skia.googlecode.com/svn/trunk@7807 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2013-02-21 14:33:46 +00:00
parent d454ec135e
commit ee3bc3b267
9 changed files with 136 additions and 66 deletions

View File

@ -296,9 +296,21 @@ bool GrBufferAllocPool::createBlock(size_t requestSize) {
GrAssert(NULL == fBufferPtr);
if (fGpu->getCaps().bufferLockSupport() &&
size > GR_GEOM_BUFFER_LOCK_THRESHOLD &&
(!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) {
// If the buffer is CPU-backed we lock it because it is free to do so and saves a copy.
// Otherwise when buffer locking is supported:
// a) If the frequently reset hint is set we only lock when the requested size meets a
// threshold (since we don't expect it is likely that we will see more vertex data)
// b) If the hint is not set we lock if the buffer size is greater than the threshold.
bool attemptLock = block.fBuffer->isCPUBacked();
if (!attemptLock && fGpu->getCaps().bufferLockSupport()) {
if (fFrequentResetHint) {
attemptLock = requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD;
} else {
attemptLock = size > GR_GEOM_BUFFER_LOCK_THRESHOLD;
}
}
if (attemptLock) {
fBufferPtr = block.fBuffer->lock();
}

View File

@ -28,12 +28,22 @@ public:
*/
bool dynamic() const { return fDynamic; }
/**
* Returns true if the buffer is a wrapper around a CPU array. If true it
* indicates that lock will always succeed and will be free.
*/
bool isCPUBacked() const { return fCPUBacked; }
/**
* Locks the buffer to be written by the CPU.
*
* The previous content of the buffer is invalidated. It is an error
* to draw from the buffer while it is locked. It is an error to call lock
* on an already locked buffer.
* on an already locked buffer. It may fail if the backend doesn't support
* locking the buffer. If the buffer is CPU backed then it will always
* succeed and is a free operation. Must be matched by an unlock() call.
* Currently only one lock at a time is supported (no nesting of
* lock/unlock).
*
* @return a pointer to the data or NULL if the lock fails.
*/
@ -65,7 +75,7 @@ public:
* Updates the buffer data.
*
* The size of the buffer will be preserved. The src data will be
* placed at the begining of the buffer and any remaining contents will
* placed at the beginning of the buffer and any remaining contents will
* be undefined.
*
* @return returns true if the update succeeds, false otherwise.
@ -76,14 +86,16 @@ public:
virtual size_t sizeInBytes() const { return fSizeInBytes; }
protected:
GrGeometryBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic)
GrGeometryBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic, bool cpuBacked)
: INHERITED(gpu, isWrapped)
, fSizeInBytes(sizeInBytes)
, fDynamic(dynamic) {}
, fDynamic(dynamic)
, fCPUBacked(cpuBacked) {}
private:
size_t fSizeInBytes;
bool fDynamic;
bool fCPUBacked;
typedef GrResource INHERITED;
};

View File

@ -24,8 +24,8 @@ public:
return this->sizeInBytes() / (sizeof(uint16_t) * 6);
}
protected:
GrIndexBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic)
: INHERITED(gpu, isWrapped, sizeInBytes, dynamic) {}
GrIndexBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic, bool cpuBacked)
: INHERITED(gpu, isWrapped, sizeInBytes, dynamic, cpuBacked) {}
private:
typedef GrGeometryBuffer INHERITED;
};

View File

@ -15,8 +15,8 @@
class GrVertexBuffer : public GrGeometryBuffer {
protected:
GrVertexBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic)
: INHERITED(gpu, isWrapped, sizeInBytes, dynamic) {}
GrVertexBuffer(GrGpu* gpu, bool isWrapped, size_t sizeInBytes, bool dynamic, bool cpuBacked)
: INHERITED(gpu, isWrapped, sizeInBytes, dynamic, cpuBacked) {}
private:
typedef GrGeometryBuffer INHERITED;
};

View File

@ -10,16 +10,32 @@
#define GL_CALL(GPU, X) GR_GL_CALL(GPU->glInterface(), X)
#if GR_DEBUG
#define VALIDATE() this->validate()
#else
#define VALIDATE() do {} while(false)
#endif
GrGLBufferImpl::GrGLBufferImpl(GrGpuGL* gpu, const Desc& desc, GrGLenum bufferType)
: fDesc(desc)
, fBufferType(bufferType)
, fLockPtr(NULL) {
GrAssert(GR_GL_ARRAY_BUFFER == bufferType || GR_GL_ELEMENT_ARRAY_BUFFER == bufferType);
if (0 == desc.fID) {
fCPUData = sk_malloc_flags(desc.fSizeInBytes, SK_MALLOC_THROW);
} else {
fCPUData = NULL;
}
VALIDATE();
}
void GrGLBufferImpl::release(GrGpuGL* gpu) {
// make sure we've not been abandoned
if (fDesc.fID && !fDesc.fIsWrapped) {
// make sure we've not been abandoned or already released
if (NULL != fCPUData) {
VALIDATE();
sk_free(fCPUData);
fCPUData = NULL;
} else if (fDesc.fID && !fDesc.fIsWrapped) {
VALIDATE();
GL_CALL(gpu, DeleteBuffers(1, &fDesc.fID));
if (GR_GL_ARRAY_BUFFER == fBufferType) {
gpu->notifyVertexBufferDelete(fDesc.fID);
@ -29,14 +45,18 @@ void GrGLBufferImpl::release(GrGpuGL* gpu) {
}
fDesc.fID = 0;
}
fLockPtr = NULL;
}
void GrGLBufferImpl::abandon() {
fDesc.fID = 0;
fLockPtr = NULL;
sk_free(fCPUData);
fCPUData = NULL;
}
void GrGLBufferImpl::bind(GrGpuGL* gpu) const {
VALIDATE();
GL_CALL(gpu, BindBuffer(fBufferType, fDesc.fID));
if (GR_GL_ARRAY_BUFFER == fBufferType) {
gpu->notifyVertexBufferBind(fDesc.fID);
@ -47,9 +67,11 @@ void GrGLBufferImpl::bind(GrGpuGL* gpu) const {
}
void* GrGLBufferImpl::lock(GrGpuGL* gpu) {
GrAssert(0 != fDesc.fID);
VALIDATE();
GrAssert(!this->isLocked());
if (gpu->getCaps().bufferLockSupport()) {
if (0 == fDesc.fID) {
fLockPtr = fCPUData;
} else if (gpu->getCaps().bufferLockSupport()) {
this->bind(gpu);
// Let driver know it can discard the old data
GL_CALL(gpu, BufferData(fBufferType,
@ -59,34 +81,35 @@ void* GrGLBufferImpl::lock(GrGpuGL* gpu) {
GR_GL_CALL_RET(gpu->glInterface(),
fLockPtr,
MapBuffer(fBufferType, GR_GL_WRITE_ONLY));
return fLockPtr;
}
return NULL;
return fLockPtr;
}
void GrGLBufferImpl::unlock(GrGpuGL* gpu) {
GrAssert(0 != fDesc.fID);
VALIDATE();
GrAssert(this->isLocked());
if (0 != fDesc.fID) {
GrAssert(gpu->getCaps().bufferLockSupport());
this->bind(gpu);
GL_CALL(gpu, UnmapBuffer(fBufferType));
}
fLockPtr = NULL;
}
bool GrGLBufferImpl::isLocked() const {
GrAssert(0 != fDesc.fID);
VALIDATE();
return NULL != fLockPtr;
}
bool GrGLBufferImpl::updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInBytes) {
GrAssert(!this->isLocked());
VALIDATE();
if (srcSizeInBytes > fDesc.fSizeInBytes) {
return false;
}
if (0 == fDesc.fID) {
return false;
memcpy(fCPUData, src, srcSizeInBytes);
return true;
}
this->bind(gpu);
GrGLenum usage = fDesc.fDynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
@ -129,3 +152,10 @@ bool GrGLBufferImpl::updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInB
#endif
return true;
}
void GrGLBufferImpl::validate() const {
GrAssert(GR_GL_ARRAY_BUFFER == fBufferType || GR_GL_ELEMENT_ARRAY_BUFFER == fBufferType);
GrAssert((0 == fDesc.fID) == (NULL != fCPUData));
GrAssert(0 != fDesc.fID || !fDesc.fIsWrapped);
GrAssert(NULL == fCPUData || NULL == fLockPtr || fCPUData == fLockPtr);
}

View File

@ -21,7 +21,7 @@ class GrGLBufferImpl : public GrNoncopyable {
public:
struct Desc {
bool fIsWrapped;
GrGLuint fID;
GrGLuint fID; // set to 0 to indicate buffer is CPU-backed and not a VBO.
size_t fSizeInBytes;
bool fDynamic;
};
@ -36,7 +36,7 @@ public:
void release(GrGpuGL* gpu);
GrGLuint bufferID() const { return fDesc.fID; }
size_t baseOffset() const { return 0; }
size_t baseOffset() const { return reinterpret_cast<size_t>(fCPUData); }
void bind(GrGpuGL* gpu) const;
@ -47,8 +47,11 @@ public:
bool updateData(GrGpuGL* gpu, const void* src, size_t srcSizeInBytes);
private:
void validate() const;
Desc fDesc;
GrGLenum fBufferType; // GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER
void* fCPUData;
void* fLockPtr;
typedef GrNoncopyable INHERITED;

View File

@ -9,7 +9,7 @@
#include "GrGpuGL.h"
GrGLIndexBuffer::GrGLIndexBuffer(GrGpuGL* gpu, const Desc& desc)
: INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic)
: INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
, fImpl(gpu, desc, GR_GL_ELEMENT_ARRAY_BUFFER) {
}

View File

@ -9,7 +9,7 @@
#include "GrGpuGL.h"
GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu, const Desc& desc)
: INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic)
: INHERITED(gpu, desc.fIsWrapped, desc.fSizeInBytes, desc.fDynamic, 0 == desc.fID)
, fImpl(gpu, desc, GR_GL_ARRAY_BUFFER) {
}

View File

@ -1231,9 +1231,15 @@ GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
desc.fSizeInBytes = size;
desc.fIsWrapped = false;
if (false && desc.fDynamic) {
desc.fID = 0;
GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this, desc));
return vertexBuffer;
} else {
GL_CALL(GenBuffers(1, &desc.fID));
if (desc.fID) {
GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, desc.fID));
fHWGeometryState.setVertexBufferID(desc.fID);
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
// make sure driver can allocate memory for this buffer
GL_ALLOC_CALL(this->glInterface(),
@ -1248,11 +1254,11 @@ GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
return NULL;
}
GrGLVertexBuffer* vertexBuffer = SkNEW_ARGS(GrGLVertexBuffer, (this, desc));
fHWGeometryState.setVertexBufferID(desc.fID);
return vertexBuffer;
}
return NULL;
}
}
GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
GrGLIndexBuffer::Desc desc;
@ -1260,9 +1266,15 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
desc.fSizeInBytes = size;
desc.fIsWrapped = false;
if (false && desc.fDynamic) {
desc.fID = 0;
GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer, (this, desc));
return indexBuffer;
} else {
GL_CALL(GenBuffers(1, &desc.fID));
if (desc.fID) {
GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, desc.fID));
fHWGeometryState.setIndexBufferID(desc.fID);
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
// make sure driver can allocate memory for this buffer
GL_ALLOC_CALL(this->glInterface(),
@ -1277,11 +1289,11 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
return NULL;
}
GrIndexBuffer* indexBuffer = SkNEW_ARGS(GrGLIndexBuffer, (this, desc));
fHWGeometryState.setIndexBufferID(desc.fID);
return indexBuffer;
}
return NULL;
}
}
GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
GrAssert(fCaps.pathStencilingSupport());
@ -2354,6 +2366,7 @@ GrGLVertexBuffer* GrGpuGL::setBuffers(bool indexed,
GrAssert(NULL != ibuf);
GrAssert(!ibuf->isLocked());
*indexOffsetInBytes += ibuf->baseOffset();
if (!fHWGeometryState.isIndexBufferIDBound(ibuf->bufferID())) {
ibuf->bind();
fHWGeometryState.setIndexBufferID(ibuf->bufferID());