aboutsummaryrefslogtreecommitdiffhomepage
path: root/gpu/src/GrVertexBufferAllocPool.cpp
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-12-22 21:39:39 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2010-12-22 21:39:39 +0000
commitac10a2d039c5d52eed66e27cbbc503ab523c1cd5 (patch)
treec5be0c3dd15052016e7d32f376507cb1ea7101dd /gpu/src/GrVertexBufferAllocPool.cpp
parentea8509cd3b1771b36054313d3ccd56679df56044 (diff)
add gpu backend (not hooked up yet)
git-svn-id: http://skia.googlecode.com/svn/trunk@649 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'gpu/src/GrVertexBufferAllocPool.cpp')
-rw-r--r--gpu/src/GrVertexBufferAllocPool.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/gpu/src/GrVertexBufferAllocPool.cpp b/gpu/src/GrVertexBufferAllocPool.cpp
new file mode 100644
index 0000000000..b6f08c97ee
--- /dev/null
+++ b/gpu/src/GrVertexBufferAllocPool.cpp
@@ -0,0 +1,220 @@
+/*
+ Copyright 2010 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#include "GrVertexBufferAllocPool.h"
+#include "GrVertexBuffer.h"
+#include "GrGpu.h"
+
+#define GrVertexBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 10)
+
+GrVertexBufferAllocPool::GrVertexBufferAllocPool(GrGpu* gpu,
+ size_t blockSize,
+ int preallocBufferCnt) :
+ fBlocks(GrMax(8, 2*preallocBufferCnt)) {
+ GrAssert(NULL != gpu);
+ fGpu = gpu;
+ fGpu->ref();
+ fBufferPtr = NULL;
+ fMinBlockSize = GrMax(GrVertexBufferAllocPool_MIN_BLOCK_SIZE, blockSize);
+
+ fPreallocBuffersInUse = 0;
+ fFirstPreallocBuffer = 0;
+ for (int i = 0; i < preallocBufferCnt; ++i) {
+ GrVertexBuffer* buffer = gpu->createVertexBuffer(fMinBlockSize, true);
+ if (NULL != buffer) {
+ *fPreallocBuffers.append() = buffer;
+ buffer->ref();
+ }
+ }
+}
+
+GrVertexBufferAllocPool::~GrVertexBufferAllocPool() {
+ fPreallocBuffers.unrefAll();
+ while (!fBlocks.empty()) {
+ destroyBlock();
+ }
+ fGpu->unref();
+}
+
+void GrVertexBufferAllocPool::reset() {
+ while (!fBlocks.empty()) {
+ destroyBlock();
+ }
+ if (fPreallocBuffers.count()) {
+ // must set this after above loop.
+ fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
+ fPreallocBuffers.count();
+ }
+ GrAssert(0 == fPreallocBuffersInUse);
+}
+
+void GrVertexBufferAllocPool::unlock() {
+ GrAssert((NULL == fBufferPtr) ? (!fBlocks.empty() ||
+ !fBlocks.back().fVertexBuffer->isLocked()) :
+ (!fBlocks.empty() &&
+ fBlocks.back().fVertexBuffer->isLocked()));
+ if (NULL != fBufferPtr) {
+ GrAssert(!fBlocks.empty());
+ GrAssert(fBlocks.back().fVertexBuffer->isLocked());
+ fBufferPtr = NULL;
+ fBlocks.back().fVertexBuffer->unlock();
+ }
+#if GR_DEBUG
+ for (uint32_t i = 0; i < fBlocks.count(); ++i) {
+ GrAssert(!fBlocks[i].fVertexBuffer->isLocked());
+ }
+#endif
+}
+
+void* GrVertexBufferAllocPool::alloc(GrVertexLayout layout,
+ uint32_t vertexCount,
+ GrVertexBuffer** buffer,
+ uint32_t* startVertex) {
+ GrAssert(NULL != buffer);
+ size_t vSize = GrDrawTarget::VertexSize(layout);
+ size_t bytes = vSize * vertexCount;
+
+ if (NULL != fBufferPtr) {
+ GrAssert(!fBlocks.empty());
+ GrAssert(fBlocks.back().fVertexBuffer->isLocked());
+ BufferBlock& back = fBlocks.back();
+ uint32_t usedBytes = back.fVertexBuffer->size() - back.fBytesFree;
+ uint32_t pad = GrUIAlignUpPad(usedBytes, layout);
+ if ((bytes + pad) <= back.fBytesFree) {
+ usedBytes += pad;
+ *startVertex = usedBytes / vSize;
+ *buffer = back.fVertexBuffer;
+ back.fBytesFree -= bytes + pad;
+ return (void*)((intptr_t)fBufferPtr + usedBytes);
+ }
+ }
+
+ if (!createBlock(GrMax(bytes, fMinBlockSize))) {
+ return NULL;
+ }
+ *startVertex = 0;
+ GrAssert(NULL != fBufferPtr);
+ BufferBlock& back = fBlocks.back();
+ *buffer = back.fVertexBuffer;
+ back.fBytesFree -= bytes;
+ return fBufferPtr;
+}
+
+int GrVertexBufferAllocPool::currentBufferVertices(GrVertexLayout layout) const {
+ if (NULL != fBufferPtr) {
+ GrAssert(!fBlocks.empty());
+ const BufferBlock& back = fBlocks.back();
+ GrAssert(back.fVertexBuffer->isLocked());
+ return back.fBytesFree / GrDrawTarget::VertexSize(layout);
+ } else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
+ return fMinBlockSize / GrDrawTarget::VertexSize(layout);
+ }
+ return 0;
+}
+
+int GrVertexBufferAllocPool::preallocatedBuffersRemaining() const {
+ return fPreallocBuffers.count() - fPreallocBuffersInUse;
+}
+
+int GrVertexBufferAllocPool::preallocatedBufferVertices(GrVertexLayout layout) const {
+ return fPreallocBuffers.count() ?
+ (fMinBlockSize / GrDrawTarget::VertexSize(layout)) :
+ 0;
+}
+
+int GrVertexBufferAllocPool::preallocatedBufferCount() const {
+ return fPreallocBuffers.count();
+}
+
+void GrVertexBufferAllocPool::release(size_t bytes) {
+ if (NULL != fBufferPtr) {
+ GrAssert(!fBlocks.empty());
+ BufferBlock& back = fBlocks.back();
+ GrAssert(back.fVertexBuffer->isLocked());
+ size_t bytesUsed = back.fVertexBuffer->size() - back.fBytesFree;
+ if (bytes >= bytesUsed) {
+ destroyBlock();
+ bytes -= bytesUsed;
+ } else {
+ back.fBytesFree += bytes;
+ return;
+ }
+ }
+ GrAssert(NULL == fBufferPtr);
+ GrAssert(fBlocks.empty() ||
+ !fBlocks.back().fVertexBuffer->isLocked());
+ // we don't honor release if it is within an already unlocked VB
+ // Our VB semantics say locking a VB discards its previous content
+ while (!fBlocks.empty() &&
+ bytes >= fBlocks.back().fVertexBuffer->size()) {
+ bytes -= fBlocks.back().fVertexBuffer->size();
+ destroyBlock();
+ }
+}
+
+bool GrVertexBufferAllocPool::createBlock(size_t size) {
+ GrAssert(size >= GrVertexBufferAllocPool_MIN_BLOCK_SIZE);
+
+ BufferBlock& block = fBlocks.push_back();
+
+ if (size == fMinBlockSize &&
+ fPreallocBuffersInUse < fPreallocBuffers.count()) {
+
+ uint32_t nextBuffer = (fPreallocBuffersInUse + fFirstPreallocBuffer) %
+ fPreallocBuffers.count();
+ block.fVertexBuffer = fPreallocBuffers[nextBuffer];
+ block.fVertexBuffer->ref();
+ ++fPreallocBuffersInUse;
+ } else {
+ block.fVertexBuffer = fGpu->createVertexBuffer(size, true);
+ if (NULL == block.fVertexBuffer) {
+ fBlocks.pop_back();
+ return false;
+ }
+ }
+
+ block.fBytesFree = size;
+ if (NULL != fBufferPtr) {
+ GrAssert(fBlocks.count() > 1);
+ BufferBlock& prev = fBlocks.fromBack(1);
+ GrAssert(prev.fVertexBuffer->isLocked());
+ fBufferPtr = NULL;
+ prev.fVertexBuffer->unlock();
+ }
+ fBufferPtr = block.fVertexBuffer->lock();
+ return true;
+}
+
+void GrVertexBufferAllocPool::destroyBlock() {
+ GrAssert(!fBlocks.empty());
+
+ BufferBlock& block = fBlocks.back();
+ if (fPreallocBuffersInUse > 0) {
+ uint32_t prevPreallocBuffer = (fPreallocBuffersInUse +
+ fFirstPreallocBuffer +
+ (fPreallocBuffers.count() - 1)) %
+ fPreallocBuffers.count();
+ if (block.fVertexBuffer == fPreallocBuffers[prevPreallocBuffer]) {
+ --fPreallocBuffersInUse;
+ }
+ }
+ block.fVertexBuffer->unref();
+ fBlocks.pop_back();
+ fBufferPtr = NULL;
+}
+
+