OBS image-source插件
+ -

着色器参数设置

2024-07-26 14 0

参数设置

数据结构关系绍下图:
150023947461
gs_effect中有一个数组params,每个params的类型为gs_effect_param。

故设置参数就是找至应的的gs_effect_param,修改其中的值。只不过这个值可能是各种类型的,故使用普遍类型DARRAY(uint8_t) cur_val存储。

    gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
    gs_eparam_t *color = gs_effect_get_param_by_name(solid, "color");
    gs_effect_set_vec4(color, colorVal);

获取数组中指定的gs_effect_prasm的指针,通过名称寻找

gs_eparam_t *gs_effect_get_param_by_name(const gs_effect_t *effect,
                     const char *name)
{
    if (!effect)
        return NULL;

    struct gs_effect_param *params = effect->params.array;

    for (size_t i = 0; i < effect->params.num; i++) {
        struct gs_effect_param *param = params + i;

        if (strcmp(param->name, name) == 0)
            return param;
    }

    return NULL;
}

值的设置很简单,就是原始数占多少字节,重置空间大小,按字节复制就行。

void gs_effect_set_vec4(gs_eparam_t *param, const struct vec4 *val)
{
    effect_setval_inline(param, val, sizeof(struct vec4));
}
static inline void effect_setval_inline(gs_eparam_t *param, const void *data,
                    size_t size)
{
    bool size_changed;
...
    size_changed = param->cur_val.num != size;

    if (size_changed)
        da_resize(param->cur_val, size);

    if (size_changed || memcmp(param->cur_val.array, data, size) != 0)
    {
        memcpy(param->cur_val.array, data, size);
        param->changed = true;
    }
}

参数加载

上面只是修改参数,而真正的参数加载是通过upload_parameters实现的。该函数由gs_technique_begin_pass调用。

bool gs_technique_begin_pass(gs_technique_t *tech, size_t idx)
{
    struct gs_effect_pass *passes;
    struct gs_effect_pass *cur_pass;

    if (!tech || idx >= tech->passes.num)
        return false;

    passes = tech->passes.array;
    cur_pass = passes + idx;

    tech->effect->cur_pass = cur_pass;
    gs_load_vertexshader(cur_pass->vertshader);//加载顶点着色器代码
    gs_load_pixelshader(cur_pass->pixelshader);//加载像素着色器代码
    upload_parameters(tech->effect, false); //加载着色器的参数

    return true;
}

每个pass都有其相关的参数,这些参数是包含2方面。

struct pass_shaderparam {
    struct gs_effect_param *eparam;  //pass私有参数指针
    gs_sparam_t *sparam;            //着色器的参数指针
};

所以通过upload_shader_params依旧从PASS的参数复制到着色器的参数空间。

static void upload_shader_params(struct darray *pass_params, bool changed_only)
{
    struct pass_shaderparam *params = pass_params->array;
    size_t i;

    for (i = 0; i < pass_params->num; i++)
    {
        struct pass_shaderparam *param = params + i;

        struct gs_effect_param *eparam = param->eparam;//pass私有参数空间
        gs_sparam_t *sparam = param->sparam;        //着色器参数空间

        if (eparam->next_sampler)
            gs_shader_set_next_sampler(sparam,  eparam->next_sampler);

        if (changed_only && !eparam->changed)
            continue;

        //pass如果还未设置值,使用其默认参数值
        if (!eparam->cur_val.num)
        {
            if (eparam->default_val.num)
                da_copy(eparam->cur_val, eparam->default_val);
            else
                continue;
        }

        //将pass私有能数复制到着色器空间
        gs_shader_set_val(sparam, eparam->cur_val.array, eparam->cur_val.num);
    }
}

由于数据有多个,故从第一个开始,到最后一个。如果PASS私有参数空间没有设置,就用默认值。

pass私有数据空间其实就是通过gs_effect_get_param_by_name类似的函数设置的。只是这里需要再将该数据复制到着色器显卡空间,让显卡使用。

其据D3D11和OPENGL的不同,其调用不同的回调函数。

void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
{
    graphics_t *graphics = thread_graphics;

    if (!gs_valid_p2("gs_shader_set_val", param, val))
        return;

    graphics->exports.gs_shader_set_val(param, val, size);
}

在D3D11对应的函数为:

void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
{
    shader_setval_inline(param, val, size);
}

再进一步为:

static inline void shader_setval_inline(gs_shader_param *param,
                    const void *data, size_t size)
{
    assert(param);
    if (!param)
        return;

    bool size_changed = param->curValue.size() != size;
    if (size_changed)
        param->curValue.resize(size);

    if (size_changed || memcmp(param->curValue.data(), data, size) != 0) {
        memcpy(param->curValue.data(), data, size);
        param->changed = true;
    }
}

着色器参数空间的创建

通过调试和栈回溯。
着色器空间参数也就是常量空间。其调用关系如下:

  • ep_compile_pass_shader
  • gs_pixelshader_create
  • device_pixelshader_create
  • gs_pixel_shader构造,其中解析出参数
  • BuildConstantBuffer,创建其常量空间,并初始化其默认值gs_shader_set_default

常量空间的创建如下:

void gs_shader::BuildConstantBuffer()
{
    for (size_t i = 0; i < params.size(); i++)
    {
        D3D11_BUFFER_DESC bd;
        memset(&bd, 0, sizeof(bd));
        bd.ByteWidth = (constantSize + 15) & 0xFFFFFFF0; /* align */
        bd.Usage = D3D11_USAGE_DYNAMIC;
        bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
        bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

        hr = device->device->CreateBuffer(&bd, NULL, constants.Assign());
    }

    for (size_t i = 0; i < params.size(); i++)
        gs_shader_set_default(&params[i]);
}

0 篇笔记 写笔记

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

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

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