obs_init_graphics之effect着色器
2024-07-07
38
0
gs_effect_create_from_file函数中,会初始化着色器。
着色器文件主要有:
struct obs_core_video {
graphics_t *graphics;
gs_effect_t *default_effect; //default.effect 默认纹理渲染
gs_effect_t *default_rect_effect; //default_rect.effect 这个只有OPENGL用
gs_effect_t *opaque_effect; //opaque.effect
gs_effect_t *solid_effect; //solid.effect
gs_effect_t *repeat_effect; //repeat.effect
gs_effect_t *conversion_effect; //format_conversion.effect //视频格式转换
gs_effect_t *bicubic_effect; //bicubic_scale.effect
gs_effect_t *lanczos_effect; //lanczos_scale.effect
gs_effect_t *area_effect; //area.effect
gs_effect_t *bilinear_lowres_effect; //bilinear_lowres_scale.effect
gs_effect_t *premultiplied_alpha_effect; //premultiplied_alpha.effect
gs_samplerstate_t *point_sampler;
...
}
这个着色器是通过gs_effect_create_from_file函数进行初始化的。例如:
char *filename = obs_find_data_file("default.effect");
video->default_effect = gs_effect_create_from_file(filename, NULL);
bfree(filename);
其中obs_find_data_file用于获取文件的路径。
gs_effect_t *gs_effect_create_from_file(const char *file, char **error_string)
{
char *file_string;
gs_effect_t *effect = NULL;
if (!gs_valid_p("gs_effect_create_from_file", file))
return NULL;
effect = find_cached_effect(file);
if (effect)
return effect;
file_string = os_quick_read_utf8_file(file);
if (!file_string) {
blog(LOG_ERROR, "Could not load effect file '%s'", file);
return NULL;
}
//文件内容,文件名,错误描述
effect = gs_effect_create(file_string, file, error_string);
bfree(file_string);
return effect;
}
首先确认是否已经加载了并处理了
static inline struct gs_effect *find_cached_effect(const char *filename)
{
struct gs_effect *effect = thread_graphics->first_effect;
while (effect) {
if (strcmp(effect->effect_path, filename) == 0)
break;
effect = effect->next;
}
return effect;
}
如果没有,则读取文件,格式为UTF-8,使用函数gs_effect_create来创建。
gs_effect_t *gs_effect_create(const char *effect_string, const char *filename,
char **error_string)
{
if (!gs_valid_p("gs_effect_create", effect_string))
return NULL;
//创建effect对象结构体
struct gs_effect *effect = bzalloc(sizeof(struct gs_effect));
bool success;
effect->graphics = thread_graphics;
effect->effect_path = bstrdup(filename);
struct effect_parser parser;
ep_init(&parser);
success = ep_parse(&parser, effect, effect_string, filename);
if (!success)
{
if (error_string)
*error_string = error_data_buildstring(&parser.cfp.error_list);
gs_effect_destroy(effect);
effect = NULL;
}
//加入链表
if (effect)
{
pthread_mutex_lock(&thread_graphics->effect_mutex);
if (effect->effect_path)
{
effect->cached = true;
effect->next = thread_graphics->first_effect;
thread_graphics->first_effect = effect;
}
pthread_mutex_unlock(&thread_graphics->effect_mutex);
}
ep_free(&parser);
return effect;
}
ep_init初始化effect_parser parser结构体
static inline void ep_init(struct effect_parser *ep)
{
da_init(ep->params);
da_init(ep->structs);
da_init(ep->funcs);
da_init(ep->samplers);
da_init(ep->techniques);
da_init(ep->files);
da_init(ep->tokens);
ep->cur_pass = NULL;
cf_parser_init(&ep->cfp);
}
这玩意最后怎么还有lexer,有词法分析。
bool ep_parse(struct effect_parser *ep, gs_effect_t *effect,
const char *effect_string, const char *file)
{
bool success;
//使用D3D11的DLL导出函数device_preprocessor_name()返回字符串 “_D3D11”
const char *graphics_preprocessor = gs_preprocessor_name();
//将字符串 “_D3D11”存储在pp成员中
if (graphics_preprocessor)
{
struct cf_def def;
cf_def_init(&def);
def.name.str.array = graphics_preprocessor;
def.name.str.len = strlen(graphics_preprocessor);
strref_copy(&def.name.unmerged_str, &def.name.str);
cf_preprocessor_add_def(&ep->cfp.pp, &def);
}
ep->effect = effect;
//分析到ep
if (!cf_parser_parse(&ep->cfp, effect_string, file))
return false;
while (ep->cfp.cur_token && ep->cfp.cur_token->type != CFTOKEN_NONE)
{
if (cf_token_is(&ep->cfp, ";") || is_whitespace(*ep->cfp.cur_token->str.array))
{
/* do nothing */
ep->cfp.cur_token++;
}
else if (cf_token_is(&ep->cfp, "struct"))
{
ep_parse_struct(ep);
}
else if (cf_token_is(&ep->cfp, "technique"))
{
ep_parse_technique(ep);
}
else if (cf_token_is(&ep->cfp, "sampler_state"))
{
ep_parse_sampler_state(ep);
}
else if (cf_token_is(&ep->cfp, "{"))
{
/* add error and pass braces */
cf_adderror(&ep->cfp, "Unexpected code segment", LEX_ERROR, NULL, NULL, NULL);
cf_pass_pair(&ep->cfp, '{', '}');
}
else
{
/* parameters and functions */
ep_parse_other(ep);
}
}
success = !error_data_has_errors(&ep->cfp.error_list);
if (success)
success = ep_compile(ep);
return success;
}
cf_parser_parser函数主要实现词法分析,并将其加入到token数组中,并使cur_token指向第一个。
黑线是成员关系,红线是指针关系。
这里只处理struct,technique和sampler_state。这些解析后的结果存于如下:
struct gs_effect_technique {
char *name;
enum effect_section section;
struct gs_effect *effect;
DARRAY(struct gs_effect_pass) passes;
};
struct gs_effect {
bool processing;//没有用
bool cached; //该effect是否已经缓存
char *effect_path, *effect_dir; //effect文件名称路径,effect_dir没有初始化为null
gs_effect_param_array_t params;
DARRAY(struct gs_effect_technique) techniques; //从effect文件中解出的所有tech
//一个effect中有可以有多个tech,一个tech下一般只有一个pass
struct gs_effect_technique *cur_technique;//当前正在运行的tech
struct gs_effect_pass *cur_pass; //当前正在运行的pass,pass中有pixelshader和vertshader
gs_eparam_t *view_proj, *world, *scale;
graphics_t *graphics;
struct gs_effect *next;
size_t loop_pass; //pass的索引在cur_technique中的索引,即指针cur_pass
bool looping; //tech是否正在运行
};
struct
一个着色器的struct示例如下:
struct VertInOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
解析后的内容ep_struct如下:
enum ep_var_type {
EP_VAR_NONE,
EP_VAR_IN = EP_VAR_NONE,
EP_VAR_INOUT,
EP_VAR_OUT,
EP_VAR_UNIFORM
};
struct ep_var {
char *type, *name, *mapping;
enum ep_var_type var_type;
};
typedef DARRAY(struct ep_var) ep_var_array_t;
struct ep_struct {
char *name;
ep_var_array_t vars; /* struct ep_var */
bool written;
};
technique
一个technique的示例如下:
technique Solid
{
pass
{
vertex_shader = VSSolid(vert_in);
pixel_shader = PSSolid(vert_in);
}
}
解析后的结构体如下:
struct ep_pass {
char *name;
cf_token_array_t vertex_program;
cf_token_array_t fragment_program;
struct gs_effect_pass *pass;
};
struct ep_technique {
char *name;
DARRAY(struct ep_pass) passes; /* struct ep_pass */
};
sampler_state
一个sampler_state示例如下:
sampler_state def_sampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
解析后结构体:
struct ep_sampler {
char *name;
DARRAY(char *) states;
DARRAY(char *) values;
bool written;
};