着色器资源是渲染管线中必要的资源,在OpenGL中使用着色器对象和程序对象是密不可分的,GLShader类包含这些对象,来看一下它的定义:
namespace blender {
namespace gpu {
/**
* Implementation of shader compilation and uniforms handling using OpenGL.
*/
class GLShader : public Shader {
friend shader::ShaderCreateInfo;
friend shader::StageInterfaceInfo;
private:
/** Handle for full program (links shader stages below). */
GLuint shader_program_ = 0;
/** Individual shader stages. */
GLuint vert_shader_ = 0;
GLuint geom_shader_ = 0;
GLuint frag_shader_ = 0;
GLuint compute_shader_ = 0;
/** True if any shader failed to compile. */
bool compilation_failed_ = false;
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
public:
GLShader(const char *name);
~GLShader();
/** Return true on success. */
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
bool finalize(const shader::ShaderCreateInfo *info = nullptr) override;
void warm_cache(int /*limit*/) override{};
std::string resources_declare(const shader::ShaderCreateInfo &info) const override;
std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override;
std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override;
std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override;
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
/** Should be called before linking. */
void transform_feedback_names_set(Span<const char *> name_list,
eGPUShaderTFBType geom_type) override;
bool transform_feedback_enable(GPUVertBuf *buf) override;
void transform_feedback_disable() override;
void bind() override;
void unbind() override;
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
/* Unusued: SSBO vertex fetch draw parameters. */
bool get_uses_ssbo_vertex_fetch() const override
{
return false;
}
int get_ssbo_vertex_fetch_output_num_verts() const override
{
return 0;
}
/** DEPRECATED: Kept only because of BGL API. */
int program_handle_get() const override;
bool is_compute() const
{
return compute_shader_ != 0;
}
private:
char *glsl_patch_get(GLenum gl_stage);
/** Create, compile and attach the shader stage to the shader program. */
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
/**
* \brief features available on newer implementation such as native barycentric coordinates
* and layered rendering, necessitate a geometry shader to work on older hardware.
*/
std::string workaround_geometry_shader_source_create(const shader::ShaderCreateInfo &info);
bool do_geometry_shader_injection(const shader::ShaderCreateInfo *info);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
};
class GLLogParser : public GPULogParser {
public:
const char *parse_line(const char *log_line, GPULogItem &log_item) override;
protected:
const char *skip_severity_prefix(const char *log_line, GPULogItem &log_item);
const char *skip_severity_keyword(const char *log_line, GPULogItem &log_item);
MEM_CXX_CLASS_ALLOC_FUNCS("GLLogParser");
};
} // namespace gpu
} // namespace blender
GLShader会生成各种阶段(顶点,几何,片段)的着色器对象以及程序对象,并会进行编译和链接,以及对应结果状态的查询,以下函数是实现方法:
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
GLuint shader = glCreateShader(gl_stage);
if (shader == 0) {
fprintf(stderr, "GLShader: Error: Could not create shader object.\n");
return 0;
}
/* Patch the shader code using the first source slot. */
sources[0] = glsl_patch_get(gl_stage);
glShaderSource(shader, sources.size(), sources.data(), nullptr);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status || (G.debug & G_DEBUG_GPU)) {
char log[5000] = "";
glGetShaderInfoLog(shader, sizeof(log), nullptr, log);
if (log[0] != '\0') {
GLLogParser parser;
switch (gl_stage) {
case GL_VERTEX_SHADER:
this->print_log(sources, log, "VertShader", !status, &parser);
break;
case GL_GEOMETRY_SHADER:
this->print_log(sources, log, "GeomShader", !status, &parser);
break;
case GL_FRAGMENT_SHADER:
this->print_log(sources, log, "FragShader", !status, &parser);
break;
case GL_COMPUTE_SHADER:
this->print_log(sources, log, "ComputeShader", !status, &parser);
break;
}
}
}
if (!status) {
glDeleteShader(shader);
compilation_failed_ = true;
return 0;
}
debug::object_label(gl_stage, shader, name);
glAttachShader(shader_program_, shader);
return shader;
}
这段代码的的功能对于熟悉OpenGL管线编程的开发者来说并不复杂,需要特别介绍的是存储着色器代码字符串的带有模板参数的类MutableSpan<T>的功能。
在Blender中,MutableSpan是一种数据类型,用于表示可变的连续数据范围。它通常用于处理和操作数组、列表或其他连续数据结构的子集。
MutableSpan提供了一种轻量级的方式来引用和操作数据范围,而无需复制或重新分配内存。它包含了指向数据的指针和长度信息,可以用于读取、写入和修改数据。
使用MutableSpan可以有效地进行数据处理和操作,而无需创建新的数据副本。这对于处理大型数据集或需要频繁修改数据的情况非常有用,因为它避免了不必要的内存分配和复制操作。
在Blender中,MutableSpan常用于处理着色器代码字符串数据,顶点、法线、UV坐标等几何数据,以及像素数据、颜色数据等图像数据。它提供了一种高效的方式来访问和修改这些数据,从而实现各种编辑和操作功能。