rlsl 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/README.md +2 -0
- data/lib/rlsl/base_translator/call_parser.rb +68 -0
- data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
- data/lib/rlsl/base_translator/code_scanner.rb +102 -0
- data/lib/rlsl/base_translator.rb +159 -63
- data/lib/rlsl/code_generator/math_prelude.rb +79 -0
- data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +97 -0
- data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
- data/lib/rlsl/code_generator/template_context.rb +41 -0
- data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
- data/lib/rlsl/code_generator.rb +26 -201
- data/lib/rlsl/compiled_shader.rb +4 -12
- data/lib/rlsl/function_context.rb +31 -14
- data/lib/rlsl/glsl/translator.rb +19 -38
- data/lib/rlsl/msl/shader.rb +8 -38
- data/lib/rlsl/msl/translator.rb +19 -36
- data/lib/rlsl/msl/uniform_buffer_packer.rb +68 -0
- data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +96 -0
- data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +79 -0
- data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +168 -0
- data/lib/rlsl/prism/ast_visitor/scope_context.rb +44 -0
- data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
- data/lib/rlsl/prism/ast_visitor.rb +54 -298
- data/lib/rlsl/prism/builtins/function_registry.rb +114 -0
- data/lib/rlsl/prism/builtins/operator_rules.rb +99 -0
- data/lib/rlsl/prism/builtins/swizzle_rules.rb +38 -0
- data/lib/rlsl/prism/builtins.rb +31 -148
- data/lib/rlsl/prism/compilation_unit.rb +7 -0
- data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +83 -0
- data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +104 -0
- data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +92 -0
- data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +89 -0
- data/lib/rlsl/prism/emitters/base_emitter.rb +68 -423
- data/lib/rlsl/prism/emitters/c_emitter.rb +78 -121
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +30 -65
- data/lib/rlsl/prism/emitters/msl_emitter.rb +35 -62
- data/lib/rlsl/prism/emitters/target_emitter.rb +77 -0
- data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +65 -61
- data/lib/rlsl/prism/ir/control_flow.rb +83 -0
- data/lib/rlsl/prism/ir/definitions.rb +67 -0
- data/lib/rlsl/prism/ir/expressions.rb +197 -0
- data/lib/rlsl/prism/ir/node.rb +21 -0
- data/lib/rlsl/prism/ir/nodes.rb +4 -371
- data/lib/rlsl/prism/ir/traversal.rb +62 -0
- data/lib/rlsl/prism/source_extractor/block_locator.rb +52 -0
- data/lib/rlsl/prism/source_extractor.rb +14 -133
- data/lib/rlsl/prism/source_unit/parser.rb +78 -0
- data/lib/rlsl/prism/source_unit.rb +42 -0
- data/lib/rlsl/prism/target_capability_validator.rb +85 -0
- data/lib/rlsl/prism/transpiler.rb +63 -60
- data/lib/rlsl/prism/type_inference/call_type_resolver.rb +35 -0
- data/lib/rlsl/prism/type_inference/call_validator.rb +71 -0
- data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +80 -0
- data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +66 -0
- data/lib/rlsl/prism/type_inference/definition_inferer.rb +41 -0
- data/lib/rlsl/prism/type_inference/expression_inferer.rb +92 -0
- data/lib/rlsl/prism/type_inference/field_type_resolver.rb +17 -0
- data/lib/rlsl/prism/type_inference/inferer_registry.rb +38 -0
- data/lib/rlsl/prism/type_inference/scope_stack.rb +47 -0
- data/lib/rlsl/prism/type_inference/type_environment.rb +112 -0
- data/lib/rlsl/prism/type_inference/type_shapes.rb +33 -0
- data/lib/rlsl/prism/type_inference.rb +114 -248
- data/lib/rlsl/runtime_shader.rb +47 -0
- data/lib/rlsl/shader_builder/build_service.rb +77 -0
- data/lib/rlsl/shader_builder/native_extension_compiler.rb +71 -0
- data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
- data/lib/rlsl/shader_builder/source_resolver.rb +91 -0
- data/lib/rlsl/shader_builder.rb +22 -113
- data/lib/rlsl/types/catalog.rb +47 -0
- data/lib/rlsl/types/target_resolver.rb +15 -0
- data/lib/rlsl/types/type_spec.rb +167 -0
- data/lib/rlsl/types/value_normalizer.rb +81 -0
- data/lib/rlsl/types.rb +11 -29
- data/lib/rlsl/uniform_context.rb +6 -12
- data/lib/rlsl/version.rb +1 -1
- data/lib/rlsl/wgsl/translator.rb +23 -39
- data/lib/rlsl.rb +14 -12
- metadata +55 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
class ShaderBuilder
|
|
5
|
+
class SourceResolver
|
|
6
|
+
def initialize(definition, transpiler_class: Prism::Transpiler)
|
|
7
|
+
@definition = definition
|
|
8
|
+
@transpiler_class = transpiler_class
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def sources_for(target)
|
|
12
|
+
[helpers_code(target), fragment_code(target)]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def translation_sources_for(target)
|
|
16
|
+
[helpers_source(target), fragment_source(target)]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def helpers_code(target)
|
|
20
|
+
helpers_source(target).code
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def fragment_code(target)
|
|
24
|
+
fragment_source(target).code
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def helpers_source(target)
|
|
30
|
+
return source_snippet("") unless @definition.helpers_block
|
|
31
|
+
return source_snippet(@definition.helpers_block.call) unless ruby_helpers?
|
|
32
|
+
|
|
33
|
+
source_snippet(
|
|
34
|
+
helpers_transpiler.transpile_helpers(@definition.helpers_block, target, @definition.custom_functions),
|
|
35
|
+
format: :target
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def fragment_source(target)
|
|
40
|
+
return source_snippet("") unless @definition.fragment_block
|
|
41
|
+
return source_snippet(@definition.fragment_block.call) unless ruby_fragment?
|
|
42
|
+
|
|
43
|
+
source_snippet(fragment_transpiler.transpile(@definition.fragment_block, target), format: :target)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def source_snippet(code, format: :legacy)
|
|
47
|
+
BaseTranslator::SourceSnippet.new(code: code.to_s, format: format)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def helpers_transpiler
|
|
51
|
+
@helpers_transpiler ||= build_transpiler
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def fragment_transpiler
|
|
55
|
+
@fragment_transpiler ||= build_transpiler(globals: helper_globals)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def build_transpiler(globals: {})
|
|
59
|
+
@transpiler_class.new(@definition.uniforms, @definition.custom_functions, globals: globals)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def helper_globals
|
|
63
|
+
return {} unless ruby_helpers? && @definition.helpers_block
|
|
64
|
+
|
|
65
|
+
@helper_globals ||= begin
|
|
66
|
+
compilation = helpers_transpiler.compile_helpers(@definition.helpers_block, @definition.custom_functions)
|
|
67
|
+
extract_global_types(compilation.ir)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def extract_global_types(ir)
|
|
72
|
+
return {} unless ir.is_a?(Prism::IR::Block)
|
|
73
|
+
|
|
74
|
+
ir.statements.each_with_object({}) do |statement, globals|
|
|
75
|
+
next unless statement.is_a?(Prism::IR::GlobalDecl)
|
|
76
|
+
next unless statement.type
|
|
77
|
+
|
|
78
|
+
globals[statement.name] = statement.type
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def ruby_helpers?
|
|
83
|
+
@definition.ruby_helpers?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def ruby_fragment?
|
|
87
|
+
@definition.ruby_fragment?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/rlsl/shader_builder.rb
CHANGED
|
@@ -1,165 +1,74 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
require_relative "shader_builder/shader_definition"
|
|
4
|
+
require_relative "shader_builder/build_service"
|
|
5
|
+
require_relative "shader_builder/source_resolver"
|
|
6
|
+
require_relative "shader_builder/native_extension_compiler"
|
|
6
7
|
|
|
7
8
|
module RLSL
|
|
8
9
|
class ShaderBuilder
|
|
9
10
|
attr_reader :name
|
|
10
11
|
|
|
11
|
-
def initialize(name)
|
|
12
|
+
def initialize(name, definition = ShaderDefinition.new)
|
|
12
13
|
@name = name.to_s
|
|
13
|
-
@
|
|
14
|
-
@fragment_mode = :c
|
|
15
|
-
@helpers_mode = :c
|
|
16
|
-
@custom_functions = {}
|
|
14
|
+
@definition = definition
|
|
17
15
|
end
|
|
18
16
|
|
|
19
17
|
def uniforms(&block)
|
|
20
18
|
if block_given?
|
|
21
19
|
ctx = UniformContext.new
|
|
22
20
|
ctx.instance_eval(&block)
|
|
23
|
-
@
|
|
21
|
+
@definition = @definition.with_uniforms(ctx.uniforms)
|
|
24
22
|
else
|
|
25
|
-
@uniforms
|
|
23
|
+
@definition.uniforms
|
|
26
24
|
end
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
def helpers(mode = :ruby, &block)
|
|
30
|
-
@
|
|
31
|
-
@helpers_mode = mode
|
|
28
|
+
@definition = @definition.with_helpers(mode: mode, block: block)
|
|
32
29
|
end
|
|
33
30
|
|
|
34
31
|
def functions(&block)
|
|
35
32
|
ctx = FunctionContext.new
|
|
36
33
|
ctx.instance_eval(&block)
|
|
37
|
-
@
|
|
34
|
+
@definition = @definition.with_custom_functions(ctx.functions)
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
def fragment(&block)
|
|
41
|
-
@
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def ruby_mode?
|
|
46
|
-
@fragment_mode == :ruby
|
|
38
|
+
@definition = @definition.with_fragment(
|
|
39
|
+
mode: block.arity > 0 ? :ruby : :c,
|
|
40
|
+
block: block
|
|
41
|
+
)
|
|
47
42
|
end
|
|
48
43
|
|
|
49
44
|
def compile_and_load
|
|
50
|
-
|
|
51
|
-
code_hash = Digest::MD5.hexdigest(c_code)[0..7]
|
|
52
|
-
ext_name = "#{@name}_#{code_hash}"
|
|
53
|
-
ext_dir = File.join(RLSL.cache_dir, ext_name)
|
|
54
|
-
ext_file = File.join(ext_dir, "#{@name}.#{RbConfig::CONFIG['DLEXT']}")
|
|
55
|
-
|
|
56
|
-
unless File.exist?(ext_file)
|
|
57
|
-
compile_extension(@name, ext_dir, c_code)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
require ext_file
|
|
61
|
-
CompiledShader.new(@name, ext_name, @uniforms.keys)
|
|
45
|
+
build_service.compile_and_load
|
|
62
46
|
end
|
|
63
47
|
|
|
64
48
|
def build_metal_shader
|
|
65
|
-
|
|
66
|
-
fragment_code = transpile_fragment(:msl)
|
|
67
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
68
|
-
else
|
|
69
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
70
|
-
fragment_code = @fragment_block ? @fragment_block.call : ""
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
translator = MSL::Translator.new(@uniforms, helpers_code, fragment_code)
|
|
74
|
-
msl_source = translator.translate
|
|
75
|
-
|
|
76
|
-
MSL::Shader.new(@name, @uniforms, msl_source)
|
|
49
|
+
build_service.build_metal_shader
|
|
77
50
|
end
|
|
78
51
|
|
|
79
52
|
def build_wgsl_shader
|
|
80
|
-
|
|
81
|
-
fragment_code = transpile_fragment(:wgsl)
|
|
82
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
83
|
-
else
|
|
84
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
85
|
-
fragment_code = @fragment_block ? @fragment_block.call : ""
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
translator = WGSL::Translator.new(@uniforms, helpers_code, fragment_code)
|
|
89
|
-
translator.translate
|
|
53
|
+
build_service.build_wgsl_shader
|
|
90
54
|
end
|
|
91
55
|
|
|
92
56
|
def build_glsl_shader(version: "450")
|
|
93
|
-
|
|
94
|
-
fragment_code = transpile_fragment(:glsl)
|
|
95
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
96
|
-
else
|
|
97
|
-
helpers_code = @helpers_block ? @helpers_block.call : ""
|
|
98
|
-
fragment_code = @fragment_block ? @fragment_block.call : ""
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
translator = GLSL::Translator.new(@uniforms, helpers_code, fragment_code, version: version)
|
|
102
|
-
translator.translate
|
|
57
|
+
build_service.build_glsl_shader(version: version)
|
|
103
58
|
end
|
|
104
59
|
|
|
105
60
|
def transpile_fragment(target)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
transpiler = Prism::Transpiler.new(@uniforms, @custom_functions)
|
|
109
|
-
transpiler.transpile(@fragment_block, target)
|
|
61
|
+
build_service.transpile_fragment(target)
|
|
110
62
|
end
|
|
111
63
|
|
|
112
64
|
def transpile_helpers(target)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
transpiler = Prism::Transpiler.new(@uniforms, @custom_functions)
|
|
116
|
-
transpiler.transpile_helpers(@helpers_block, target, @custom_functions)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def helpers_ruby_mode?
|
|
120
|
-
@helpers_mode == :ruby
|
|
65
|
+
build_service.transpile_helpers(target)
|
|
121
66
|
end
|
|
122
67
|
|
|
123
68
|
private
|
|
124
69
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
helpers_code = transpile_helpers(:c)
|
|
128
|
-
helpers_block = -> { helpers_code }
|
|
129
|
-
else
|
|
130
|
-
helpers_block = @helpers_block
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
if ruby_mode?
|
|
134
|
-
fragment_code = transpile_fragment(:c)
|
|
135
|
-
fragment_block = -> { fragment_code }
|
|
136
|
-
else
|
|
137
|
-
fragment_block = @fragment_block
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
codegen = CodeGenerator.new(@name, @uniforms, helpers_block, fragment_block)
|
|
141
|
-
codegen.generate
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def compile_extension(ext_name, ext_dir, c_code)
|
|
145
|
-
FileUtils.mkdir_p(ext_dir)
|
|
146
|
-
|
|
147
|
-
File.write(File.join(ext_dir, "#{ext_name}.c"), c_code)
|
|
148
|
-
|
|
149
|
-
extconf = <<~RUBY
|
|
150
|
-
require "mkmf"
|
|
151
|
-
$CFLAGS << " -O3 -ffast-math"
|
|
152
|
-
if RUBY_PLATFORM =~ /darwin/
|
|
153
|
-
$CFLAGS << " -fblocks"
|
|
154
|
-
end
|
|
155
|
-
create_makefile("#{ext_name}")
|
|
156
|
-
RUBY
|
|
157
|
-
File.write(File.join(ext_dir, "extconf.rb"), extconf)
|
|
158
|
-
|
|
159
|
-
Dir.chdir(ext_dir) do
|
|
160
|
-
system("#{RbConfig.ruby} extconf.rb > /dev/null 2>&1") or raise "extconf failed for #{ext_name}"
|
|
161
|
-
system("/usr/bin/make > /dev/null 2>&1") or raise "make failed for #{ext_name}"
|
|
162
|
-
end
|
|
70
|
+
def build_service
|
|
71
|
+
BuildService.new(@name, @definition)
|
|
163
72
|
end
|
|
164
73
|
end
|
|
165
74
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module UniformTypes
|
|
5
|
+
module Catalog
|
|
6
|
+
def supported?(type)
|
|
7
|
+
UNIFORM_TYPE_SPECS.key?(type.to_sym)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fetch(type)
|
|
11
|
+
UNIFORM_TYPE_SPECS.fetch(type) do
|
|
12
|
+
raise ArgumentError, "Unsupported uniform type: #{type.inspect}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def c_type(type)
|
|
17
|
+
fetch(type).c_type
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def compiled_types
|
|
21
|
+
@compiled_types ||= UNIFORM_TYPE_SPECS.select { |_type, spec| spec.compiled? }.keys.freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def compiled_spec(type)
|
|
25
|
+
spec = fetch(type)
|
|
26
|
+
return spec if spec.compiled?
|
|
27
|
+
|
|
28
|
+
raise ArgumentError, "Unsupported compiled uniform type: #{type}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def metal_spec(type)
|
|
32
|
+
spec = fetch(type)
|
|
33
|
+
return spec if spec.metal_packable?
|
|
34
|
+
|
|
35
|
+
raise ArgumentError, "Unsupported Metal uniform type: #{type}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def runtime_types
|
|
39
|
+
@runtime_types ||= UNIFORM_TYPE_SPECS.select { |_type, spec| spec.runtime_supported? }.keys.freeze
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def function_shorthand_types
|
|
43
|
+
@function_shorthand_types ||= UNIFORM_TYPE_SPECS.select { |_type, spec| spec.function_shorthand? }.keys.freeze
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module UniformTypes
|
|
5
|
+
module TargetResolver
|
|
6
|
+
def target_type(type, target)
|
|
7
|
+
spec = fetch(type)
|
|
8
|
+
target_type = spec.public_send(:"#{target}_type")
|
|
9
|
+
return target_type if target_type
|
|
10
|
+
|
|
11
|
+
raise ArgumentError, "Unsupported #{target.to_s.upcase} uniform type: #{type}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
UniformTypeSpec = Struct.new(
|
|
5
|
+
:c_type,
|
|
6
|
+
:glsl_type,
|
|
7
|
+
:wgsl_type,
|
|
8
|
+
:msl_type,
|
|
9
|
+
:wrapper_kind,
|
|
10
|
+
:vector_size,
|
|
11
|
+
:metal_alignment,
|
|
12
|
+
:metal_size,
|
|
13
|
+
:compiled_supported,
|
|
14
|
+
:runtime_supported,
|
|
15
|
+
:function_shorthand,
|
|
16
|
+
keyword_init: true
|
|
17
|
+
) do
|
|
18
|
+
def compiled?
|
|
19
|
+
compiled_supported
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def metal_packable?
|
|
23
|
+
!metal_alignment.nil? && !metal_size.nil?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def runtime_supported?
|
|
27
|
+
runtime_supported
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def function_shorthand?
|
|
31
|
+
function_shorthand
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def target_supported?(target)
|
|
35
|
+
!public_send(:"#{target}_type").nil?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
C_TYPES = <<~C
|
|
40
|
+
typedef struct { float x, y; } vec2;
|
|
41
|
+
typedef struct { float x, y, z; } vec3;
|
|
42
|
+
typedef struct { float x, y, z, w; } vec4;
|
|
43
|
+
typedef struct { float m[4]; } mat2;
|
|
44
|
+
typedef struct { float m[9]; } mat3;
|
|
45
|
+
typedef struct { float m[16]; } mat4;
|
|
46
|
+
typedef struct { void* data; int width; int height; } sampler2D;
|
|
47
|
+
|
|
48
|
+
#define PI 3.14159265f
|
|
49
|
+
#define TAU 6.28318530f
|
|
50
|
+
C
|
|
51
|
+
|
|
52
|
+
UNIFORM_TYPE_SPECS = {
|
|
53
|
+
float: UniformTypeSpec.new(
|
|
54
|
+
c_type: "float",
|
|
55
|
+
glsl_type: "float",
|
|
56
|
+
wgsl_type: "f32",
|
|
57
|
+
msl_type: "float",
|
|
58
|
+
wrapper_kind: :float,
|
|
59
|
+
metal_alignment: 4,
|
|
60
|
+
metal_size: 4,
|
|
61
|
+
compiled_supported: true,
|
|
62
|
+
runtime_supported: true,
|
|
63
|
+
function_shorthand: true
|
|
64
|
+
),
|
|
65
|
+
vec2: UniformTypeSpec.new(
|
|
66
|
+
c_type: "vec2",
|
|
67
|
+
glsl_type: "vec2",
|
|
68
|
+
wgsl_type: "vec2<f32>",
|
|
69
|
+
msl_type: "float2",
|
|
70
|
+
wrapper_kind: :vector,
|
|
71
|
+
vector_size: 2,
|
|
72
|
+
metal_alignment: 8,
|
|
73
|
+
metal_size: 8,
|
|
74
|
+
compiled_supported: true,
|
|
75
|
+
runtime_supported: true,
|
|
76
|
+
function_shorthand: true
|
|
77
|
+
),
|
|
78
|
+
vec3: UniformTypeSpec.new(
|
|
79
|
+
c_type: "vec3",
|
|
80
|
+
glsl_type: "vec3",
|
|
81
|
+
wgsl_type: "vec3<f32>",
|
|
82
|
+
msl_type: "float3",
|
|
83
|
+
wrapper_kind: :vector,
|
|
84
|
+
vector_size: 3,
|
|
85
|
+
metal_alignment: 16,
|
|
86
|
+
metal_size: 16,
|
|
87
|
+
compiled_supported: true,
|
|
88
|
+
runtime_supported: true,
|
|
89
|
+
function_shorthand: true
|
|
90
|
+
),
|
|
91
|
+
vec4: UniformTypeSpec.new(
|
|
92
|
+
c_type: "vec4",
|
|
93
|
+
glsl_type: "vec4",
|
|
94
|
+
wgsl_type: "vec4<f32>",
|
|
95
|
+
msl_type: "float4",
|
|
96
|
+
wrapper_kind: :vector,
|
|
97
|
+
vector_size: 4,
|
|
98
|
+
metal_alignment: 16,
|
|
99
|
+
metal_size: 16,
|
|
100
|
+
compiled_supported: true,
|
|
101
|
+
runtime_supported: true,
|
|
102
|
+
function_shorthand: true
|
|
103
|
+
),
|
|
104
|
+
int: UniformTypeSpec.new(
|
|
105
|
+
c_type: "int",
|
|
106
|
+
glsl_type: "int",
|
|
107
|
+
wgsl_type: "i32",
|
|
108
|
+
msl_type: "int",
|
|
109
|
+
wrapper_kind: :int,
|
|
110
|
+
metal_alignment: 4,
|
|
111
|
+
metal_size: 4,
|
|
112
|
+
compiled_supported: true,
|
|
113
|
+
runtime_supported: true,
|
|
114
|
+
function_shorthand: true
|
|
115
|
+
),
|
|
116
|
+
bool: UniformTypeSpec.new(
|
|
117
|
+
c_type: "int",
|
|
118
|
+
glsl_type: "bool",
|
|
119
|
+
wgsl_type: "bool",
|
|
120
|
+
msl_type: "bool",
|
|
121
|
+
wrapper_kind: :bool,
|
|
122
|
+
metal_alignment: 4,
|
|
123
|
+
metal_size: 4,
|
|
124
|
+
compiled_supported: true,
|
|
125
|
+
runtime_supported: true,
|
|
126
|
+
function_shorthand: true
|
|
127
|
+
),
|
|
128
|
+
mat2: UniformTypeSpec.new(
|
|
129
|
+
c_type: "mat2",
|
|
130
|
+
glsl_type: "mat2",
|
|
131
|
+
wgsl_type: "mat2x2<f32>",
|
|
132
|
+
msl_type: "float2x2",
|
|
133
|
+
compiled_supported: false,
|
|
134
|
+
runtime_supported: false,
|
|
135
|
+
function_shorthand: true
|
|
136
|
+
),
|
|
137
|
+
mat3: UniformTypeSpec.new(
|
|
138
|
+
c_type: "mat3",
|
|
139
|
+
glsl_type: "mat3",
|
|
140
|
+
wgsl_type: "mat3x3<f32>",
|
|
141
|
+
msl_type: "float3x3",
|
|
142
|
+
compiled_supported: false,
|
|
143
|
+
runtime_supported: false,
|
|
144
|
+
function_shorthand: true
|
|
145
|
+
),
|
|
146
|
+
mat4: UniformTypeSpec.new(
|
|
147
|
+
c_type: "mat4",
|
|
148
|
+
glsl_type: "mat4",
|
|
149
|
+
wgsl_type: "mat4x4<f32>",
|
|
150
|
+
msl_type: "float4x4",
|
|
151
|
+
compiled_supported: false,
|
|
152
|
+
runtime_supported: false,
|
|
153
|
+
function_shorthand: true
|
|
154
|
+
),
|
|
155
|
+
sampler2D: UniformTypeSpec.new(
|
|
156
|
+
c_type: "sampler2D",
|
|
157
|
+
glsl_type: "sampler2D",
|
|
158
|
+
wgsl_type: "texture_2d<f32>",
|
|
159
|
+
msl_type: nil,
|
|
160
|
+
compiled_supported: false,
|
|
161
|
+
runtime_supported: false,
|
|
162
|
+
function_shorthand: true
|
|
163
|
+
)
|
|
164
|
+
}.transform_values(&:freeze).freeze
|
|
165
|
+
|
|
166
|
+
UNIFORM_TYPES = UNIFORM_TYPE_SPECS.keys.freeze
|
|
167
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module UniformTypes
|
|
5
|
+
module ValueNormalizer
|
|
6
|
+
def normalize_values(uniform_types, uniforms, shader_name: nil)
|
|
7
|
+
uniform_types.each_with_object({}) do |(name, type), normalized|
|
|
8
|
+
unless uniforms.key?(name)
|
|
9
|
+
raise ArgumentError, missing_uniform_message(name, shader_name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
normalized[name] = normalize_value(type, uniforms[name], name: name, shader_name: shader_name)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def normalize_value(type, value, name:, shader_name: nil)
|
|
17
|
+
return value if type.nil?
|
|
18
|
+
|
|
19
|
+
spec = fetch(type)
|
|
20
|
+
raise ArgumentError, unsupported_runtime_type_message(type, shader_name) unless spec.runtime_supported?
|
|
21
|
+
|
|
22
|
+
case spec.wrapper_kind
|
|
23
|
+
when :float
|
|
24
|
+
Float(value)
|
|
25
|
+
when :int
|
|
26
|
+
Integer(value)
|
|
27
|
+
when :bool
|
|
28
|
+
normalize_bool(value, name: name, shader_name: shader_name)
|
|
29
|
+
when :vector
|
|
30
|
+
normalize_vector(value, spec.vector_size, name: name, shader_name: shader_name)
|
|
31
|
+
else
|
|
32
|
+
raise ArgumentError, unsupported_runtime_type_message(type, shader_name)
|
|
33
|
+
end
|
|
34
|
+
rescue TypeError
|
|
35
|
+
raise ArgumentError, invalid_uniform_message(name, type, value, shader_name)
|
|
36
|
+
rescue ArgumentError => e
|
|
37
|
+
raise e if e.message.start_with?("Invalid value for uniform", "Unsupported runtime uniform type")
|
|
38
|
+
|
|
39
|
+
raise ArgumentError, invalid_uniform_message(name, type, value, shader_name)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def normalize_bool(value, name:, shader_name: nil)
|
|
43
|
+
return value if value == true || value == false
|
|
44
|
+
return false if value == 0
|
|
45
|
+
return true if value == 1
|
|
46
|
+
|
|
47
|
+
raise ArgumentError, invalid_uniform_message(name, :bool, value, shader_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def normalize_vector(value, vector_size, name:, shader_name: nil)
|
|
51
|
+
unless value.is_a?(Array) && value.length == vector_size
|
|
52
|
+
raise ArgumentError, invalid_vector_message(name, vector_size, value, shader_name)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
value.map { |component| Float(component) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def missing_uniform_message(name, shader_name)
|
|
61
|
+
"Missing uniform #{name.inspect}#{shader_suffix(shader_name)}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def invalid_uniform_message(name, type, value, shader_name)
|
|
65
|
+
"Invalid value for uniform #{name.inspect}#{shader_suffix(shader_name)}: expected #{type}, got #{value.inspect}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def invalid_vector_message(name, vector_size, value, shader_name)
|
|
69
|
+
"Invalid value for uniform #{name.inspect}#{shader_suffix(shader_name)}: expected vec#{vector_size}, got #{value.inspect}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def unsupported_runtime_type_message(type, shader_name)
|
|
73
|
+
"Unsupported runtime uniform type #{type.inspect}#{shader_suffix(shader_name)}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def shader_suffix(shader_name)
|
|
77
|
+
shader_name ? " in #{shader_name}" : ""
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
data/lib/rlsl/types.rb
CHANGED
|
@@ -1,36 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
typedef struct { float x, y, z; } vec3;
|
|
8
|
-
typedef struct { float x, y, z, w; } vec4;
|
|
9
|
-
typedef struct { float m[4]; } mat2;
|
|
10
|
-
typedef struct { float m[9]; } mat3;
|
|
11
|
-
typedef struct { float m[16]; } mat4;
|
|
12
|
-
typedef struct { void* data; int width; int height; } sampler2D;
|
|
13
|
-
|
|
14
|
-
#define PI 3.14159265f
|
|
15
|
-
#define TAU 6.28318530f
|
|
16
|
-
C
|
|
3
|
+
require_relative "types/type_spec"
|
|
4
|
+
require_relative "types/catalog"
|
|
5
|
+
require_relative "types/target_resolver"
|
|
6
|
+
require_relative "types/value_normalizer"
|
|
17
7
|
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
module RLSL
|
|
9
|
+
module UniformTypes
|
|
10
|
+
extend Catalog
|
|
11
|
+
extend TargetResolver
|
|
12
|
+
extend ValueNormalizer
|
|
13
|
+
end
|
|
20
14
|
|
|
21
|
-
# Type mapping helper
|
|
22
15
|
module TypeMapping
|
|
23
|
-
C_UNIFORM_TYPES =
|
|
24
|
-
float: "float",
|
|
25
|
-
int: "int",
|
|
26
|
-
bool: "int",
|
|
27
|
-
vec2: "vec2",
|
|
28
|
-
vec3: "vec3",
|
|
29
|
-
vec4: "vec4",
|
|
30
|
-
mat2: "mat2",
|
|
31
|
-
mat3: "mat3",
|
|
32
|
-
mat4: "mat4",
|
|
33
|
-
sampler2D: "sampler2D"
|
|
34
|
-
}.freeze
|
|
16
|
+
C_UNIFORM_TYPES = UNIFORM_TYPE_SPECS.transform_values(&:c_type).freeze
|
|
35
17
|
end
|
|
36
18
|
end
|
data/lib/rlsl/uniform_context.rb
CHANGED
|
@@ -9,20 +9,14 @@ module RLSL
|
|
|
9
9
|
@uniforms = {}
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
@uniforms[name] =
|
|
12
|
+
def define_uniform(name, type)
|
|
13
|
+
@uniforms[name] = type
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def vec3(name)
|
|
21
|
-
@uniforms[name] = :vec3
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def vec4(name)
|
|
25
|
-
@uniforms[name] = :vec4
|
|
16
|
+
RLSL::UNIFORM_TYPES.each do |type|
|
|
17
|
+
define_method(type) do |name|
|
|
18
|
+
define_uniform(name, type)
|
|
19
|
+
end
|
|
26
20
|
end
|
|
27
21
|
end
|
|
28
22
|
end
|
data/lib/rlsl/version.rb
CHANGED