在Blender中有多个引擎,其中Eevee引擎的特性是实时渲染性能好,这个系列的文章将以分析Eevee引擎的设计方法为目的,逐步探究Blender中为渲染工作所设计的各种类的作用。
GPUBackend类是一个充分包含渲染管线资源的虚类,先看一下它的定义。
namespace blender {
namespace gpu {
class Context;
class Batch;
class DrawList;
class Fence;
class FrameBuffer;
class IndexBuf;
class PixelBuffer;
class QueryPool;
class Shader;
class Texture;
class UniformBuf;
class StorageBuf;
class VertBuf;
class GPUBackend {
public:
virtual ~GPUBackend() = default;
virtual void delete_resources() = 0;
static GPUBackend *get();
virtual void samplers_update() = 0;
virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0;
virtual void compute_dispatch_indirect(StorageBuf *indirect_buf) = 0;
virtual Context *context_alloc(void *ghost_window, void *ghost_context) = 0;
virtual Batch *batch_alloc() = 0;
virtual DrawList *drawlist_alloc(int list_length) = 0;
virtual Fence *fence_alloc() = 0;
virtual FrameBuffer *framebuffer_alloc(const char *name) = 0;
virtual IndexBuf *indexbuf_alloc() = 0;
virtual PixelBuffer *pixelbuf_alloc(uint size) = 0;
virtual QueryPool *querypool_alloc() = 0;
virtual Shader *shader_alloc(const char *name) = 0;
virtual Texture *texture_alloc(const char *name) = 0;
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
virtual StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) = 0;
virtual VertBuf *vertbuf_alloc() = 0;
/* Render Frame Coordination --
* Used for performing per-frame actions globally */
virtual void render_begin() = 0;
virtual void render_end() = 0;
virtual void render_step() = 0;
};
} // namespace gpu
} // namespace blender
在使用OpenGL时,Blender设计了一个子类GLBackend,用来实现OpenGL的实现方法;
namespace blender {
namespace gpu {
class GLBackend : public GPUBackend {
private:
GLSharedOrphanLists shared_orphan_list_;
#ifdef WITH_RENDERDOC
renderdoc::api::Renderdoc renderdoc_;
#endif
public:
GLBackend()
{
/* platform_init needs to go first. */
GLBackend::platform_init();
GLBackend::capabilities_init();
GLTexture::samplers_init();
}
~GLBackend()
{
GLBackend::platform_exit();
}
void delete_resources() override
{
/* Delete any resources with context active. */
GLTexture::samplers_free();
}
static GLBackend *get()
{
return static_cast<GLBackend *>(GPUBackend::get());
}
void samplers_update() override
{
GLTexture::samplers_update();
};
Context *context_alloc(void *ghost_window, void * /*ghost_context*/) override
{
return new GLContext(ghost_window, shared_orphan_list_);
};
Batch *batch_alloc() override
{
return new GLBatch();
};
DrawList *drawlist_alloc(int list_length) override
{
return new GLDrawList(list_length);
};
Fence *fence_alloc() override
{
return new GLFence();
};
FrameBuffer *framebuffer_alloc(const char *name) override
{
return new GLFrameBuffer(name);
};
IndexBuf *indexbuf_alloc() override
{
return new GLIndexBuf();
};
PixelBuffer *pixelbuf_alloc(uint size) override
{
return new GLPixelBuffer(size);
};
QueryPool *querypool_alloc() override
{
return new GLQueryPool();
};
Shader *shader_alloc(const char *name) override
{
return new GLShader(name);
};
Texture *texture_alloc(const char *name) override
{
return new GLTexture(name);
};
UniformBuf *uniformbuf_alloc(int size, const char *name) override
{
return new GLUniformBuf(size, name);
};
StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) override
{
return new GLStorageBuf(size, usage, name);
};
VertBuf *vertbuf_alloc() override
{
return new GLVertBuf();
};
GLSharedOrphanLists &shared_orphan_list_get()
{
return shared_orphan_list_;
};
void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
{
GLContext::get()->state_manager_active_get()->apply_state();
GLCompute::dispatch(groups_x_len, groups_y_len, groups_z_len);
}
void compute_dispatch_indirect(StorageBuf *indirect_buf) override
{
GLContext::get()->state_manager_active_get()->apply_state();
dynamic_cast<GLStorageBuf *>(indirect_buf)->bind_as(GL_DISPATCH_INDIRECT_BUFFER);
/* This barrier needs to be here as it only work on the currently bound indirect buffer. */
glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
glDispatchComputeIndirect((GLintptr)0);
/* Unbind. */
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
}
/* Render Frame Coordination */
void render_begin() override{};
void render_end() override{};
void render_step() override{};
bool debug_capture_begin();
void debug_capture_end();
private:
static void platform_init();
static void platform_exit();
static void capabilities_init();
};
} // namespace gpu
} // namespace blender
从GLBackend类的接口来看,可以确定GLShader等类也是继承自gup_shader_private.h文件中定的定义的Shader类,其他资源也是如此。由此可见,Blender使用了动态绑定的方法来管理渲染管线中的资源。