From f9d1a4b9ed165b10ff51e406159795bebcc7d73c Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sun, 6 Oct 2013 18:29:29 -0700 Subject: [PATCH] added first GLSL code, moved some graphics functions around, and adjusted some existing shader parser code --- libobs-d3d11/GS_D3D11ShaderProcessor.cpp | 16 +- libobs-opengl/gl-shaderparser.c | 240 ++++++++++++++++++ libobs-opengl/gl-shaderparser.h | 51 ++++ libobs-opengl/gl-texturecube.c | 2 + libobs/graphics/graphics.h | 86 ++++--- libobs/graphics/shader-parser.c | 10 +- libobs/graphics/shader-parser.h | 54 +++- vs/2010/libobs-opengl/libobs-opengl.vcxproj | 2 + .../libobs-opengl.vcxproj.filters | 6 + 9 files changed, 404 insertions(+), 63 deletions(-) create mode 100644 libobs-opengl/gl-shaderparser.c create mode 100644 libobs-opengl/gl-shaderparser.h diff --git a/libobs-d3d11/GS_D3D11ShaderProcessor.cpp b/libobs-d3d11/GS_D3D11ShaderProcessor.cpp index a836e3ed7..ce771d22d 100644 --- a/libobs-d3d11/GS_D3D11ShaderProcessor.cpp +++ b/libobs-d3d11/GS_D3D11ShaderProcessor.cpp @@ -224,13 +224,13 @@ void ShaderProcessor::BuildString(string &outputString) void ShaderProcessor::Process(const char *shader_string, const char *file) { - if (!shader_parse(&parser, shader_string, file)) { - char *str = error_data_buildstring(&parser.cfp.error_list); - if (str) { - blog(LOG_WARNING, "Shader parser errors/warnings:\n" - "%s\n", str); - bfree(str); - } - throw "Failed to parse shader"; + bool success = shader_parse(&parser, shader_string, file); + char *str = shader_parser_geterrors(&parser); + if (str) { + blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str); + bfree(str); } + + if (!success) + throw "Failed to parse shader"; } diff --git a/libobs-opengl/gl-shaderparser.c b/libobs-opengl/gl-shaderparser.c new file mode 100644 index 000000000..e72bf3796 --- /dev/null +++ b/libobs-opengl/gl-shaderparser.c @@ -0,0 +1,240 @@ +/****************************************************************************** + Copyright (C) 2013 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include "gl-subsystem.h" +#include "gl-shaderparser.h" + +static void gl_write_type_n(struct gl_shader_parser *glsp, + const char *type, size_t len) +{ + if (astrcmp_n(type, "float2", len) == 0) + dstr_cat(&glsp->gl_string, "vec2"); + else if (astrcmp_n(type, "float3", len) == 0) + dstr_cat(&glsp->gl_string, "vec3"); + else if (astrcmp_n(type, "float4", len) == 0) + dstr_cat(&glsp->gl_string, "vec4"); + else if (astrcmp_n(type, "float3x3", len) == 0) + dstr_cat(&glsp->gl_string, "mat3x3"); + else if (astrcmp_n(type, "float3x4", len) == 0) + dstr_cat(&glsp->gl_string, "mat3x4"); + else if (astrcmp_n(type, "float4x4", len) == 0) + dstr_cat(&glsp->gl_string, "mat4x4"); + else if (astrcmp_n(type, "texture2d", len) == 0) + dstr_cat(&glsp->gl_string, "sampler2D"); + else if (astrcmp_n(type, "texture3d", len) == 0) + dstr_cat(&glsp->gl_string, "sampler3D"); + else if (astrcmp_n(type, "texture_cube", len) == 0) + dstr_cat(&glsp->gl_string, "samplerCube"); + else + dstr_ncat(&glsp->gl_string, type, len); +} + +static inline void gl_write_type(struct gl_shader_parser *glsp, + const char *type) +{ + gl_write_type_n(glsp, type, strlen(type)); +} + +static inline void gl_write_type_token(struct gl_shader_parser *glsp, + struct cf_token *token) +{ + gl_write_type_n(glsp, token->str.array, token->str.len); +} + +static void gl_write_var(struct gl_shader_parser *glsp, struct shader_var *var) +{ + if (var->var_type == SHADER_VAR_UNIFORM) + dstr_cat(&glsp->gl_string, "uniform "); + else if (var->var_type == SHADER_VAR_CONST) + dstr_cat(&glsp->gl_string, "const "); + + gl_write_type(glsp, var->type); + dstr_cat(&glsp->gl_string, " "); + dstr_cat(&glsp->gl_string, var->name); + dstr_cat(&glsp->gl_string, ";\n"); +} + +static inline void gl_write_params(struct gl_shader_parser *glsp) +{ + size_t i; + for (i = 0; i < glsp->parser.params.num; i++) { + struct shader_var *var = glsp->parser.params.array+i; + gl_write_var(glsp, var); + } + + dstr_cat(&glsp->gl_string, "\n"); +} + +static void gl_write_storage_var(struct gl_shader_parser *glsp, + struct shader_var *var, const char *storage, + const char *prefix); + +/* unwraps a structure that's used for input/output */ +static void gl_unwrap_storage_struct(struct gl_shader_parser *glsp, + struct shader_struct *st, const char *storage, + const char *prefix) +{ + struct dstr prefix_str; + size_t i; + + dstr_init(&prefix_str); + if (prefix) + dstr_copy(&prefix_str, prefix); + dstr_cat(&prefix_str, st->name); + dstr_cat(&prefix_str, "_"); + + for (i = 0; i < st->vars.num; i++) { + struct shader_var *st_var = st->vars.array+i; + gl_write_storage_var(glsp, st_var, storage, prefix_str.array); + } + + dstr_free(&prefix_str); +} + +static void gl_write_storage_var(struct gl_shader_parser *glsp, + struct shader_var *var, const char *storage, const char *prefix) +{ + struct shader_struct *st = shader_parser_getstruct(&glsp->parser, + var->type); + + if (st) { + gl_unwrap_storage_struct(glsp, st, storage, prefix); + } else { + if (storage) { + dstr_cat(&glsp->gl_string, storage); + dstr_cat(&glsp->gl_string, " "); + } + + gl_write_type(glsp, var->type); + dstr_cat(&glsp->gl_string, " "); + if (prefix) + dstr_cat(&glsp->gl_string, prefix); + dstr_cat(&glsp->gl_string, var->name); + dstr_cat(&glsp->gl_string, ";\n"); + } +} + +static inline void gl_write_inputs(struct gl_shader_parser *glsp, + struct shader_func *main) +{ + size_t i; + for (i = 0; i < main->params.num; i++) { + struct shader_var *var = main->params.array+i; + gl_write_storage_var(glsp, var, "in", "in_"); + } +} + +static void gl_write_outputs(struct gl_shader_parser *glsp, + struct shader_func *main) +{ + struct shader_var var; + + shader_var_init(&var); + var.type = bstrdup(main->return_type); + var.name = bstrdup("return_val"); + if (main->return_mapping) + var.mapping = bstrdup(main->return_mapping); + + gl_write_storage_var(glsp, &var, "out", "out_"); + shader_var_free(&var); +} + +static void gl_write_struct(struct gl_shader_parser *glsp, + struct shader_struct *st) +{ + size_t i; + dstr_cat(&glsp->gl_string, "struct "); + dstr_cat(&glsp->gl_string, st->name); + dstr_cat(&glsp->gl_string, " {\n"); + + for (i = 0; i < st->vars.num; i++) { + struct shader_var *var = st->vars.array+i; + + dstr_cat(&glsp->gl_string, "\t"); + gl_write_var(glsp, var); + } + + dstr_cat(&glsp->gl_string, "};\n\n"); +} + +static inline void gl_write_structs(struct gl_shader_parser *glsp) +{ + size_t i; + for (i = 0; i < glsp->parser.structs.num; i++) { + struct shader_struct *st = glsp->parser.structs.array+i; + gl_write_struct(glsp, st); + } +} + +/* + * NOTE: HLSL-> GLSL intrinsic conversions + * atan2 -> atan + * clip -> (unsupported) + * ddx -> dFdx + * ddy -> dFdy + * fmod -> (unsupported) + * frac -> fract + * lerp -> mix + * lit -> (unsupported) + * log10 -> (unsupported) + * mul -> (change to operator) + * rsqrt -> inversesqrt + * saturate -> (use clamp) + * tex* -> texture + * tex*grad -> textureGrad + * tex*lod -> textureLod + * tex*bias -> (use optional 'bias' value) + * tex*proj -> textureProj + * + * All else can be left as-is + */ + +static void gl_write_functions(struct gl_shader_parser *glsp) +{ +} + +static bool gl_shader_buildstring(struct gl_shader_parser *glsp) +{ + struct shader_func *main = shader_parser_getfunc(&glsp->parser, "main"); + if (!main) { + blog(LOG_ERROR, "function 'main' not found"); + return false; + } + + dstr_copy(&glsp->gl_string, "#version 140\n\n"); + gl_write_params(glsp); + gl_write_inputs(glsp, main); + gl_write_outputs(glsp, main); + gl_write_structs(glsp); + gl_write_functions(glsp); + // gl_write_main(glsp); + + return true; +} + +bool gl_shader_parse(struct gl_shader_parser *glsp, + const char *shader_str, const char *file) +{ + bool success = shader_parse(&glsp->parser, shader_str, file); + char *str = shader_parser_geterrors(&glsp->parser); + if (str) { + blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str); + bfree(str); + } + + return success; +} diff --git a/libobs-opengl/gl-shaderparser.h b/libobs-opengl/gl-shaderparser.h new file mode 100644 index 000000000..bcc4cb59d --- /dev/null +++ b/libobs-opengl/gl-shaderparser.h @@ -0,0 +1,51 @@ +/****************************************************************************** + Copyright (C) 2013 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#ifndef GL_SHADER_PARSER_H +#define GL_SHADER_PARSER_H + +/* + * Parses shaders into GLSL. Shaders are almost identical to HLSL + * model 5 so it requires quite a bit of tweaking to convert correctly. + * Takes the parsed shader data, and builds a GLSL string out of it. + */ + +#include "util/dstr.h" +#include "graphics/shader-parser.h" + +struct gl_shader_parser { + struct dstr gl_string; + struct dstr gl_main_func; + struct shader_parser parser; +}; + +static inline void gl_shader_parser_init(struct gl_shader_parser *glsp) +{ + shader_parser_init(&glsp->parser); + dstr_init(&glsp->gl_string); +} + +static inline void gl_shader_parser_free(struct gl_shader_parser *glsp) +{ + dstr_free(&glsp->gl_string); + shader_parser_free(&glsp->parser); +} + +extern bool gl_shader_parse(struct gl_shader_parser *glsp, + const char *shader_str, const char *file); + +#endif diff --git a/libobs-opengl/gl-texturecube.c b/libobs-opengl/gl-texturecube.c index ebc03ad4b..137f47bdd 100644 --- a/libobs-opengl/gl-texturecube.c +++ b/libobs-opengl/gl-texturecube.c @@ -62,6 +62,8 @@ texture_t device_create_cubetexture(device_t device, uint32_t size, tex->base.format = color_format; tex->base.gl_format = convert_gs_format(color_format); tex->base.gl_internal_format = convert_gs_internal_format(color_format); + tex->base.is_render_target = flags & GS_RENDERTARGET; + tex->base.gen_mipmaps = flags & GS_BUILDMIPMAPS; tex->size = size; if (!gl_gen_textures(1, &tex->base.texture)) diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index 563bcecc6..64fd72243 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -226,48 +226,6 @@ struct gs_rect { int cy; }; -static inline uint32_t gs_get_format_bpp(enum gs_color_format format) -{ - switch (format) { - case GS_A8: return 8; - case GS_R8: return 8; - case GS_RGBA: return 32; - case GS_BGRX: return 32; - case GS_BGRA: return 32; - case GS_R10G10B10A2: return 32; - case GS_RGBA16: return 64; - case GS_R16: return 16; - case GS_RGBA16F: return 64; - case GS_RGBA32F: return 128; - case GS_RG16F: return 32; - case GS_RG32F: return 64; - case GS_R16F: return 16; - case GS_R32F: return 32; - case GS_DXT1: return 4; - case GS_DXT3: return 8; - case GS_DXT5: return 8; - default: return 0; - } -} - -static inline bool gs_is_compressed_format(enum gs_color_format format) -{ - return (format == GS_DXT1 || format == GS_DXT3 || format == GS_DXT5); -} - -static inline uint32_t gs_num_total_levels(uint32_t width, uint32_t height) -{ - uint32_t size = width > height ? width : height; - uint32_t num_levels = 0; - - while (size > 1) { - size /= 2; - num_levels++; - } - - return num_levels; -} - /* wrapped opaque data types */ struct gs_texture; @@ -700,6 +658,50 @@ EXPORT void *indexbuffer_getdata(indexbuffer_t indexbuffer); EXPORT size_t indexbuffer_numindices(indexbuffer_t indexbuffer); EXPORT enum gs_index_type indexbuffer_gettype(indexbuffer_t indexbuffer); +/* inline functions used by modules */ + +static inline uint32_t gs_get_format_bpp(enum gs_color_format format) +{ + switch (format) { + case GS_A8: return 8; + case GS_R8: return 8; + case GS_RGBA: return 32; + case GS_BGRX: return 32; + case GS_BGRA: return 32; + case GS_R10G10B10A2: return 32; + case GS_RGBA16: return 64; + case GS_R16: return 16; + case GS_RGBA16F: return 64; + case GS_RGBA32F: return 128; + case GS_RG16F: return 32; + case GS_RG32F: return 64; + case GS_R16F: return 16; + case GS_R32F: return 32; + case GS_DXT1: return 4; + case GS_DXT3: return 8; + case GS_DXT5: return 8; + default: return 0; + } +} + +static inline bool gs_is_compressed_format(enum gs_color_format format) +{ + return (format == GS_DXT1 || format == GS_DXT3 || format == GS_DXT5); +} + +static inline uint32_t gs_num_total_levels(uint32_t width, uint32_t height) +{ + uint32_t size = width > height ? width : height; + uint32_t num_levels = 0; + + while (size > 1) { + size /= 2; + num_levels++; + } + + return num_levels; +} + #ifdef __cplusplus } #endif diff --git a/libobs/graphics/shader-parser.c b/libobs/graphics/shader-parser.c index 809da93fa..e8c33937c 100644 --- a/libobs/graphics/shader-parser.c +++ b/libobs/graphics/shader-parser.c @@ -400,8 +400,7 @@ exit: return true; } -static void sp_parse_function(struct shader_parser *sp, - char *type, char *name) +static void sp_parse_function(struct shader_parser *sp, char *type, char *name) { struct shader_func func; @@ -414,8 +413,13 @@ static void sp_parse_function(struct shader_parser *sp, /* if function is mapped to something, for example COLOR */ if (token_is(&sp->cfp, ":")) { - if (!next_valid_token(&sp->cfp)) + char *mapping = NULL; + int errorcode = next_name(&sp->cfp, &mapping, "mapping", "{"); + if (errorcode != PARSE_SUCCESS) goto error; + + func.return_mapping = mapping; + if (!next_valid_token(&sp->cfp)) goto error; } diff --git a/libobs/graphics/shader-parser.h b/libobs/graphics/shader-parser.h index 8b1805316..d2c1b9e03 100644 --- a/libobs/graphics/shader-parser.h +++ b/libobs/graphics/shader-parser.h @@ -141,6 +141,7 @@ static inline void shader_struct_free(struct shader_struct *ss) struct shader_func { char *name; char *return_type; + char *return_mapping; DARRAY(struct shader_var) params; const struct cf_token *start, *end; @@ -151,10 +152,11 @@ static inline void shader_func_init(struct shader_func *sf, { da_init(sf->params); - sf->return_type = return_type; - sf->name = name; - sf->start = NULL; - sf->end = NULL; + sf->return_type = return_type; + sf->return_mapping = NULL; + sf->name = name; + sf->start = NULL; + sf->end = NULL; } static inline void shader_func_free(struct shader_func *sf) @@ -166,6 +168,7 @@ static inline void shader_func_free(struct shader_func *sf) bfree(sf->name); bfree(sf->return_type); + bfree(sf->return_mapping); da_free(sf->params); } @@ -213,14 +216,19 @@ static inline void shader_parser_free(struct shader_parser *sp) EXPORT bool shader_parse(struct shader_parser *sp, const char *shader, const char *file); -static inline struct shader_func *shader_parser_getfunc( - struct shader_parser *sp, const char *func_name) +static inline char *shader_parser_geterrors(struct shader_parser *sp) +{ + return error_data_buildstring(&sp->cfp.error_list); +} + +static inline struct shader_var *shader_parser_getparam( + struct shader_parser *sp, const char *param_name) { size_t i; - for (i = 0; i < sp->funcs.num; i++) { - struct shader_func *func = sp->funcs.array+i; - if (strcmp(func->name, func_name) == 0) - return func; + for (i = 0; i < sp->params.num; i++) { + struct shader_var *param = sp->params.array+i; + if (strcmp(param->name, param_name) == 0) + return param; } return NULL; @@ -239,6 +247,32 @@ static inline struct shader_struct *shader_parser_getstruct( return NULL; } +static inline struct shader_sampler *shader_parser_getsampler( + struct shader_parser *sp, const char *sampler_name) +{ + size_t i; + for (i = 0; i < sp->samplers.num; i++) { + struct shader_sampler *sampler = sp->samplers.array+i; + if (strcmp(sampler->name, sampler_name) == 0) + return sampler; + } + + return NULL; +} + +static inline struct shader_func *shader_parser_getfunc( + struct shader_parser *sp, const char *func_name) +{ + size_t i; + for (i = 0; i < sp->funcs.num; i++) { + struct shader_func *func = sp->funcs.array+i; + if (strcmp(func->name, func_name) == 0) + return func; + } + + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/vs/2010/libobs-opengl/libobs-opengl.vcxproj b/vs/2010/libobs-opengl/libobs-opengl.vcxproj index 69dc17576..a971b12d0 100644 --- a/vs/2010/libobs-opengl/libobs-opengl.vcxproj +++ b/vs/2010/libobs-opengl/libobs-opengl.vcxproj @@ -157,10 +157,12 @@ + + diff --git a/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters b/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters index 6e756ae24..acccc81ef 100644 --- a/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters +++ b/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters @@ -24,6 +24,9 @@ Header Files + + Header Files + @@ -41,5 +44,8 @@ Source Files + + Source Files + \ No newline at end of file