Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Unified Diff: src/gpu/GrCmdBuffer.h

Issue 628453002: Create a single command buffer for GrInOrderDrawBuffer (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gyp/gpu.gypi ('k') | src/gpu/GrInOrderDrawBuffer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrCmdBuffer.h
diff --git a/src/gpu/GrCmdBuffer.h b/src/gpu/GrCmdBuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..e4bc3dabd4be7dbea427eb420982cdeeb0db604c
--- /dev/null
+++ b/src/gpu/GrCmdBuffer.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrCmdBuffer_DEFINED
+#define GrCmdBuffer_DEFINED
+
+#include "SkTemplates.h"
+#include "SkTypes.h"
+
+class GrDrawTarget;
+
+/**
+ * Ordered list of commands for a GrDrawTarget.
+ *
+ * The commands are stored contiguously within large blocks of memory, in order avoid
+ * excessive calls to malloc().
+ *
+ * @param TAlign A type whose size is the desired alignment for command allocations.
+ * Using long double will always meet alignment requirements, but this may
+ * be smaller if the largest alignment requirement is know ahead of time.
+ */
+template<typename TAlign = long double> class GrCmdBuffer : SkNoncopyable {
bsalomon 2014/10/03 15:04:45 Do long doubles require alignment? Wondering if vo
Chris Dalton 2014/10/03 16:16:24 According to this, long double gets aligned at 16
bsalomon 2014/10/03 18:43:03 Interesting. Maybe just have no default?
Chris Dalton 2014/10/03 19:38:40 Sure
Chris Dalton 2014/10/08 19:29:02 Done.
+public:
+ class Cmd;
+ class Iter;
+
+ /**
+ * Create a command buffer
+ *
+ * @param initialSizeInBytes The amount of memory reserved by the command buffer
+ * initially, and after calls to reset().
+ */
+ GrCmdBuffer(int initialSizeInBytes)
+ : fHeadBlock(bytes_to_length(initialSizeInBytes)),
+ fTailBlock(&fHeadBlock),
+ fBack(0),
+ fFirstCmd(NULL),
+ fLastCmd(NULL) {}
+
+ ~GrCmdBuffer() { this->reset(); }
+
+ bool empty() {
+ SkASSERT((NULL == fFirstCmd) == (NULL == fLastCmd));
+ return NULL == fFirstCmd;
+ }
+
+ Cmd& front() {
+ SkASSERT(!this->empty());
+ return *fFirstCmd;
+ }
+
+ Cmd& back() {
+ SkASSERT(!this->empty());
+ return *fLastCmd;
+ }
+
+ /**
+ * Destruct all commands in the command buffer and reset to empty.
+ */
+ void reset();
+
+ /**
+ * Push a command to the back of the buffer, with optional arguments to for its
+ * constructor. TCmd must be a subclass of GrCmdBuffer::Cmd.
+ */
+ template<typename TCmd>
+ TCmd& push_back() { return this->push_back_size<TCmd>(sizeof(TCmd)); }
bsalomon 2014/10/03 15:04:45 Instead of all these could we use something like a
Chris Dalton 2014/10/03 16:16:24 I did consider that approach. The only problem is
bsalomon 2014/10/03 18:43:03 In the other instances where we've done this we ju
Chris Dalton 2014/10/03 19:38:40 Ok, this will work now. (The issue used to be that
Chris Dalton 2014/10/08 19:29:02 Done.
+ template<typename TCmd, typename TArg1>
+ TCmd& push_back(const TArg1& a) { return this->push_back_size<TCmd>(sizeof(TCmd), a); }
+ template<typename TCmd, typename TArg1, typename TArg2>
+ TCmd& push_back(const TArg1& a, const TArg2& b) { return this->push_back_size<TCmd>(sizeof(TCmd), a, b); }
+ template<typename TCmd, typename TArg1, typename TArg2, typename TArg3>
+ TCmd& push_back(const TArg1& a, const TArg2& b, const TArg3& c) { return this->push_back_size<TCmd>(sizeof(TCmd), a, b, c); }
+
+ /**
+ * Push a variable-size command to the back of the buffer, with optional arguments for
+ * its constructor. TCmd must be a subclass of GrCmdBuffer::Cmd.
+ *
+ * @param sizeInBytes The amount of memory to allocate for the command. This may be
bsalomon 2014/10/03 15:04:45 Wonder whether we should only take the extra paylo
Chris Dalton 2014/10/03 16:16:24 The Cmd base class could also maybe know where to
bsalomon 2014/10/03 18:43:03 Sure but then we need to store ptr. If it's a para
Chris Dalton 2014/10/03 19:38:40 So at execute time, the client code doesn't know w
Chris Dalton 2014/10/08 19:29:02 Left as-is for now, to resemble the way this would
+ * larger than sizeof(TCmd) to accomodate variable-length arrays.
+ */
+ template<typename TCmd>
+ TCmd& push_back_size(int sizeInBytes);
+ template<typename TCmd, typename TArg1>
+ TCmd& push_back_size(int sizeInBytes, const TArg1&);
+ template<typename TCmd, typename TArg1, typename TArg2>
+ TCmd& push_back_size(int sizeInBytes, const TArg1&, const TArg2&);
+ template<typename TCmd, typename TArg1, typename TArg2, typename TArg3>
+ TCmd& push_back_size(int sizeInBytes, const TArg1&, const TArg2&, const TArg3&);
+
+private:
+ static int bytes_to_length(int bytes) { return (bytes + sizeof(TAlign) - 1) / sizeof(TAlign); }
+
+ void* push_back_raw(int sizeInBytes);
+ template<typename T> T& init_back(T* cmd);
+
+ struct Block {
+ Block(int length) : fLength(length), fBuffer(fLength) {}
+ const int fLength;
+ SkAutoTMalloc<TAlign> fBuffer;
+ SkAutoTDelete<Block> fNext;
+ };
+ Block fHeadBlock;
+ Block* fTailBlock;
+ int fBack;
+
+ Cmd* fFirstCmd;
+ Cmd* fLastCmd;
+
+ friend class Iter;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template<typename TAlign>
+class GrCmdBuffer<TAlign>::Cmd : SkNoncopyable {
+public:
+ Cmd() : fNext(NULL) {}
+ virtual ~Cmd() {}
+ virtual void execute(GrDrawTarget*) = 0;
+
+ uint8_t type() const { return fType; }
+ void resetType(uint8_t type) { fType = type; }
+
+private:
+ Cmd* fNext;
+ uint8_t fType;
bsalomon 2014/10/03 15:04:45 Is the type really just just used to hang the debu
Chris Dalton 2014/10/03 16:16:24 At least for now, concatInstancedDraw() also check
bsalomon 2014/10/03 18:43:03 The GrIODB could just have a bool, fLastCmdWasDraw
Chris Dalton 2014/10/03 19:38:40 Oh, fLastCmdWasDraw, I like that
Chris Dalton 2014/10/08 19:29:02 I ended up leaving fType in the base Cmd class. It
+
+ friend class GrCmdBuffer;
+};
+
+template<typename TAlign>
+class GrCmdBuffer<TAlign>::Iter {
+public:
+ Iter(GrCmdBuffer& cmdBuffer) : fCmd(NULL), fNext(cmdBuffer.fFirstCmd) {}
+
+ bool next() {
+ if (NULL == fNext) {
+ return false;
+ }
+ fCmd = fNext;
+ fNext = fCmd->fNext;
+ return true;
+ }
+
+ Cmd* operator->() {
+ SkASSERT(fCmd);
+ return fCmd;
+ }
+
+private:
+ Cmd* fCmd;
+ Cmd* fNext;
+};
+
+template<typename TAlign>
+void GrCmdBuffer<TAlign>::reset() {
+ Iter iter(*this);
+ while (iter.next()) {
+ iter->~Cmd();
+ }
+ fHeadBlock.fNext.free();
+ fTailBlock = &fHeadBlock;
+ fBack = 0;
+ fFirstCmd = fLastCmd = NULL;
+}
+
+template<typename TAlign>
+void* GrCmdBuffer<TAlign>::push_back_raw(int sizeInBytes) {
+ const int cmdLength = bytes_to_length(sizeInBytes);
+
+ if (fBack + cmdLength > fTailBlock->fLength) {
+ SkASSERT(NULL == fTailBlock->fNext.get());
+ Block* next = SkNEW_ARGS(Block, (SkTMax(2 * fTailBlock->fLength, cmdLength)));
+ fTailBlock->fNext.reset(next);
+ fTailBlock = next;
+ fBack = 0;
+ }
+
+ void* data = &fTailBlock->fBuffer[fBack];
+ fBack += cmdLength;
+ return data;
+}
+
+template<typename TAlign>
+template<typename T>
+T& GrCmdBuffer<TAlign>::init_back(T* cmd) {
+ cmd->fType = T::kCmdType;
+ if (NULL == fFirstCmd) {
+ SkASSERT(NULL == fLastCmd);
+ fFirstCmd = fLastCmd = cmd;
+ } else {
+ SkASSERT(NULL != fLastCmd);
+ fLastCmd->fNext = cmd;
+ fLastCmd = cmd;
+ }
+ return *cmd;
+}
+
+template<typename TAlign>
+template<typename TCmd>
+TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes) {
+ SkASSERT(sizeInBytes >= (int)sizeof(TCmd));
+ TCmd* cmd = SkNEW_PLACEMENT(this->push_back_raw(sizeInBytes), TCmd);
+ return this->init_back(cmd);
+}
+
+template<typename TAlign>
+template<typename TCmd, typename TArg1>
+TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a) {
+ SkASSERT(sizeInBytes >= (int)sizeof(TCmd));
+ TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a));
+ return this->init_back(cmd);
+}
+
+template<typename TAlign>
+template<typename TCmd, typename TArg1, typename TArg2>
+TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a, const TArg2& b) {
+ SkASSERT(sizeInBytes >= (int)sizeof(TCmd));
+ TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a, b));
+ return this->init_back(cmd);
+}
+
+template<typename TAlign>
+template<typename TCmd, typename TArg1, typename TArg2, typename TArg3>
+TCmd& GrCmdBuffer<TAlign>::push_back_size(int sizeInBytes, const TArg1& a, const TArg2& b, const TArg3& c) {
+ SkASSERT(sizeInBytes >= (int)sizeof(TCmd));
+ TCmd* cmd = SkNEW_PLACEMENT_ARGS(this->push_back_raw(sizeInBytes), TCmd, (a, b, c));
+ return this->init_back(cmd);
+}
+
+#endif
« no previous file with comments | « gyp/gpu.gypi ('k') | src/gpu/GrInOrderDrawBuffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698