aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2014-11-21 14:38:06 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-11-21 14:38:06 -0800
commit77d77f446d1685cd21465627a747341c3c3665e4 (patch)
tree3d771f0dd9ab2a38d17cd9a280eb2e799327ac7f /src/gpu
parentebacb6127a952910f43a59460af43427d93df46c (diff)
Add pop_back to GrTRecorder.h
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrTRecorder.h83
1 files changed, 71 insertions, 12 deletions
diff --git a/src/gpu/GrTRecorder.h b/src/gpu/GrTRecorder.h
index ab559e4a59..bddf1978d8 100644
--- a/src/gpu/GrTRecorder.h
+++ b/src/gpu/GrTRecorder.h
@@ -54,7 +54,7 @@ public:
and after calls to reset().
*/
GrTRecorder(int initialSizeInBytes)
- : fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes))),
+ : fHeadBlock(MemBlock::Alloc(LengthOf(initialSizeInBytes), NULL)),
fTailBlock(fHeadBlock),
fLastItem(NULL) {}
@@ -71,6 +71,12 @@ public:
}
/**
+ * Removes and destroys the last block added to the recorder. It may not be called when the
+ * recorder is empty.
+ */
+ void pop_back();
+
+ /**
* Destruct all items in the list and reset to empty.
*/
void reset();
@@ -100,35 +106,49 @@ private:
static int LengthOf(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeof(TAlign); }
struct Header {
- int fTotalLength;
+ int fTotalLength; // The length of an entry including header, item, and data in TAligns.
+ int fPrevLength; // Same but for the previous entry. Used for iterating backwards.
};
template<typename TItem> TItem* alloc_back(int dataLength);
struct MemBlock : SkNoncopyable {
- static MemBlock* Alloc(int length) {
+ /** Allocates a new block and appends it to prev if not NULL. The length param is in units
+ of TAlign. */
+ static MemBlock* Alloc(int length, MemBlock* prev) {
MemBlock* block = reinterpret_cast<MemBlock*>(
sk_malloc_throw(sizeof(TAlign) * (length_of<MemBlock>::kValue + length)));
block->fLength = length;
block->fBack = 0;
block->fNext = NULL;
+ block->fPrev = prev;
+ if (prev) {
+ SkASSERT(NULL == prev->fNext);
+ prev->fNext = block;
+ }
return block;
}
+ // Frees from this block forward. Also adjusts prev block's next ptr.
static void Free(MemBlock* block) {
- if (!block) {
- return;
+ if (block && block->fPrev) {
+ SkASSERT(block->fPrev->fNext == block);
+ block->fPrev->fNext = NULL;
+ }
+ while (block) {
+ MemBlock* next = block->fNext;
+ sk_free(block);
+ block = next;
}
- Free(block->fNext);
- sk_free(block);
}
TAlign& operator [](int i) {
return reinterpret_cast<TAlign*>(this)[length_of<MemBlock>::kValue + i];
}
- int fLength;
- int fBack;
+ int fLength; // Length in units of TAlign of the block.
+ int fBack; // Offset, in TAligns, to unused portion of the memory block.
MemBlock* fNext;
+ MemBlock* fPrev;
};
MemBlock* const fHeadBlock;
MemBlock* fTailBlock;
@@ -147,15 +167,54 @@ private:
////////////////////////////////////////////////////////////////////////////////
template<typename TBase, typename TAlign>
+void GrTRecorder<TBase, TAlign>::pop_back() {
+ SkASSERT(fLastItem);
+ Header* header = reinterpret_cast<Header*>(
+ reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue);
+ fTailBlock->fBack -= header->fTotalLength;
+ fLastItem->~TBase();
+
+ int lastItemLength = header->fPrevLength;
+
+ if (!header->fPrevLength) {
+ // We popped the first entry in the recorder.
+ SkASSERT(0 == fTailBlock->fBack);
+ fLastItem = NULL;
+ return;
+ }
+ if (!fTailBlock->fBack) {
+ // We popped the last entry in a block that isn't the head block. Move back a block but
+ // don't free it since we'll probably grow into it shortly.
+ fTailBlock = fTailBlock->fPrev;
+ SkASSERT(fTailBlock);
+ }
+ fLastItem = reinterpret_cast<TBase*>(
+ &(*fTailBlock)[fTailBlock->fBack - lastItemLength + length_of<Header>::kValue]);
+}
+
+template<typename TBase, typename TAlign>
template<typename TItem>
TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) {
+ // Find the header of the previous entry and get its length. We need to store that in the new
+ // header for backwards iteration (pop_back()).
+ int prevLength = 0;
+ if (fLastItem) {
+ Header* lastHeader = reinterpret_cast<Header*>(
+ reinterpret_cast<TAlign*>(fLastItem) - length_of<Header>::kValue);
+ prevLength = lastHeader->fTotalLength;
+ }
+
const int totalLength = length_of<Header>::kValue + length_of<TItem>::kValue + dataLength;
+ // Check if there is room in the current block and if not walk to next (allocating if
+ // necessary). Note that pop_back() and reset() can leave the recorder in a state where it
+ // has preallocated blocks hanging off the tail that are currently unused.
while (fTailBlock->fBack + totalLength > fTailBlock->fLength) {
if (!fTailBlock->fNext) {
- fTailBlock->fNext = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLength));
+ fTailBlock = MemBlock::Alloc(SkTMax(2 * fTailBlock->fLength, totalLength), fTailBlock);
+ } else {
+ fTailBlock = fTailBlock->fNext;
}
- fTailBlock = fTailBlock->fNext;
SkASSERT(0 == fTailBlock->fBack);
}
@@ -164,6 +223,7 @@ TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) {
&(*fTailBlock)[fTailBlock->fBack + length_of<Header>::kValue]);
header->fTotalLength = totalLength;
+ header->fPrevLength = prevLength;
fLastItem = rawPtr;
fTailBlock->fBack += totalLength;
@@ -225,7 +285,6 @@ void GrTRecorder<TBase, TAlign>::reset() {
// everything else.
if (fTailBlock->fBack <= fTailBlock->fLength / 2) {
MemBlock::Free(fTailBlock->fNext);
- fTailBlock->fNext = NULL;
} else if (fTailBlock->fNext) {
MemBlock::Free(fTailBlock->fNext->fNext);
fTailBlock->fNext->fNext = NULL;