Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2022-08-20 22:58:08 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-08-20 23:22:57 +0300
commitdec817524fd5964cc5a92b38ef19b78d86833963 (patch)
treec9cccbe8e1952c95481b0fbae94fc40f549789ab
parentdcc42042077c65663aa398a25dd800243dff2e27 (diff)
Refactor Pass class
Now there is a still a base class but no virtual functions. The different implementation of draw are declared as method shadowing the base class method. Sub pass is limited to 1 depth. Cannot have nested subpass. Test is now passing
-rw-r--r--source/blender/draw/intern/draw_command.cc18
-rw-r--r--source/blender/draw/intern/draw_command.hh114
-rw-r--r--source/blender/draw/intern/draw_manager.cc7
-rw-r--r--source/blender/draw/intern/draw_manager.hh12
-rw-r--r--source/blender/draw/intern/draw_pass.cc120
-rw-r--r--source/blender/draw/intern/draw_pass.hh491
-rw-r--r--source/blender/draw/tests/draw_pass_test.cc33
7 files changed, 493 insertions, 302 deletions
diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc
index ef47479875a..72f3911fda5 100644
--- a/source/blender/draw/intern/draw_command.cc
+++ b/source/blender/draw/intern/draw_command.cc
@@ -326,10 +326,13 @@ std::string PushConstant::serialize() const
std::string Draw::serialize() const
{
- return std::string(".draw(inst_len=") + std::to_string(instance_len) +
- ", vert_len=" + std::to_string(vertex_len) +
- ", vert_first=" + std::to_string(vertex_first) +
- ", res_id=" + std::to_string(handle.resource_index()) + ")";
+ std::string inst_len = (instance_len == (uint)-1) ? "from_batch" : std::to_string(instance_len);
+ std::string vert_len = (vertex_len == (uint)-1) ? "from_batch" : std::to_string(vertex_len);
+ std::string vert_first = (vertex_first == (uint)-1) ? "from_batch" :
+ std::to_string(vertex_first);
+ return std::string(".draw(inst_len=") + inst_len + ", vert_len=" + vert_len +
+ ", vert_first=" + vert_first + ", res_id=" + std::to_string(handle.resource_index()) +
+ ")";
}
std::string DrawIndirect::serialize() const
@@ -371,7 +374,7 @@ std::string Clear::serialize() const
}
}
if (eGPUFrameBufferBits(clear_channels) & GPU_STENCIL_BIT) {
- ss << "stencil=" << std::bitset<8>(stencil) << ")";
+ ss << "stencil=0b" << std::bitset<8>(stencil) << ")";
}
return std::string(".clear(") + ss.str() + ")";
}
@@ -385,9 +388,8 @@ std::string StateSet::serialize() const
std::string StencilSet::serialize() const
{
std::stringstream ss;
- ss << ".stencil_set(write_mask=" << std::bitset<8>(write_mask)
- << ", compare_mask=" << std::bitset<8>(compare_mask)
- << ", reference=" << std::bitset<8>(reference);
+ ss << ".stencil_set(write_mask=0b" << std::bitset<8>(write_mask) << ", compare_mask=0b"
+ << std::bitset<8>(compare_mask) << ", reference=0b" << std::bitset<8>(reference);
return ss.str();
}
diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh
index f977d271cc2..a2168201360 100644
--- a/source/blender/draw/intern/draw_command.hh
+++ b/source/blender/draw/intern/draw_command.hh
@@ -56,6 +56,7 @@ enum class Type : uint8_t {
*/
None = 0,
+ /** Commands stored as Undetermined in regular command buffer. */
Barrier,
Clear,
Dispatch,
@@ -67,6 +68,10 @@ enum class Type : uint8_t {
ShaderBind,
StateSet,
StencilSet,
+
+ /** Special commands stored in separate buffers. */
+ SubPass,
+ MultiDraw,
};
/**
@@ -75,12 +80,10 @@ enum class Type : uint8_t {
* stream.
*/
struct Header {
- /** Command index in command heap of this type. */
- uint command_index;
/** Command type. */
Type type;
- /** Special hack as we store a SubPass as 2 commands. */
- bool is_subpass;
+ /** Command index in command heap of this type. */
+ uint command_index;
};
struct ShaderBind {
@@ -103,6 +106,8 @@ struct ResourceBind {
} type;
union {
+ /** TODO: Use draw::Texture|StorageBuffer|UniformBuffer as resources as they will give more
+ * debug info. */
GPUUniformBuf *uniform_buf;
GPUUniformBuf **uniform_buf_ref;
GPUStorageBuf *storage_buf;
@@ -218,8 +223,8 @@ struct PushConstant {
struct Draw {
GPUBatch *batch;
uint instance_len;
- uint vertex_first;
uint vertex_len;
+ uint vertex_first;
ResourceHandle handle;
void execute(RecordingState &state) const;
@@ -291,18 +296,93 @@ struct StencilSet {
std::string serialize() const;
};
-union Undetermined {
- ShaderBind shader_bind;
- ResourceBind resource_bind;
- PushConstant push_constant;
- Draw draw;
- DrawIndirect draw_indirect;
- Dispatch dispatch;
- DispatchIndirect dispatch_indirect;
- Barrier barrier;
- Clear clear;
- StateSet state_set;
- StencilSet stencil_set;
+struct Undetermined {
+ union {
+ ShaderBind shader_bind;
+ ResourceBind resource_bind;
+ PushConstant push_constant;
+ Draw draw;
+ DrawIndirect draw_indirect;
+ Dispatch dispatch;
+ DispatchIndirect dispatch_indirect;
+ Barrier barrier;
+ Clear clear;
+ StateSet state_set;
+ StencilSet stencil_set;
+ };
+
+ void execute(const command::Type &type, command::RecordingState &state) const
+ {
+ switch (type) {
+ case command::Type::ShaderBind:
+ shader_bind.execute(state);
+ break;
+ case command::Type::ResourceBind:
+ resource_bind.execute();
+ break;
+ case command::Type::PushConstant:
+ push_constant.execute(state);
+ break;
+ case command::Type::Draw:
+ draw.execute(state);
+ break;
+ case command::Type::DrawIndirect:
+ draw_indirect.execute(state);
+ break;
+ case command::Type::Dispatch:
+ dispatch.execute(state);
+ break;
+ case command::Type::DispatchIndirect:
+ dispatch_indirect.execute(state);
+ break;
+ case command::Type::Barrier:
+ barrier.execute();
+ break;
+ case command::Type::Clear:
+ clear.execute();
+ break;
+ case command::Type::StateSet:
+ state_set.execute(state);
+ break;
+ case command::Type::StencilSet:
+ stencil_set.execute();
+ break;
+ default:
+ /* Skip Type::None. */
+ break;
+ }
+ }
+
+ std::string serialize(const command::Type &type) const
+ {
+ switch (type) {
+ case command::Type::ShaderBind:
+ return shader_bind.serialize();
+ case command::Type::ResourceBind:
+ return resource_bind.serialize();
+ case command::Type::PushConstant:
+ return push_constant.serialize();
+ case command::Type::Draw:
+ return draw.serialize();
+ case command::Type::DrawIndirect:
+ return draw_indirect.serialize();
+ case command::Type::Dispatch:
+ return dispatch.serialize();
+ case command::Type::DispatchIndirect:
+ return dispatch_indirect.serialize();
+ case command::Type::Barrier:
+ return barrier.serialize();
+ case command::Type::Clear:
+ return clear.serialize();
+ case command::Type::StateSet:
+ return state_set.serialize();
+ case command::Type::StencilSet:
+ return stencil_set.serialize();
+ default:
+ /* Skip Type::None. */
+ return "";
+ }
+ }
};
/** Try to keep the command size as low as possible for performance. */
diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc
index 8fee875b8cf..5995c548228 100644
--- a/source/blender/draw/intern/draw_manager.cc
+++ b/source/blender/draw/intern/draw_manager.cc
@@ -9,15 +9,16 @@
namespace blender::draw {
-void Manager::submit(const Pass &pass)
+void Manager::submit(const PassSimple &pass)
{
command::RecordingState state;
pass.submit(state);
}
-std::string Manager::serialize(const Pass &pass)
+void Manager::submit(const PassMain &pass)
{
- return pass.serialize();
+ command::RecordingState state;
+ pass.submit(state);
}
} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh
index f559e810645..f2db36d522e 100644
--- a/source/blender/draw/intern/draw_manager.hh
+++ b/source/blender/draw/intern/draw_manager.hh
@@ -23,16 +23,8 @@ class Manager {
* Submit a pass for drawing. All resource reference will be dereferenced and commands will be
* sent to GPU.
*/
- /* TODO(fclem): Why doesn't this work? */
- // void submit(const PassCommon &pass);
- void submit(const Pass &pass);
-
- /**
- * Will turn the command stream into a debug string.
- */
- /* TODO(fclem): Why doesn't this work? */
- // std::string serialize(const PassCommon &pass);
- std::string serialize(const Pass &pass);
+ void submit(const PassSimple &pass);
+ void submit(const PassMain &pass);
};
} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_pass.cc b/source/blender/draw/intern/draw_pass.cc
index f767613c3f2..d0d397c8295 100644
--- a/source/blender/draw/intern/draw_pass.cc
+++ b/source/blender/draw/intern/draw_pass.cc
@@ -10,15 +10,131 @@
namespace blender::draw {
/* -------------------------------------------------------------------- */
-/** \name Pass
+/** \name Pass Submission
* \{ */
+void PassSimple::submit(command::RecordingState &state) const
+{
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::SubPass:
+ sub_passes_[header.command_index].submit(state);
+ break;
+ default:
+ commands_[header.command_index].execute(header.type, state);
+ break;
+ }
+ }
+}
+
+void PassSimple::Sub::submit(command::RecordingState &state) const
+{
+ for (const command::Header &header : headers_) {
+ commands_[header.command_index].execute(header.type, state);
+ }
+}
+
+void PassMain::submit(command::RecordingState &state) const
+{
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::SubPass:
+ sub_passes_[header.command_index].submit(state);
+ break;
+ case Type::MultiDraw:
+ /* TODO */
+ break;
+ default:
+ commands_[header.command_index].execute(header.type, state);
+ break;
+ }
+ }
+}
+
+void PassMain::Sub::submit(command::RecordingState &state) const
+{
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::MultiDraw:
+ /* TODO */
+ break;
+ default:
+ commands_[header.command_index].execute(header.type, state);
+ break;
+ }
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Sub Pass
+/** \name Pass Serialization
* \{ */
+std::string PassSimple::serialize() const
+{
+ std::stringstream ss;
+ ss << "PassSimple(" << debug_name << ")" << std::endl;
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::SubPass:
+ ss << sub_passes_[header.command_index].serialize() << std::endl;
+ break;
+ default:
+ ss << commands_[header.command_index].serialize(header.type) << std::endl;
+ break;
+ }
+ }
+ return ss.str();
+}
+
+std::string PassSimple::Sub::serialize() const
+{
+ std::stringstream ss;
+ ss << ".sub(" << debug_name << ")" << std::endl;
+ for (const command::Header &header : headers_) {
+ ss << " " << commands_[header.command_index].serialize(header.type) << std::endl;
+ }
+ return ss.str();
+}
+
+std::string PassMain::serialize() const
+{
+ std::stringstream ss;
+ ss << "PassMain(" << debug_name << ")" << std::endl;
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::SubPass:
+ ss << sub_passes_[header.command_index].serialize() << std::endl;
+ break;
+ case Type::MultiDraw:
+ /* TODO */
+ break;
+ default:
+ ss << commands_[header.command_index].serialize(header.type) << std::endl;
+ break;
+ }
+ }
+ return ss.str();
+}
+
+std::string PassMain::Sub::serialize() const
+{
+ std::stringstream ss;
+ ss << ".sub(" << debug_name << ")" << std::endl;
+ for (const command::Header &header : headers_) {
+ switch (header.type) {
+ case Type::MultiDraw:
+ /* TODO */
+ break;
+ default:
+ ss << " " << commands_[header.command_index].serialize(header.type) << std::endl;
+ break;
+ }
+ }
+ return ss.str();
+}
+
/** \} */
} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh
index f4721ba07f8..4d4f74e1425 100644
--- a/source/blender/draw/intern/draw_pass.hh
+++ b/source/blender/draw/intern/draw_pass.hh
@@ -10,18 +10,20 @@
* only change in resource load (memory & CPU usage). They can be swapped without any functional
* change.
*
- * `Pass`:
+ * `PassMain`:
* Should be used on heavy load passes such as ones that may contain scene objects. Draw call
* submission is optimized for large number of draw calls. But has a significant overhead per
* #Pass. Use many #PassSub along with a main #Pass to reduce the overhead and allow groupings of
* commands.
*
- * `PassSub`:
+ * `Pass(Main|Simple)::Sub`:
* A lightweight #Pass that lives inside a main #Pass. It can only be created from #Pass.sub()
* and is auto managed. This mean it can be created, filled and thrown away. A #PassSub reference
* is valid until the next #Pass.init() of the parent pass. Commands recorded inside a #PassSub are
* inserted inside the parent #Pass where the sub have been created durring submission.
*
+ * `PassSimple`:
+ * Does not have the overhead of #PassMain but does not have the culling and batching optimization.
*
* NOTE: A pass can be recorded once and resubmitted any number of time. This can be a good
* optimization for passes that are always the same for each frame. The only thing to be aware of
@@ -49,27 +51,27 @@ class Manager;
/** \name Pass API
* \{ */
+namespace detail {
+
/**
* Public API of a draw pass.
*/
-class Pass {
+class PassBase {
friend Manager;
- private:
+ protected:
/** Highest level of the command stream. Split command stream in different command types. */
Vector<command::Header> headers_;
/** Commands referenced by headers (which contains their types). */
Vector<command::Undetermined> commands_;
- /** Sub-passes referenced by headers. */
- // Vector<Pass> sub_passes_;
/** Currently bound shader. Used for interface queries. */
GPUShader *shader_;
public:
const char *debug_name;
- Pass() = delete;
- Pass(const char *name = "Unamed") : debug_name(name){};
+ PassBase() = delete;
+ PassBase(const char *name = "Unamed") : debug_name(name){};
/**
* Reset the pass command pool.
@@ -77,11 +79,6 @@ class Pass {
void init();
/**
- * Create a sub-pass inside this pass. The sub-pass memory is auto managed.
- */
- // Sub &sub();
-
- /**
* Changes the fixed function pipeline state.
* Starts as DRW_STATE_NO_DRAW at the start of a Pass submission.
* SubPass inherit previous pass state.
@@ -123,25 +120,28 @@ class Pass {
uint vertex_len = -1,
uint vertex_first = -1,
ResourceHandle handle = {0});
- void draw(GPUBatch *batch,
- StorageBuffer<DrawCommand> &indirect_buffer,
- ResourceHandle handle = {0});
+ void draw_indirect(GPUBatch *batch,
+ StorageBuffer<DrawCommand> &indirect_buffer,
+ ResourceHandle handle = {0});
/** Shorter version for the common case. */
- void draw(GPUBatch *batch, ResourceHandle handle);
+ void draw(GPUBatch *batch, ResourceHandle handle)
+ {
+ draw(batch, -1, -1, -1, handle);
+ }
/**
* Record a procedural draw call. Geometry is **NOT** source from a GPUBatch.
* NOTE: An instance or vertex count of 0 will discard the draw call. It will not be recorded.
*/
- void draw(GPUPrimType primitive,
- uint instance_len,
- uint vertex_len,
- uint vertex_first = -1,
- ResourceHandle handle = {0});
- void draw(GPUPrimType primitive,
- StorageBuffer<DrawCommand> &indirect_buffer,
- ResourceHandle handle = {0});
+ void draw_procedural(GPUPrimType primitive,
+ uint instance_len,
+ uint vertex_len,
+ uint vertex_first = -1,
+ ResourceHandle handle = {0});
+ void draw_procedural_indirect(GPUPrimType primitive,
+ StorageBuffer<DrawCommand> &indirect_buffer,
+ ResourceHandle handle = {0});
/**
* Record a compute dispatch call.
@@ -215,14 +215,14 @@ class Pass {
/**
* Turn the pass into a string for inspection.
*/
- std::string serialize() const;
+ virtual std::string serialize() const = 0;
- friend std::ostream &operator<<(std::ostream &stream, const Pass &pass)
+ friend std::ostream &operator<<(std::ostream &stream, const PassBase &pass)
{
return stream << pass.serialize();
}
- private:
+ protected:
/**
* Internal Helpers
*/
@@ -233,21 +233,67 @@ class Pass {
GPUBatch *procedural_batch_get(GPUPrimType primitive);
- static void submit_command(command::RecordingState &state,
- const command::Type &type,
- const command::Undetermined &command);
-
- static std::string serialize_command(const command::Type &type,
- const command::Undetermined &command);
-
/**
* Return a new command recorded with the given type.
*/
command::Undetermined &create_command(command::Type type);
+};
+
+} // namespace detail
+
+/**
+ * Normal pass type. No visibility or draw-call optimisation.
+ */
+class PassSimple : public detail::PassBase {
+ friend Manager;
+
+ public:
+ class Sub : public detail::PassBase {
+ friend PassSimple;
+
+ public:
+ /**
+ * Turn the pass into a string for inspection.
+ */
+ std::string serialize() const;
+
+ private:
+ Sub(const char *name) : PassBase(name){};
+
+ void submit(command::RecordingState &state) const;
+ };
+
+ private:
+ /** Sub-passes referenced by headers. */
+ Vector<PassSimple::Sub> sub_passes_;
+
+ public:
+ PassSimple() = delete;
+ PassSimple(const char *name) : PassBase(name){};
+
+ /**
+ * Create a sub-pass inside this pass. The sub-pass memory is auto managed.
+ */
+ PassSimple::Sub &sub(const char *name);
+
+ void draw(GPUBatch *batch,
+ uint instance_len = -1,
+ uint vertex_len = -1,
+ uint vertex_first = -1,
+ ResourceHandle handle = {0});
+
+ /** Shorter version for the common case. */
+ void draw(GPUBatch *batch, ResourceHandle handle)
+ {
+ draw(batch, -1, -1, -1, handle);
+ }
/**
- * Submit a Pass as GPU commands. Should only be called by draw::Manager.
+ * Turn the pass into a string for inspection.
*/
+ std::string serialize() const;
+
+ private:
void submit(command::RecordingState &state) const;
};
@@ -258,115 +304,129 @@ class Pass {
* IMPORTANT: To be used only for passes containing lots of draw calls since it has a potentially
* high overhead due to batching and culling optimizations.
*/
-class PassMain : public Pass {
+class PassMain : public detail::PassBase {
+ friend Manager;
+
+ public:
+ class Sub : public detail::PassBase {
+ friend PassMain;
+
+ public:
+ /**
+ * Turn the pass into a string for inspection.
+ */
+ std::string serialize() const;
+
+ private:
+ command::MultiDrawBuffer &multi_draws_;
+
+ Sub(const char *name, command::MultiDrawBuffer &multi_draws)
+ : PassBase(name), multi_draws_(multi_draws){};
+
+ void draw(GPUBatch *batch,
+ uint instance_len = -1,
+ uint vertex_len = -1,
+ uint vertex_first = -1,
+ ResourceHandle handle = {0});
+
+ void submit(command::RecordingState &state) const;
+ };
+
private:
+ /** Sub-passes referenced by headers. */
+ Vector<PassMain::Sub> sub_passes_;
/** Multi draw indirect rendering for many draw calls efficient rendering. */
command::MultiDrawBuffer multi_draws_;
public:
PassMain() = delete;
- PassMain(const char *name) : Pass(name){};
+ PassMain(const char *name) : PassBase(name){};
+
+ /**
+ * Create a sub-pass inside this pass. The sub-pass memory is auto managed.
+ */
+ PassMain::Sub &sub(const char *name);
-#if 0
void draw(GPUBatch *batch,
uint instance_len = -1,
uint vertex_len = -1,
uint vertex_first = -1,
ResourceHandle handle = {0});
- void draw(GPUBatch *batch,
- StorageBuffer<DrawCommand> &indirect_buffer,
- ResourceHandle handle = {0});
-#endif
+
+ /** Shorter version for the common case. */
+ void draw(GPUBatch *batch, ResourceHandle handle)
+ {
+ draw(batch, -1, -1, -1, handle);
+ }
+
+ /**
+ * Turn the pass into a string for inspection.
+ */
+ std::string serialize() const;
+
+ private:
+ void submit(command::RecordingState &state) const;
};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Pass
+/** \name PassSimple Implementation
* \{ */
-/**
- * Reset the pass command pool.
- */
-inline void Pass::init()
+inline PassSimple::Sub &PassSimple::sub(const char *name)
+{
+ int64_t index = sub_passes_.append_and_get_index(PassSimple::Sub(name));
+ headers_.append({command::Type::SubPass, static_cast<uint>(index)});
+ return sub_passes_[index];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name PassMain Implementation
+ * \{ */
+
+inline PassMain::Sub &PassMain::sub(const char *name)
+{
+ int64_t index = sub_passes_.append_and_get_index(PassMain::Sub(name, multi_draws_));
+ headers_.append({command::Type::SubPass, static_cast<uint>(index)});
+ return sub_passes_[index];
+}
+
+/** \} */
+
+namespace detail {
+
+/* -------------------------------------------------------------------- */
+/** \name PassBase Implementation
+ * \{ */
+
+inline void PassBase::init()
{
headers_.clear();
commands_.clear();
}
-inline command::Undetermined &Pass::create_command(command::Type type)
+inline command::Undetermined &PassBase::create_command(command::Type type)
{
int64_t index = commands_.append_and_get_index({});
- headers_.append({static_cast<uint>(index), type, false});
+ headers_.append({type, static_cast<uint>(index)});
return commands_[index];
}
-inline void Pass::submit(command::RecordingState &state) const
-{
-#if 0
- if (command_last_ != -1) {
- uint cmd_index = 0;
- while (cmd_index != -1) {
- command::Header &header = headers_[cmd_index];
- cmd_index = header.next;
-
- if (header.is_subpass) {
- /** WARNING: Recursive. */
- PassSub &sub = *reinterpret_cast<PassSub *>(&commands_[header.command_index]);
- ss << submit();
- }
- else if (false) {
- /** TODO(fclem): MultiDraw */
- }
- else {
- ss << detail::PassCommon::submit_command(
- state, header.type, commands_[header.command_index])
- << std::endl;
- }
- }
- }
-#endif
-}
-
-inline std::string Pass::serialize() const
-{
-#if 0
- if (command_last_ != -1) {
- uint cmd_index = 0;
- while (cmd_index != -1) {
- command::Header &header = headers_[cmd_index];
- cmd_index = header.next;
-
- if (header.is_subpass) {
- /** WARNING: Recursive. */
- PassSub &sub = *reinterpret_cast<PassSub *>(&commands_[header.command_index]);
- ss << sub.serialize();
- }
- else if (false) {
- /** TODO(fclem): MultiDraw */
- }
- else {
- ss << detail::PassCommon::serialize_command(header.type, commands_[header.command_index])
- << std::endl;
- }
- }
- }
-#endif
- return "";
-}
-
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Draw Calls
+/** \name Draw Calls Implementation
* \{ */
-inline void Pass::clear(eGPUFrameBufferBits planes, float4 color, float depth, uint8_t stencil)
+inline void PassBase::clear(eGPUFrameBufferBits planes, float4 color, float depth, uint8_t stencil)
{
create_command(command::Type::Clear).clear = {(uint8_t)planes, stencil, depth, color};
}
-inline GPUBatch *Pass::procedural_batch_get(GPUPrimType primitive)
+inline GPUBatch *PassBase::procedural_batch_get(GPUPrimType primitive)
{
switch (primitive) {
case GPU_PRIM_POINTS:
@@ -384,7 +444,7 @@ inline GPUBatch *Pass::procedural_batch_get(GPUPrimType primitive)
}
}
-inline void Pass::draw(
+inline void PassBase::draw(
GPUBatch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceHandle handle)
{
if (instance_len == 0 || vertex_len == 0) {
@@ -394,54 +454,49 @@ inline void Pass::draw(
create_command(Type::Draw).draw = {batch, instance_len, vertex_len, vertex_first, handle};
}
-inline void Pass::draw(GPUBatch *batch,
- StorageBuffer<DrawCommand> &indirect_buffer,
- ResourceHandle handle)
+inline void PassBase::draw_indirect(GPUBatch *batch,
+ StorageBuffer<DrawCommand> &indirect_buffer,
+ ResourceHandle handle)
{
BLI_assert(shader_);
create_command(Type::DrawIndirect).draw_indirect = {batch, &indirect_buffer, handle};
}
-inline void Pass::draw(GPUPrimType primitive,
- uint instance_len,
- uint vertex_len,
- uint vertex_first,
- ResourceHandle handle)
+inline void PassBase::draw_procedural(GPUPrimType primitive,
+ uint instance_len,
+ uint vertex_len,
+ uint vertex_first,
+ ResourceHandle handle)
{
draw(procedural_batch_get(primitive), instance_len, vertex_len, vertex_first, handle);
}
-inline void Pass::draw(GPUPrimType primitive,
- StorageBuffer<DrawCommand> &indirect_buffer,
- ResourceHandle handle)
+inline void PassBase::draw_procedural_indirect(GPUPrimType primitive,
+ StorageBuffer<DrawCommand> &indirect_buffer,
+ ResourceHandle handle)
{
- draw(procedural_batch_get(primitive), indirect_buffer, handle);
-}
-
-inline void Pass::draw(GPUBatch *batch, ResourceHandle handle)
-{
- draw(batch, -1, -1, -1, handle);
+ draw_indirect(procedural_batch_get(primitive), indirect_buffer, handle);
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Compute Dispatch
+/** \name Compute Dispatch Implementation
* \{ */
-inline void Pass::dispatch(int3 group_len)
+inline void PassBase::dispatch(int3 group_len)
{
BLI_assert(shader_);
create_command(Type::Dispatch).dispatch = {group_len};
}
-inline void Pass::dispatch(int3 *group_len)
+inline void PassBase::dispatch(int3 *group_len)
{
BLI_assert(shader_);
create_command(Type::Dispatch).dispatch = {group_len};
}
-inline void Pass::dispatch(StorageBuffer<DispatchCommand> &indirect_buffer)
+inline void PassBase::dispatch(StorageBuffer<DispatchCommand> &indirect_buffer)
{
BLI_assert(shader_);
create_command(Type::DispatchIndirect).dispatch_indirect = {&indirect_buffer};
@@ -450,30 +505,30 @@ inline void Pass::dispatch(StorageBuffer<DispatchCommand> &indirect_buffer)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Clear
+/** \name Clear Implementation
* \{ */
-inline void Pass::clear_color(float4 color)
+inline void PassBase::clear_color(float4 color)
{
clear(GPU_COLOR_BIT, color, 0.0f, 0);
}
-inline void Pass::clear_depth(float depth)
+inline void PassBase::clear_depth(float depth)
{
clear(GPU_DEPTH_BIT, float4(0.0f), depth, 0);
}
-inline void Pass::clear_stencil(uint8_t stencil)
+inline void PassBase::clear_stencil(uint8_t stencil)
{
clear(GPU_STENCIL_BIT, float4(0.0f), 0.0f, stencil);
}
-inline void Pass::clear_depth_stencil(float depth, uint8_t stencil)
+inline void PassBase::clear_depth_stencil(float depth, uint8_t stencil)
{
clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT, float4(0.0f), depth, stencil);
}
-inline void Pass::clear_color_depth_stencil(float4 color, float depth, uint8_t stencil)
+inline void PassBase::clear_color_depth_stencil(float4 color, float depth, uint8_t stencil)
{
clear(GPU_DEPTH_BIT | GPU_STENCIL_BIT | GPU_COLOR_BIT, color, depth, stencil);
}
@@ -481,10 +536,10 @@ inline void Pass::clear_color_depth_stencil(float4 color, float depth, uint8_t s
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Barrier
+/** \name Barrier Implementation
* \{ */
-inline void Pass::barrier(eGPUBarrier type)
+inline void PassBase::barrier(eGPUBarrier type)
{
create_command(Type::Barrier).barrier = {type};
}
@@ -492,20 +547,20 @@ inline void Pass::barrier(eGPUBarrier type)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name State
+/** \name State Implementation
* \{ */
-inline void Pass::state_set(DRWState state)
+inline void PassBase::state_set(DRWState state)
{
create_command(Type::StateSet).state_set = {state};
}
-inline void Pass::state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
+inline void PassBase::state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
{
create_command(Type::StencilSet).stencil_set = {write_mask, reference, compare_mask};
}
-inline void Pass::shader_set(GPUShader *shader)
+inline void PassBase::shader_set(GPUShader *shader)
{
shader_ = shader;
create_command(Type::ShaderBind).shader_bind = {shader};
@@ -514,91 +569,91 @@ inline void Pass::shader_set(GPUShader *shader)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Resource bind
+/** \name Resource bind Implementation
* \{ */
-inline int Pass::push_constant_offset(const char *name)
+inline int PassBase::push_constant_offset(const char *name)
{
return GPU_shader_get_uniform(shader_, name);
}
-inline void Pass::bind(const char *name, GPUStorageBuf *buffer)
+inline void PassBase::bind(const char *name, GPUStorageBuf *buffer)
{
bind(GPU_shader_get_uniform_block_binding(shader_, name), buffer);
}
-inline void Pass::bind(const char *name, GPUUniformBuf *buffer)
+inline void PassBase::bind(const char *name, GPUUniformBuf *buffer)
{
bind(GPU_shader_get_ssbo(shader_, name), buffer);
}
-inline void Pass::bind(const char *name, GPUTexture *texture, eGPUSamplerState state)
+inline void PassBase::bind(const char *name, GPUTexture *texture, eGPUSamplerState state)
{
bind(GPU_shader_get_texture_binding(shader_, name), texture, state);
}
-inline void Pass::bind(const char *name, draw::Image *image)
+inline void PassBase::bind(const char *name, draw::Image *image)
{
bind(GPU_shader_get_texture_binding(shader_, name), image);
}
-inline void Pass::bind(int slot, GPUStorageBuf *buffer)
+inline void PassBase::bind(int slot, GPUStorageBuf *buffer)
{
create_command(Type::ResourceBind).resource_bind = {slot, buffer};
}
-inline void Pass::bind(int slot, GPUUniformBuf *buffer)
+inline void PassBase::bind(int slot, GPUUniformBuf *buffer)
{
create_command(Type::ResourceBind).resource_bind = {slot, buffer};
}
-inline void Pass::bind(int slot, GPUTexture *texture, eGPUSamplerState state)
+inline void PassBase::bind(int slot, GPUTexture *texture, eGPUSamplerState state)
{
create_command(Type::ResourceBind).resource_bind = {slot, texture, state};
}
-inline void Pass::bind(int slot, draw::Image *image)
+inline void PassBase::bind(int slot, draw::Image *image)
{
create_command(Type::ResourceBind).resource_bind = {slot, image};
}
-inline void Pass::bind(const char *name, GPUStorageBuf **buffer)
+inline void PassBase::bind(const char *name, GPUStorageBuf **buffer)
{
bind(GPU_shader_get_uniform_block_binding(shader_, name), buffer);
}
-inline void Pass::bind(const char *name, GPUUniformBuf **buffer)
+inline void PassBase::bind(const char *name, GPUUniformBuf **buffer)
{
bind(GPU_shader_get_ssbo(shader_, name), buffer);
}
-inline void Pass::bind(const char *name, GPUTexture **texture, eGPUSamplerState state)
+inline void PassBase::bind(const char *name, GPUTexture **texture, eGPUSamplerState state)
{
bind(GPU_shader_get_texture_binding(shader_, name), texture, state);
}
-inline void Pass::bind(const char *name, draw::Image **image)
+inline void PassBase::bind(const char *name, draw::Image **image)
{
bind(GPU_shader_get_texture_binding(shader_, name), image);
}
-inline void Pass::bind(int slot, GPUStorageBuf **buffer)
+inline void PassBase::bind(int slot, GPUStorageBuf **buffer)
{
create_command(Type::ResourceBind).resource_bind = {slot, buffer};
}
-inline void Pass::bind(int slot, GPUUniformBuf **buffer)
+inline void PassBase::bind(int slot, GPUUniformBuf **buffer)
{
create_command(Type::ResourceBind).resource_bind = {slot, buffer};
}
-inline void Pass::bind(int slot, GPUTexture **texture, eGPUSamplerState state)
+inline void PassBase::bind(int slot, GPUTexture **texture, eGPUSamplerState state)
{
create_command(Type::ResourceBind).resource_bind = {slot, texture, state};
}
-inline void Pass::bind(int slot, draw::Image **image)
+inline void PassBase::bind(int slot, draw::Image **image)
{
create_command(Type::ResourceBind).resource_bind = {slot, image};
}
@@ -606,100 +661,100 @@ inline void Pass::bind(int slot, draw::Image **image)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Push Constant
+/** \name Push Constant Implementation
* \{ */
-inline void Pass::push_constant(const char *name, const float &data)
+inline void PassBase::push_constant(const char *name, const float &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const float2 &data)
+inline void PassBase::push_constant(const char *name, const float2 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const float3 &data)
+inline void PassBase::push_constant(const char *name, const float3 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const float4 &data)
+inline void PassBase::push_constant(const char *name, const float4 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const int &data)
+inline void PassBase::push_constant(const char *name, const int &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const int2 &data)
+inline void PassBase::push_constant(const char *name, const int2 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const int3 &data)
+inline void PassBase::push_constant(const char *name, const int3 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const int4 &data)
+inline void PassBase::push_constant(const char *name, const int4 &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const bool &data)
+inline void PassBase::push_constant(const char *name, const bool &data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const float *data, int array_len)
+inline void PassBase::push_constant(const char *name, const float *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const float2 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const float2 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const float3 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const float3 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const float4 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const float4 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const int *data, int array_len)
+inline void PassBase::push_constant(const char *name, const int *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const int2 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const int2 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const int3 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const int3 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const int4 *data, int array_len)
+inline void PassBase::push_constant(const char *name, const int4 *data, int array_len)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data, array_len};
}
-inline void Pass::push_constant(const char *name, const float4x4 *data)
+inline void PassBase::push_constant(const char *name, const float4x4 *data)
{
create_command(Type::PushConstant).push_constant = {push_constant_offset(name), data};
}
-inline void Pass::push_constant(const char *name, const float4x4 &data)
+inline void PassBase::push_constant(const char *name, const float4x4 &data)
{
/* WORKAROUND: Push 3 consecutive commands to hold the 64 bytes of the float4x4.
* This assumes that all commands are always stored in flat array of memory. */
@@ -718,82 +773,8 @@ inline void Pass::push_constant(const char *name, const float4x4 &data)
create_command(Type::None) = commands[2];
}
-inline void Pass::submit_command(command::RecordingState &state,
- const command::Type &type,
- const command::Undetermined &command)
-{
- switch (type) {
- case command::Type::ShaderBind:
- command.shader_bind.execute(state);
- break;
- case command::Type::ResourceBind:
- command.resource_bind.execute();
- break;
- case command::Type::PushConstant:
- command.push_constant.execute(state);
- break;
- case command::Type::Draw:
- command.draw.execute(state);
- break;
- case command::Type::DrawIndirect:
- command.draw_indirect.execute(state);
- break;
- case command::Type::Dispatch:
- command.dispatch.execute(state);
- break;
- case command::Type::DispatchIndirect:
- command.dispatch_indirect.execute(state);
- break;
- case command::Type::Barrier:
- command.barrier.execute();
- break;
- case command::Type::Clear:
- command.clear.execute();
- break;
- case command::Type::StateSet:
- command.state_set.execute(state);
- break;
- case command::Type::StencilSet:
- command.stencil_set.execute();
- break;
- default:
- /* Skip Type::None. */
- break;
- }
-}
-
-inline std::string Pass::serialize_command(const command::Type &type,
- const command::Undetermined &command)
-{
- switch (type) {
- case command::Type::ShaderBind:
- return command.shader_bind.serialize();
- case command::Type::ResourceBind:
- return command.resource_bind.serialize();
- case command::Type::PushConstant:
- return command.push_constant.serialize();
- case command::Type::Draw:
- return command.draw.serialize();
- case command::Type::DrawIndirect:
- return command.draw_indirect.serialize();
- case command::Type::Dispatch:
- return command.dispatch.serialize();
- case command::Type::DispatchIndirect:
- return command.dispatch_indirect.serialize();
- case command::Type::Barrier:
- return command.barrier.serialize();
- case command::Type::Clear:
- return command.clear.serialize();
- case command::Type::StateSet:
- return command.state_set.serialize();
- case command::Type::StencilSet:
- return command.stencil_set.serialize();
- default:
- /* Skip Type::None. */
- return "";
- }
-}
-
/** \} */
+} // namespace detail
+
} // namespace blender::draw
diff --git a/source/blender/draw/tests/draw_pass_test.cc b/source/blender/draw/tests/draw_pass_test.cc
index c38c596b41d..8cd647e5894 100644
--- a/source/blender/draw/tests/draw_pass_test.cc
+++ b/source/blender/draw/tests/draw_pass_test.cc
@@ -10,8 +10,6 @@ namespace blender::draw {
static void test_draw_pass_all_commands()
{
- Manager drw;
-
Texture tex;
tex.ensure_2d(GPU_RGBA16, int2(1));
@@ -24,7 +22,7 @@ static void test_draw_pass_all_commands()
float alpha = 0.0f;
int3 dispatch_size(1);
- Pass pass = {"test.all_commands"};
+ PassSimple pass = {"test.all_commands"};
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_STENCIL);
pass.clear_color_depth_stencil(float4(0.25f, 0.5f, 100.0f, -2000.0f), 0.5f, 0xF0);
@@ -40,7 +38,7 @@ static void test_draw_pass_all_commands()
pass.bind("missing_ssbo", &ssbo); /* Should not crash. */
pass.push_constant("alpha", alpha);
pass.push_constant("alpha", &alpha);
- pass.draw(GPU_PRIM_TRIS, 1, 3);
+ pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
/* Should not crash even if shader is not a compute. This is because we only serialize. */
/* TODO(fclem): Use real compute shader. */
@@ -53,10 +51,31 @@ static void test_draw_pass_all_commands()
alpha = 1.0f;
dispatch_size = int3(2);
- std::string result = drw.serialize(pass);
- StringRefNull expected = "";
+ std::string result = pass.serialize();
+ std::stringstream expected;
+ expected << "PassSimple(test.all_commands)" << std::endl;
+ expected << ".state_set(6)" << std::endl;
+ expected << ".clear(color=(0.25, 0.5, 100, -2000), depth=0.5, stencil=0b11110000))" << std::endl;
+ expected << ".stencil_set(write_mask=0b10000000, compare_mask=0b00001111, reference=0b10001111"
+ << std::endl;
+ expected << ".shader_bind(gpu_shader_3D_image_modulate_alpha)" << std::endl;
+ expected << ".bind_texture(0)" << std::endl;
+ expected << ".bind_texture_ref(0)" << std::endl;
+ expected << ".bind_image(-1)" << std::endl;
+ expected << ".bind_image_ref(-1)" << std::endl;
+ expected << ".bind_uniform_buf(-1)" << std::endl;
+ expected << ".bind_uniform_buf_ref(-1)" << std::endl;
+ expected << ".bind_storage_buf(-1)" << std::endl;
+ expected << ".bind_storage_buf_ref(-1)" << std::endl;
+ expected << ".push_constant(2, data=0)" << std::endl;
+ expected << ".push_constant(2, data=1)" << std::endl;
+ expected << ".draw(inst_len=1, vert_len=3, vert_first=from_batch, res_id=0)" << std::endl;
+ expected << ".shader_bind(gpu_shader_3D_image_modulate_alpha)" << std::endl;
+ expected << ".dispatch(1, 1, 1)" << std::endl;
+ expected << ".dispatch_ref(2, 2, 2)" << std::endl;
+ expected << ".barrier(4)" << std::endl;
- EXPECT_EQ(result, expected);
+ EXPECT_EQ(result, expected.str());
}
DRAW_TEST(draw_pass_all_commands)