Skip to content

Commit

Permalink
Treat as external the global fields of an interface block (#431), fixes
Browse files Browse the repository at this point in the history
#430

Interface blocks without an instance name introduce external global
variables.
  • Loading branch information
eldritchconundrum authored Jul 15, 2024
1 parent 0e40701 commit 9e53909
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 10 deletions.
6 changes: 4 additions & 2 deletions src/ast.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ and Expr =

and TypeSpec =
| TypeName of string
// e.g. struct foo { float x; float y; }
// struct or interface block, e.g. struct foo { float x; float y; }
| TypeBlock of string(*type*) * Ident option(*name*) * Decl list
// An interface block followed by an instance name (in a TLDecl), like structs, declares an instance.
// An interface block without an instance name (in a TypeDecl), unlike structs, introduces a set of external global variables.

and Type = {
name: TypeSpec // e.g. int
Expand Down Expand Up @@ -167,7 +169,7 @@ and TopLevel =
| TLDirective of string list
| Function of FunctionType * Stmt
| TLDecl of Decl
| TypeDecl of TypeSpec // structs
| TypeDecl of TypeSpec // structs or interface blocks
| Precision of Type

let makeType name tyQ sizes = {Type.name=name; typeQ=tyQ; arraySizes=sizes}
Expand Down
17 changes: 9 additions & 8 deletions src/renamer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,12 @@ type private RenamerImpl(options: Options.Options) =
| e -> e
mapExpr (mapEnvExpr options mapper) expr |> ignore<Expr>

let renDecl level env (ty:Type, vars) =
let renDecl level isFieldOfAnInterfaceBlockWithoutInstanceName env (ty:Type, vars) =
let aux (env: Env) (decl: Ast.DeclElt) =
Option.iter (renExpr env) decl.init
Option.iter (renExpr env) decl.size
let isExternal = level = Level.TopLevel && (ty.IsExternal || options.hlsl)
let isExternal = (level = Level.TopLevel && (ty.IsExternal || options.hlsl)) ||
isFieldOfAnInterfaceBlockWithoutInstanceName

if (level = Level.TopLevel && options.preserveAllGlobals) ||
List.contains decl.name.Name options.noRenamingList then
Expand Down Expand Up @@ -280,7 +281,7 @@ type private RenamerImpl(options: Options.Options) =
function
| Expr e -> renExpr env e; env
| Decl d ->
renDecl Level.InFunc env d
renDecl Level.InFunc false env d
| Block b ->
renList env renStmt b |> ignore<Env>
env
Expand All @@ -291,7 +292,7 @@ type private RenamerImpl(options: Options.Options) =
env
| ForD(init, cond, inc, body) as stmt ->
let newEnv = env.onEnterFunction env stmt
let newEnv = renDecl Level.InFunc newEnv init
let newEnv = renDecl Level.InFunc false newEnv init
renStmt newEnv body |> ignore<Env>
Option.iter (renExpr newEnv) cond
Option.iter (renExpr newEnv) inc
Expand Down Expand Up @@ -332,20 +333,20 @@ type private RenamerImpl(options: Options.Options) =
let renTyBlock (env: Env) = function
| TypeBlock("struct", _, _) -> env
| TypeBlock(_, _, fields) ->
// treat the fields as if they were global variables
renList env (renDecl Level.TopLevel) fields
// interface block without an instance name: the fields are treated as external global variables
renList env (renDecl Level.TopLevel true) fields
| _ -> env

let rec renTopLevelName env = function
| TLDecl d -> renDecl Level.TopLevel env d
| TLDecl d -> renDecl Level.TopLevel false env d
| TypeDecl tyDecl -> renTyBlock env tyDecl
| Function(fct, _) -> renFctName env fct
| _ -> env

let rec renTopLevelBody (env: Env) = function
| Function(fct, body) ->
let env = env.onEnterFunction env body
let env = renList env (renDecl Level.InFunc) fct.args
let env = renList env (renDecl Level.InFunc false) fct.args
renStmt env body |> ignore<Env>
| _ -> ()

Expand Down
1 change: 1 addition & 0 deletions tests/commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
# Multifile tests

--no-remove-unused --move-declarations --format c-array -o tests/unit/inout.expected tests/unit/inout.frag tests/unit/inout2.frag
--no-remove-unused --format c-array -o tests/unit/interface-block-renaming.expected tests/unit/interface-block-renaming1.frag tests/unit/interface-block-renaming2.frag

# kkp symbols tests

Expand Down
18 changes: 18 additions & 0 deletions tests/unit/interface-block-renaming.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Generated with (https://github.com/laurentlb/Shader_Minifier/)
#ifndef SHADER_MINIFIER_IMPL
#ifndef SHADER_MINIFIER_HEADER
# define SHADER_MINIFIER_HEADER
# define VAR_field "U"
#endif

#else // if SHADER_MINIFIER_IMPL

// tests/unit/interface-block-renaming1.frag
"#version 460\n"
"uniform Uniform1{vec4 U;};",

// tests/unit/interface-block-renaming2.frag
"#version 460\n"
"uniform Uniform1{vec4 U;};",

#endif
4 changes: 4 additions & 0 deletions tests/unit/interface-block-renaming1.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#version 460
// https://github.com/laurentlb/shader-minifier/issues/430
uniform Uniform1 { vec4 field; };
//uniform Uniform2 { vec4 field; } instance; // TODO
4 changes: 4 additions & 0 deletions tests/unit/interface-block-renaming2.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#version 460
// https://github.com/laurentlb/shader-minifier/issues/430
uniform Uniform1 { vec4 field; };
//uniform Uniform2 { vec4 field; } instance; // TODO

0 comments on commit 9e53909

Please sign in to comment.