OBS图形及渲染
+ -

obs_init_graphics之effect着色器

2024-07-07 29 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指向第一个。
173721989395

黑线是成员关系,红线是指针关系。

这里只处理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;
};

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!