diff options
author | cdalton <cdalton@nvidia.com> | 2015-04-16 10:42:49 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-16 10:42:49 -0700 |
commit | 72badbd99e2321bfbcb22f78218bbafa71af4698 (patch) | |
tree | b8bbe4a69fdb0d3bc584fdfc30d69e3c84ca2fd1 | |
parent | bdb0bf5f8858043878d8a4fa8130c6c87bef3fd4 (diff) |
Add ReverseIter to GrTRecorder
BUG=skia:
Review URL: https://codereview.chromium.org/1035083004
-rw-r--r-- | src/gpu/GrTRecorder.h | 62 | ||||
-rw-r--r-- | tests/GrTRecorderTest.cpp | 69 |
2 files changed, 110 insertions, 21 deletions
diff --git a/src/gpu/GrTRecorder.h b/src/gpu/GrTRecorder.h index bddf1978d8..1c49c86f38 100644 --- a/src/gpu/GrTRecorder.h +++ b/src/gpu/GrTRecorder.h @@ -46,6 +46,7 @@ template<typename TItem> struct GrTRecorderAllocWrapper; template<typename TBase, typename TAlign> class GrTRecorder : SkNoncopyable { public: class Iter; + class ReverseIter; /** * Create a recorder. @@ -162,6 +163,7 @@ private: const GrTRecorderAllocWrapper<UItem>&); friend class Iter; + friend class ReverseIter; }; //////////////////////////////////////////////////////////////////////////////// @@ -182,7 +184,7 @@ void GrTRecorder<TBase, TAlign>::pop_back() { fLastItem = NULL; return; } - if (!fTailBlock->fBack) { + while (!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; @@ -239,6 +241,15 @@ TItem* GrTRecorder<TBase, TAlign>::alloc_back(int dataLength) { return rawPtr; } +/** + * Iterates through a recorder from front to back. The initial state of the iterator is + * to not have the front item loaded yet; next() must be called first. Usage model: + * + * GrTRecorder<TBase, TAlign>::Iter iter(recorder); + * while (iter.next()) { + * iter->doSomething(); + * } + */ template<typename TBase, typename TAlign> class GrTRecorder<TBase, TAlign>::Iter { public: @@ -273,6 +284,55 @@ private: TBase* fItem; }; +/** + * Iterates through a recorder in reverse, from back to front. This version mirrors "Iter", + * so the initial state is to have recorder.back() loaded already. (Note that this will + * assert if the recorder is empty.) Usage model: + * + * GrTRecorder<TBase, TAlign>::ReverseIter reverseIter(recorder); + * do { + * reverseIter->doSomething(); + * } while (reverseIter.previous()); + */ +template<typename TBase, typename TAlign> +class GrTRecorder<TBase, TAlign>::ReverseIter { +public: + ReverseIter(GrTRecorder& recorder) + : fBlock(recorder.fTailBlock), + fItem(&recorder.back()) { + Header* lastHeader = reinterpret_cast<Header*>( + reinterpret_cast<TAlign*>(fItem) - length_of<Header>::kValue); + fPosition = fBlock->fBack - lastHeader->fTotalLength; + } + + bool previous() { + Header* header = reinterpret_cast<Header*>(&(*fBlock)[fPosition]); + + while (0 == fPosition) { + if (!fBlock->fPrev) { + // We've reached the front of the recorder. + return false; + } + fBlock = fBlock->fPrev; + fPosition = fBlock->fBack; + } + + fPosition -= header->fPrevLength; + SkASSERT(fPosition >= 0); + + fItem = reinterpret_cast<TBase*>(&(*fBlock)[fPosition + length_of<Header>::kValue]); + return true; + } + + TBase* get() const { return fItem; } + TBase* operator->() const { return this->get(); } + +private: + MemBlock* fBlock; + int fPosition; + TBase* fItem; +}; + template<typename TBase, typename TAlign> void GrTRecorder<TBase, TAlign>::reset() { Iter iter(*this); diff --git a/tests/GrTRecorderTest.cpp b/tests/GrTRecorderTest.cpp index fde70ac8e8..cef870fa90 100644 --- a/tests/GrTRecorderTest.cpp +++ b/tests/GrTRecorderTest.cpp @@ -5,14 +5,15 @@ * found in the LICENSE file. */ -#if SK_SUPPORT_GPU - -#include "GrTRecorder.h" #include "SkMatrix.h" #include "SkRandom.h" #include "SkString.h" #include "Test.h" +#if SK_SUPPORT_GPU + +#include "GrTRecorder.h" + //////////////////////////////////////////////////////////////////////////////// static int activeRecorderItems = 0; @@ -101,6 +102,15 @@ static void test_extra_data(skiatest::Reporter* reporter) { } REPORTER_ASSERT(reporter, !iter.next()); + ExtraData::Recorder::ReverseIter reverseIter(recorder); + for (int i = 99; i >= 0; --i) { + REPORTER_ASSERT(reporter, i == reverseIter->fData); + for (int j = 0; j < i; j++) { + REPORTER_ASSERT(reporter, i == reverseIter->extraData()[j]); + } + REPORTER_ASSERT(reporter, reverseIter.previous() == !!i); + } + recorder.reset(); REPORTER_ASSERT(reporter, 0 == activeRecorderItems); } @@ -197,19 +207,20 @@ public: virtual ClassType getType() { return kSubclassEmpty_ClassType; } }; +class Order { +public: + Order() { this->reset(); } + void reset() { fCurrent = 0; } + ClassType next() { + fCurrent = 1664525 * fCurrent + 1013904223; + return static_cast<ClassType>(fCurrent % kNumClassTypes); + } +private: + uint32_t fCurrent; +}; +static void test_subclasses_iters(skiatest::Reporter*, Order&, Base::Recorder::Iter&, + Base::Recorder::ReverseIter&, int = 0); static void test_subclasses(skiatest::Reporter* reporter) { - class Order { - public: - Order() { this->reset(); } - void reset() { fCurrent = 0; } - ClassType next() { - fCurrent = 1664525 * fCurrent + 1013904223; - return static_cast<ClassType>(fCurrent % kNumClassTypes); - } - private: - uint32_t fCurrent; - }; - Base::Recorder recorder(1024); Order order; @@ -244,15 +255,33 @@ static void test_subclasses(skiatest::Reporter* reporter) { order.reset(); Base::Recorder::Iter iter(recorder); - for (int i = 0; i < 1000; ++i) { - REPORTER_ASSERT(reporter, iter.next()); - REPORTER_ASSERT(reporter, order.next() == iter->getType()); - iter->validate(reporter); - } + Base::Recorder::ReverseIter reverseIter(recorder); + + test_subclasses_iters(reporter, order, iter, reverseIter); + REPORTER_ASSERT(reporter, !iter.next()); // Don't reset the recorder. It should automatically destruct all its items. } +static void test_subclasses_iters(skiatest::Reporter* reporter, Order& order, + Base::Recorder::Iter& iter, + Base::Recorder::ReverseIter& reverseIter, int i) { + if (i >= 1000) { + return; + } + + ClassType classType = order.next(); + + REPORTER_ASSERT(reporter, iter.next()); + REPORTER_ASSERT(reporter, classType == iter->getType()); + iter->validate(reporter); + + test_subclasses_iters(reporter, order, iter, reverseIter, i + 1); + + REPORTER_ASSERT(reporter, classType == reverseIter->getType()); + reverseIter->validate(reporter); + REPORTER_ASSERT(reporter, reverseIter.previous() == !!i); +} DEF_GPUTEST(GrTRecorder, reporter, factory) { test_empty_back_and_pop(reporter); |