着色器参数设置
2024-07-26
28
0
参数设置
数据结构关系绍下图:
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(¶ms[i]);
}