OBS图形及渲染
+ -

obs_init_graphics之effect着色器

2024-07-07 38 0

gs_effect_create_from_file函数中,会初始化着色器。
着色器文件主要有:

  1. struct obs_core_video {
  2. graphics_t *graphics;
  3. gs_effect_t *default_effect; //default.effect 默认纹理渲染
  4. gs_effect_t *default_rect_effect; //default_rect.effect 这个只有OPENGL用
  5. gs_effect_t *opaque_effect; //opaque.effect
  6. gs_effect_t *solid_effect; //solid.effect
  7. gs_effect_t *repeat_effect; //repeat.effect
  8. gs_effect_t *conversion_effect; //format_conversion.effect //视频格式转换
  9. gs_effect_t *bicubic_effect; //bicubic_scale.effect
  10. gs_effect_t *lanczos_effect; //lanczos_scale.effect
  11. gs_effect_t *area_effect; //area.effect
  12. gs_effect_t *bilinear_lowres_effect; //bilinear_lowres_scale.effect
  13. gs_effect_t *premultiplied_alpha_effect; //premultiplied_alpha.effect
  14. gs_samplerstate_t *point_sampler;
  15. ...
  16. }

这个着色器是通过gs_effect_create_from_file函数进行初始化的。例如:

  1. char *filename = obs_find_data_file("default.effect");
  2. video->default_effect = gs_effect_create_from_file(filename, NULL);
  3. bfree(filename);

其中obs_find_data_file用于获取文件的路径。

  1. gs_effect_t *gs_effect_create_from_file(const char *file, char **error_string)
  2. {
  3. char *file_string;
  4. gs_effect_t *effect = NULL;
  5. if (!gs_valid_p("gs_effect_create_from_file", file))
  6. return NULL;
  7. effect = find_cached_effect(file);
  8. if (effect)
  9. return effect;
  10. file_string = os_quick_read_utf8_file(file);
  11. if (!file_string) {
  12. blog(LOG_ERROR, "Could not load effect file '%s'", file);
  13. return NULL;
  14. }
  15. //文件内容,文件名,错误描述
  16. effect = gs_effect_create(file_string, file, error_string);
  17. bfree(file_string);
  18. return effect;
  19. }

首先确认是否已经加载了并处理了

  1. static inline struct gs_effect *find_cached_effect(const char *filename)
  2. {
  3. struct gs_effect *effect = thread_graphics->first_effect;
  4. while (effect) {
  5. if (strcmp(effect->effect_path, filename) == 0)
  6. break;
  7. effect = effect->next;
  8. }
  9. return effect;
  10. }

如果没有,则读取文件,格式为UTF-8,使用函数gs_effect_create来创建。

  1. gs_effect_t *gs_effect_create(const char *effect_string, const char *filename,
  2. char **error_string)
  3. {
  4. if (!gs_valid_p("gs_effect_create", effect_string))
  5. return NULL;
  6. //创建effect对象结构体
  7. struct gs_effect *effect = bzalloc(sizeof(struct gs_effect));
  8. bool success;
  9. effect->graphics = thread_graphics;
  10. effect->effect_path = bstrdup(filename);
  11. struct effect_parser parser;
  12. ep_init(&parser);
  13. success = ep_parse(&parser, effect, effect_string, filename);
  14. if (!success)
  15. {
  16. if (error_string)
  17. *error_string = error_data_buildstring(&parser.cfp.error_list);
  18. gs_effect_destroy(effect);
  19. effect = NULL;
  20. }
  21. //加入链表
  22. if (effect)
  23. {
  24. pthread_mutex_lock(&thread_graphics->effect_mutex);
  25. if (effect->effect_path)
  26. {
  27. effect->cached = true;
  28. effect->next = thread_graphics->first_effect;
  29. thread_graphics->first_effect = effect;
  30. }
  31. pthread_mutex_unlock(&thread_graphics->effect_mutex);
  32. }
  33. ep_free(&parser);
  34. return effect;
  35. }

ep_init初始化effect_parser parser结构体

  1. static inline void ep_init(struct effect_parser *ep)
  2. {
  3. da_init(ep->params);
  4. da_init(ep->structs);
  5. da_init(ep->funcs);
  6. da_init(ep->samplers);
  7. da_init(ep->techniques);
  8. da_init(ep->files);
  9. da_init(ep->tokens);
  10. ep->cur_pass = NULL;
  11. cf_parser_init(&ep->cfp);
  12. }

