在blender中,对VBO定义分了三个层次:
- 使用GPUVertBuf结构体在各种对象间传递数据;
- 使用VertBuf类描述顶点数据的数据结构
- 使用GLVertBuf类补充和OpenGL相关的参数
在blender中使用VertBuf描述一个VBO对象,需要包含以下接口和信息:
-
static size_t memory_usage;
:静态成员变量,用于跟踪VertBuf
类的内存使用情况。 -
GPUVertFormat format = {};
:GPUVertFormat
类型的成员变量,用于指定顶点的格式。 -
uint vertex_len = 0;
:无符号整数类型的成员变量,表示要绘制的顶点数量。 -
uint vertex_alloc = 0;
:无符号整数类型的成员变量,表示分配的顶点数据的数量。 -
GPUVertBufStatus flag = GPU_VERTBUF_INVALID;
:GPUVertBufStatus
类型的成员变量,表示顶点缓冲区的状态。 -
uchar *data = nullptr;
:指向无符号字符类型的指针,用于存储顶点数据的内存地址,在这个代码中,使用一个指向无符号字符类型的指针来表示顶点数据的存储位置,可能是为了灵活性和通用性的考虑。
无符号字符类型(
uchar
)是一个字节大小的数据类型,可以用来表示任意类型的数据。通过使用指向无符号字符类型的指针,可以将顶点数据的存储位置指向任意类型的数据,而不仅仅局限于特定的数据类型。这种灵活性对于处理不同格式的顶点数据非常有用。顶点数据可以包含各种属性,如位置、颜色、法线等,每个属性可能有不同的数据类型和格式。使用指向无符号字符类型的指针,可以轻松地处理不同格式的顶点数据,而不需要为每种格式定义不同的数据结构。
此外,使用指针还可以方便地进行内存管理和数据传输。通过在指针中存储顶点数据的起始地址,可以轻松地在内存中分配和释放顶点数据,以及在需要时将数据传输到显存中供GPU使用。
总而言之,使用指向无符号字符类型的指针来表示顶点数据的存储位置,提供了灵活性、通用性和方便性,使得处理不同格式的顶点数据更加简便和高效。
-
GPUUsageType extended_usage_;
:GPUUsageType
类型的成员变量,表示扩展的使用类型。 -
GPUUsageType usage_;
:GPUUsageType
类型的成员变量,表示使用类型的提示,用于OpenGL优化。 -
int handle_refcount_ = 1;
:整数类型的成员变量,表示引用计数器,用于避免释放GPUVertBuf
对象。
namespace blender::gpu {
/**
* Implementation of Vertex Buffers.
* Base class which is then specialized for each implementation (GL, VK, ...).
*/
class VertBuf {
public:
static size_t memory_usage;
GPUVertFormat format = {};
/** Number of verts we want to draw. */
uint vertex_len = 0;
/** Number of verts data. */
uint vertex_alloc = 0;
/** Status flag. */
GPUVertBufStatus flag = GPU_VERTBUF_INVALID;
/** NULL indicates data in VRAM (unmapped) */
uchar *data = nullptr;
#ifndef NDEBUG
/** Usage including extended usage flags. */
GPUUsageType extended_usage_ = GPU_USAGE_STATIC;
#endif
protected:
/** Usage hint for GL optimization. */
GPUUsageType usage_ = GPU_USAGE_STATIC;
private:
/** This counter will only avoid freeing the #GPUVertBuf, not the data. */
int handle_refcount_ = 1;
public:
VertBuf();
virtual ~VertBuf();
void init(const GPUVertFormat *format, GPUUsageType usage);
void clear();
/* Data management. */
void allocate(uint vert_len);
void resize(uint vert_len);
void upload();
virtual void bind_as_ssbo(uint binding) = 0;
virtual void bind_as_texture(uint binding) = 0;
virtual void wrap_handle(uint64_t handle) = 0;
VertBuf *duplicate();
/* Size of the data allocated. */
size_t size_alloc_get() const
{
BLI_assert(format.packed);
return vertex_alloc * format.stride;
}
/* Size of the data uploaded to the GPU. */
size_t size_used_get() const
{
BLI_assert(format.packed);
return vertex_len * format.stride;
}
void reference_add()
{
handle_refcount_++;
}
void reference_remove()
{
BLI_assert(handle_refcount_ > 0);
handle_refcount_--;
if (handle_refcount_ == 0) {
delete this;
}
}
GPUUsageType get_usage_type() const
{
return usage_;
}
virtual void update_sub(uint start, uint len, const void *data) = 0;
virtual void read(void *data) const = 0;
protected:
virtual void acquire_data() = 0;
virtual void resize_data() = 0;
virtual void release_data() = 0;
virtual void upload_data() = 0;
virtual void duplicate_data(VertBuf *dst) = 0;
};
/* Syntactic sugar. */
static inline GPUVertBuf *wrap(VertBuf *vert)
{
return reinterpret_cast<GPUVertBuf *>(vert);
}
static inline VertBuf *unwrap(GPUVertBuf *vert)
{
return reinterpret_cast<VertBuf *>(vert);
}
static inline const VertBuf *unwrap(const GPUVertBuf *vert)
{
return reinterpret_cast<const VertBuf *>(vert);
}
} // namespace blender::gpu
最后使用GLVertBuf补充与OpenGL相关的参数
-
GLuint vbo_id_ = 0;
:无符号整数类型的成员变量,表示OpenGL缓冲区的句柄。 -
::GPUTexture *buffer_texture_ = nullptr;
:指向GPUTexture
类型的指针,表示如果缓冲区被绑定为缓冲区纹理,则使用的纹理。在首次使用时进行初始化。 -
bool is_wrapper_ = false;
:布尔类型的成员变量,表示缓冲区句柄是否由GLVertBuf
包装,即我们不拥有它并且不应该释放它。 -
size_t vbo_size_ = 0;
:表示在GPU上的缓冲区大小
namespace blender {
namespace gpu {
class GLVertBuf : public VertBuf {
friend class GLTexture; /* For buffer texture. */
friend class GLShader; /* For transform feedback. */
friend class GLStorageBuf; /* For sub copy. */
private:
/** OpenGL buffer handle. Init on first upload. Immutable after that. */
GLuint vbo_id_ = 0;
/** Texture used if the buffer is bound as buffer texture. Init on first use. */
::GPUTexture *buffer_texture_ = nullptr;
/** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and
* should not free it. */
bool is_wrapper_ = false;
/** Size on the GPU. */
size_t vbo_size_ = 0;
public:
void bind();
void update_sub(uint start, uint len, const void *data) override;
void read(void *data) const override;
void wrap_handle(uint64_t handle) override;
protected:
void acquire_data() override;
void resize_data() override;
void release_data() override;
void upload_data() override;
void duplicate_data(VertBuf *dst) override;
void bind_as_ssbo(uint binding) override;
void bind_as_texture(uint binding) override;
private:
bool is_active() const;
MEM_CXX_CLASS_ALLOC_FUNCS("GLVertBuf");
};
static inline GLenum to_gl(GPUUsageType type)
{
switch (type) {
case GPU_USAGE_STREAM:
return GL_STREAM_DRAW;
case GPU_USAGE_DYNAMIC:
return GL_DYNAMIC_DRAW;
case GPU_USAGE_STATIC:
case GPU_USAGE_DEVICE_ONLY:
return GL_STATIC_DRAW;
default:
BLI_assert(0);
return GL_STATIC_DRAW;
}
}
static inline GLenum to_gl(GPUVertCompType type)
{
switch (type) {
case GPU_COMP_I8:
return GL_BYTE;
case GPU_COMP_U8:
return GL_UNSIGNED_BYTE;
case GPU_COMP_I16:
return GL_SHORT;
case GPU_COMP_U16:
return GL_UNSIGNED_SHORT;
case GPU_COMP_I32:
return GL_INT;
case GPU_COMP_U32:
return GL_UNSIGNED_INT;
case GPU_COMP_F32:
return GL_FLOAT;
case GPU_COMP_I10:
return GL_INT_2_10_10_10_REV;
default:
BLI_assert(0);
return GL_FLOAT;
}
}
} // namespace gpu
} // namespace blender