[qfcc] Handle glsl version and extension directives

The version directive really does only some error checking, and
only GL_EXT_multiview and GL_GOOGLE_include_directive are supported for
extensions, but enable/disable work (but not yet warn for multiview).
This commit is contained in:
Bill Currie 2024-09-01 16:56:35 +09:00
parent cba28e9421
commit f335540e99
8 changed files with 206 additions and 9 deletions

View file

@ -58,4 +58,8 @@ void glsl_block_clear (void);
void glsl_declare_block (struct specifier_s spec, struct symbol_s *block_sym, void glsl_declare_block (struct specifier_s spec, struct symbol_s *block_sym,
struct symbol_s *instance_name); struct symbol_s *instance_name);
bool glsl_on_include (const char *name);
void glsl_include (int behavior, void *scanner);
void glsl_multiview (int behavior, void *scanner);
#endif//__glsl_lang_h #endif//__glsl_lang_h

View file

@ -28,6 +28,8 @@
#ifndef __rua_lang_h #ifndef __rua_lang_h
#define __rua_lang_h #define __rua_lang_h
#include <stdio.h>
#include "QF/dstring.h" #include "QF/dstring.h"
#include "specifier.h" #include "specifier.h"
@ -189,11 +191,17 @@ const char *rua_directive_get_key (const void *dir, void *unused) __attribute__(
const char *rua_keyword_get_key (const void *dir, void *unused) __attribute__((pure)); const char *rua_keyword_get_key (const void *dir, void *unused) __attribute__((pure));
typedef struct language_s { typedef struct language_s {
bool initialized;
void (*init) (void); void (*init) (void);
int (*parse) (FILE *in); int (*parse) (FILE *in);
int (*finish) (const char *file); int (*finish) (const char *file);
void (*extension) (const char *name, const char *value, void *scanner);
void (*version) (int version, const char *profile);
bool (*on_include) (const char *name);
} language_t; } language_t;
extern language_t current_language;
extern language_t lang_ruamoko; extern language_t lang_ruamoko;
extern language_t lang_pascal; extern language_t lang_pascal;

View file

@ -28,7 +28,9 @@
# include "config.h" # include "config.h"
#endif #endif
#include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/glsl-lang.h" #include "tools/qfcc/include/glsl-lang.h"
#include "tools/qfcc/include/rua-lang.h"
#define SRC_LINE_EXP2(l,f) "#line " #l " " #f "\n" #define SRC_LINE_EXP2(l,f) "#line " #l " " #f "\n"
#define SRC_LINE_EXP(l,f) SRC_LINE_EXP2(l,f) #define SRC_LINE_EXP(l,f) SRC_LINE_EXP2(l,f)
@ -41,6 +43,9 @@ SRC_LINE
"in int gl_DrawID;" "\n" "in int gl_DrawID;" "\n"
"in int gl_BaseVertex;" "\n" "in int gl_BaseVertex;" "\n"
"in int gl_BaseInstance;" "\n" "in int gl_BaseInstance;" "\n"
"#ifdef GL_EXT_multiview" "\n"
"highp int gl_ViewIndex;" "\n"
"#endif" "\n"
"out gl_PerVertex {" "\n" "out gl_PerVertex {" "\n"
" vec4 gl_Position;" "\n" " vec4 gl_Position;" "\n"
" float gl_PointSize;" "\n" " float gl_PointSize;" "\n"
@ -60,6 +65,9 @@ SRC_LINE
"in int gl_PatchVerticesIn;" "\n" "in int gl_PatchVerticesIn;" "\n"
"in int gl_PrimitiveID;" "\n" "in int gl_PrimitiveID;" "\n"
"in int gl_InvocationID;" "\n" "in int gl_InvocationID;" "\n"
"#ifdef GL_EXT_multiview" "\n"
"highp int gl_ViewIndex;" "\n"
"#endif" "\n"
"out gl_PerVertex {" "\n" "out gl_PerVertex {" "\n"
" vec4 gl_Position;" "\n" " vec4 gl_Position;" "\n"
" float gl_PointSize;" "\n" " float gl_PointSize;" "\n"
@ -82,6 +90,9 @@ SRC_LINE
"in vec3 gl_TessCoord;" "\n" "in vec3 gl_TessCoord;" "\n"
"patch in float gl_TessLevelOuter[4];" "\n" "patch in float gl_TessLevelOuter[4];" "\n"
"patch in float gl_TessLevelInner[2];" "\n" "patch in float gl_TessLevelInner[2];" "\n"
"#ifdef GL_EXT_multiview" "\n"
"highp int gl_ViewIndex;" "\n"
"#endif" "\n"
"out gl_PerVertex {" "\n" "out gl_PerVertex {" "\n"
" vec4 gl_Position;" "\n" " vec4 gl_Position;" "\n"
" float gl_PointSize;" "\n" " float gl_PointSize;" "\n"
@ -99,6 +110,9 @@ SRC_LINE
"} gl_in[];" "\n" "} gl_in[];" "\n"
"in int gl_PrimitiveIDIn;" "\n" "in int gl_PrimitiveIDIn;" "\n"
"in int gl_InvocationID;" "\n" "in int gl_InvocationID;" "\n"
"#ifdef GL_EXT_multiview" "\n"
"highp int gl_ViewIndex;" "\n"
"#endif" "\n"
"out gl_PerVertex {" "\n" "out gl_PerVertex {" "\n"
" vec4 gl_Position;" "\n" " vec4 gl_Position;" "\n"
" float gl_PointSize;" "\n" " float gl_PointSize;" "\n"
@ -123,6 +137,9 @@ SRC_LINE
"in int gl_Layer;" "\n" "in int gl_Layer;" "\n"
"in int gl_ViewportIndex;" "\n" "in int gl_ViewportIndex;" "\n"
"in bool gl_HelperInvocation;" "\n" "in bool gl_HelperInvocation;" "\n"
"#ifdef GL_EXT_multiview" "\n"
"highp int gl_ViewIndex;" "\n"
"#endif" "\n"
"out float gl_FragDepth;" "\n" "out float gl_FragDepth;" "\n"
"out int gl_SampleMask[];" "\n"; "out int gl_SampleMask[];" "\n";
@ -817,6 +834,37 @@ bool allInvocations(bool value)
bool allInvocationsEqual(bool value) bool allInvocationsEqual(bool value)
#endif #endif
void
glsl_multiview (int behavior, void *scanner)
{
if (behavior) {
rua_parse_define ("GL_EXT_multiview 1\n");
} else {
rua_undefine ("GL_EXT_multiview", scanner);
}
}
static int glsl_include_state = 0;
bool
glsl_on_include (const char *name)
{
if (!glsl_include_state) {
error (0, "'#include' : required extension not requested");
return false;
}
if (glsl_include_state > 1) {
warning (0, "'#include' : required extension not requested");
}
return true;
}
void
glsl_include (int behavior, void *scanner)
{
glsl_include_state = behavior;
}
static void static void
glsl_parse_vars (const char *var_src) glsl_parse_vars (const char *var_src)
{ {
@ -826,6 +874,7 @@ glsl_parse_vars (const char *var_src)
static void static void
glsl_init_common (void) glsl_init_common (void)
{ {
current_language.initialized = true;
glsl_block_clear (); glsl_block_clear ();
glsl_parse_vars (glsl_system_constants); glsl_parse_vars (glsl_system_constants);
} }

View file

@ -1492,32 +1492,143 @@ glsl_parse_string (const char *str)
return ret; return ret;
} }
static const char *glsl_behaviors[] = {
"disable",
"enable",
"require",
"warn",
};
#define num_behaviors (sizeof (glsl_behaviors) / sizeof (glsl_behaviors[0]))
typedef struct {
const char *name;
void (*set_behavior) (int behavior, void *scanner);
} glsl_ext_t;
static glsl_ext_t glsl_extensions[] = {
{"GL_EXT_multiview", glsl_multiview },
{"GL_GOOGLE_include_directive", glsl_include },
};
#define num_extensions (sizeof (glsl_extensions) / sizeof (glsl_extensions[0]))
static int
extension_cmp (const void *_a, const void *_b)
{
auto a = (const glsl_ext_t *) _a;
auto b = (const glsl_ext_t *) _b;
return strcmp (a->name, b->name);
}
static int
behavior_cmp (const void *_a, const void *_b)
{
auto a = (const char **) _a;
auto b = (const char **) _b;
return strcmp (*a, *b);
}
static void
glsl_extension (const char *name, const char *value, void *scanner)
{
if (current_language.initialized) {
error (0, "extensions directives must occur before any "
"non-preprocessor tokens");
return;
}
const char **res;
res = bsearch (&value, glsl_behaviors, num_behaviors, sizeof (char *),
behavior_cmp);
if (!res) {
error (0, "invalid behavior: %s", value);
return;
}
int behavior = res - glsl_behaviors;
if (strcmp (name, "all") == 0) {
if (behavior != 0 && behavior != 3) {
error (0, "behavior must be 'warn' or 'disable' for 'all'");
return;
}
for (size_t i = 0; i < num_extensions; i++) {
glsl_extensions[i].set_behavior (behavior, scanner);
}
} else {
glsl_ext_t key = { .name = name };
glsl_ext_t *ext;
ext = bsearch (&key, glsl_extensions, num_extensions,
sizeof (glsl_ext_t), extension_cmp);
if (ext) {
ext->set_behavior (behavior, scanner);
} else {
if (behavior == 2) {
error (0, "unknown extension '%s'", name);
} else {
warning (0, "unknown extension '%s'", name);
}
}
}
}
static void
glsl_version (int version, const char *profile)
{
if (!profile || strcmp (profile, "core") == 0) {
// ok
} else if (strcmp (profile, "es") == 0
|| strcmp (profile, "compatibility") == 0) {
error (0, "profile '%s' not supported", profile);
} else {
error (0, "bad profile name '%s': use es, core or compatibility",
profile);
}
if (version != 450 && version != 460) {
error (0, "version not supported");
}
}
language_t lang_glsl_comp = { language_t lang_glsl_comp = {
.init = glsl_init_comp, .init = glsl_init_comp,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };
language_t lang_glsl_vert = { language_t lang_glsl_vert = {
.init = glsl_init_vert, .init = glsl_init_vert,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };
language_t lang_glsl_tesc = { language_t lang_glsl_tesc = {
.init = glsl_init_tesc, .init = glsl_init_tesc,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };
language_t lang_glsl_tese = { language_t lang_glsl_tese = {
.init = glsl_init_tese, .init = glsl_init_tese,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };
language_t lang_glsl_geom = { language_t lang_glsl_geom = {
.init = glsl_init_geom, .init = glsl_init_geom,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };
language_t lang_glsl_frag = { language_t lang_glsl_frag = {
.init = glsl_init_frag, .init = glsl_init_frag,
.parse = glsl_yyparse, .parse = glsl_yyparse,
.extension = glsl_extension,
.version = glsl_version,
.on_include = glsl_on_include,
}; };

View file

@ -138,7 +138,7 @@ parse_error (void *scanner)
%token CONCAT ARGS %token CONCAT ARGS
%token EXTENSION VERSION %token EXTENSION VERSION
%type <t.text> string %type <t.text> string opt_profile
%type <macro> params opt_params body arg arg_list arg_clist %type <macro> params opt_params body arg arg_list arg_clist
%type <dstr> text text_text %type <dstr> text text_text
%type <expr> unary_expr expr id defined defined_id line_expr %type <expr> unary_expr expr id defined defined_id line_expr
@ -247,12 +247,29 @@ directive
extra_warn extra_warn
| ENDIF { rua_endif (scanner); } | ENDIF { rua_endif (scanner); }
extra_warn extra_warn
| EXTENSION ID ':' ID eod | EXTENSION ID ':' ID
| VERSION VALUE opt_profile eod {
if (current_language.extension) {
current_language.extension ($2, $4, scanner);
} else {
internal_error (0, "invalid directive");
}
}
extra_warn
| VERSION VALUE opt_profile
{
if (current_language.version) {
auto version = get_long ($2, $<t.text>2, 460);
current_language.version (expr_long (version), $3);
} else {
internal_error (0, "invalid directive");
}
}
extra_warn
; ;
opt_profile opt_profile
: /* empty */ : /* empty */ { $$ = nullptr; }
| ID | ID
; ;

View file

@ -427,8 +427,6 @@ directive (const char *token, yyscan_t scanner)
extra->preprocessor = false; extra->preprocessor = false;
return -1; return -1;
} }
//auto lex = qc_yyget_extra (scanner);
//lex->current_lang = &lex->pre_lang;
return directive->value; return directive->value;
} }
@ -1167,6 +1165,9 @@ qc_process (rua_extra_t *extra, int token, rua_tok_t *tok, yyscan_t scanner)
} }
return token ? YYPUSH_MORE : 0; return token ? YYPUSH_MORE : 0;
} }
if (!current_language.initialized && current_language.init) {
current_language.init ();
}
QC_YYSTYPE lval = {}; QC_YYSTYPE lval = {};
token = qc_token (extra, &lval, tok, scanner); token = qc_token (extra, &lval, tok, scanner);
if (token >= 0) { if (token >= 0) {
@ -2141,6 +2142,11 @@ rua_include_file (const char *name, void *scanner)
if (extra->suppressed) { if (extra->suppressed) {
return; return;
} }
if (current_language.on_include) {
if (!current_language.on_include (name)) {
return;
}
}
struct yyguts_t * yyg = (struct yyguts_t*)scanner;//FIXME struct yyguts_t * yyg = (struct yyguts_t*)scanner;//FIXME
int quote = *name; int quote = *name;
name = make_string (name, 0); name = make_string (name, 0);

View file

@ -385,14 +385,14 @@ compile_to_obj (const char *file, const char *obj, language_t *lang)
return !options.preprocess_only; return !options.preprocess_only;
} }
current_language = *lang;
InitData (); InitData ();
chain_initial_types (); chain_initial_types ();
begin_compilation (); begin_compilation ();
pr.comp_dir = save_cwd (); pr.comp_dir = save_cwd ();
add_source_file (file); add_source_file (file);
if (lang->init) { lang->initialized = false;
lang->init ();
}
err = lang->parse (yyin) || pr.error_count; err = lang->parse (yyin) || pr.error_count;
fclose (yyin); fclose (yyin);
if (cpp_name && !options.save_temps) { if (cpp_name && !options.save_temps) {
@ -672,6 +672,7 @@ compile_file (const char *filename)
FILE *yyin; FILE *yyin;
int (*yyparse) (FILE *in) = lang_ruamoko.parse; int (*yyparse) (FILE *in) = lang_ruamoko.parse;
current_language = lang_ruamoko;
yyin = preprocess_file (filename, 0); yyin = preprocess_file (filename, 0);
if (options.preprocess_only || !yyin) if (options.preprocess_only || !yyin)
return !options.preprocess_only; return !options.preprocess_only;

View file

@ -40,6 +40,7 @@
#include "tools/qfcc/include/symtab.h" #include "tools/qfcc/include/symtab.h"
#include "tools/qfcc/include/type.h" #include "tools/qfcc/include/type.h"
language_t current_language;
function_t *current_func; function_t *current_func;
class_type_t *current_class; class_type_t *current_class;
expr_t *local_expr; expr_t *local_expr;