这玩意最后怎么还有lexer,有词法分析。

  1. bool ep_parse(struct effect_parser *ep, gs_effect_t *effect,
  2. const char *effect_string, const char *file)
  3. {
  4. bool success;
  5. //使用D3D11的DLL导出函数device_preprocessor_name()返回字符串 “_D3D11”
  6. const char *graphics_preprocessor = gs_preprocessor_name();
  7. //将字符串 “_D3D11”存储在pp成员中
  8. if (graphics_preprocessor)
  9. {
  10. struct cf_def def;
  11. cf_def_init(&def);
  12. def.name.str.array = graphics_preprocessor;
  13. def.name.str.len = strlen(graphics_preprocessor);
  14. strref_copy(&def.name.unmerged_str, &def.name.str);
  15. cf_preprocessor_add_def(&ep->cfp.pp, &def);
  16. }
  17. ep->effect = effect;
  18. //分析到ep
  19. if (!cf_parser_parse(&ep->cfp, effect_string, file))
  20. return false;
  21. while (ep->cfp.cur_token && ep->cfp.cur_token->type != CFTOKEN_NONE)
  22. {
  23. if (cf_token_is(&ep->cfp, ";") || is_whitespace(*ep->cfp.cur_token->str.array))
  24. {
  25. /* do nothing */
  26. ep->cfp.cur_token++;
  27. }
  28. else if (cf_token_is(&ep->cfp, "struct"))
  29. {
  30. ep_parse_struct(ep);
  31. }
  32. else if (cf_token_is(&ep->cfp, "technique"))
  33. {
  34. ep_parse_technique(ep);
  35. }
  36. else if (cf_token_is(&ep->cfp, "sampler_state"))
  37. {
  38. ep_parse_sampler_state(ep);
  39. }
  40. else if (cf_token_is(&ep->cfp, "{"))
  41. {
  42. /* add error and pass braces */
  43. cf_adderror(&ep->cfp, "Unexpected code segment", LEX_ERROR, NULL, NULL, NULL);
  44. cf_pass_pair(&ep->cfp, '{', '}');
  45. }
  46. else
  47. {
  48. /* parameters and functions */
  49. ep_parse_other(ep);
  50. }
  51. }
  52. success = !error_data_has_errors(&ep->cfp.error_list);
  53. if (success)
  54. success = ep_compile(ep);
  55. return success;
  56. }

cf_parser_parser函数主要实现词法分析,并将其加入到token数组中,并使cur_token指向第一个。
173721989395

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

这里只处理struct,technique和sampler_state。这些解析后的结果存于如下:

  1. struct gs_effect_technique {
  2. char *name;
  3. enum effect_section section;
  4. struct gs_effect *effect;
  5. DARRAY(struct gs_effect_pass) passes;
  6. };
  7. struct gs_effect {
  8. bool processing;//没有用
  9. bool cached; //该effect是否已经缓存
  10. char *effect_path, *effect_dir; //effect文件名称路径,effect_dir没有初始化为null
  11. gs_effect_param_array_t params;
  12. DARRAY(struct gs_effect_technique) techniques; //从effect文件中解出的所有tech
  13. //一个effect中有可以有多个tech,一个tech下一般只有一个pass
  14. struct gs_effect_technique *cur_technique;//当前正在运行的tech
  15. struct gs_effect_pass *cur_pass; //当前正在运行的pass,pass中有pixelshader和vertshader
  16. gs_eparam_t *view_proj, *world, *scale;
  17. graphics_t *graphics;
  18. struct gs_effect *next;
  19. size_t loop_pass; //pass的索引在cur_technique中的索引,即指针cur_pass
  20. bool looping; //tech是否正在运行
  21. };

struct

一个着色器的struct示例如下:

  1. struct VertInOut {
  2. float4 pos : POSITION;
  3. float2 uv : TEXCOORD0;
  4. };

解析后的内容ep_struct如下:

  1. enum ep_var_type {
  2. EP_VAR_NONE,
  3. EP_VAR_IN = EP_VAR_NONE,
  4. EP_VAR_INOUT,
  5. EP_VAR_OUT,
  6. EP_VAR_UNIFORM
  7. };
  8. struct ep_var {
  9. char *type, *name, *mapping;
  10. enum ep_var_type var_type;
  11. };
  12. typedef DARRAY(struct ep_var) ep_var_array_t;
  13. struct ep_struct {
  14. char *name;
  15. ep_var_array_t vars; /* struct ep_var */
  16. bool written;
  17. };

technique

一个technique的示例如下:

  1. technique Solid
  2. {
  3. pass
  4. {
  5. vertex_shader = VSSolid(vert_in);
  6. pixel_shader = PSSolid(vert_in);
  7. }
  8. }

解析后的结构体如下:

  1. struct ep_pass {
  2. char *name;
  3. cf_token_array_t vertex_program;
  4. cf_token_array_t fragment_program;
  5. struct gs_effect_pass *pass;
  6. };
  7. struct ep_technique {
  8. char *name;
  9. DARRAY(struct ep_pass) passes; /* struct ep_pass */
  10. };

sampler_state

一个sampler_state示例如下:

  1. sampler_state def_sampler {
  2. Filter = Linear;
  3. AddressU = Clamp;
  4. AddressV = Clamp;
  5. };

解析后结构体:

  1. struct ep_sampler {
  2. char *name;
  3. DARRAY(char *) states;
  4. DARRAY(char *) values;
  5. bool written;
  6. };

0 篇笔记 写笔记

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

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

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