rlsl 0.1.1 → 1.0.1
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/.rubocop.yml +8 -0
- data/CHANGELOG.md +13 -2
- data/README.md +101 -26
- data/Rakefile +7 -0
- data/lib/rlsl/base_translator/call_parser.rb +79 -0
- data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
- data/lib/rlsl/base_translator/code_scanner.rb +140 -0
- data/lib/rlsl/base_translator.rb +182 -64
- data/lib/rlsl/code_generator/math_prelude.rb +172 -0
- data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +137 -0
- data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
- data/lib/rlsl/code_generator/template_context.rb +44 -0
- data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
- data/lib/rlsl/code_generator.rb +30 -202
- data/lib/rlsl/compiled_shader.rb +5 -13
- data/lib/rlsl/errors.rb +29 -0
- data/lib/rlsl/function_context.rb +31 -14
- data/lib/rlsl/glsl/translator.rb +35 -41
- data/lib/rlsl/msl/shader.rb +34 -46
- data/lib/rlsl/msl/translator.rb +38 -34
- data/lib/rlsl/msl/uniform_buffer_packer.rb +72 -0
- data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +137 -0
- data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +92 -0
- data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +172 -0
- data/lib/rlsl/prism/ast_visitor/scope_context.rb +48 -0
- data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
- data/lib/rlsl/prism/ast_visitor.rb +100 -286
- data/lib/rlsl/prism/builtins/function_registry.rb +131 -0
- data/lib/rlsl/prism/builtins/operator_rules.rb +123 -0
- data/lib/rlsl/prism/builtins/swizzle_rules.rb +47 -0
- data/lib/rlsl/prism/builtins.rb +39 -148
- data/lib/rlsl/prism/compilation_unit.rb +7 -0
- data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +126 -0
- data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +134 -0
- data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +108 -0
- data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +95 -0
- data/lib/rlsl/prism/emitters/base_emitter.rb +120 -414
- data/lib/rlsl/prism/emitters/c_emitter.rb +165 -112
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +63 -50
- data/lib/rlsl/prism/emitters/msl_emitter.rb +67 -52
- data/lib/rlsl/prism/emitters/target_emitter.rb +124 -0
- data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +217 -58
- data/lib/rlsl/prism/errors.rb +9 -0
- data/lib/rlsl/prism/ir/control_flow.rb +85 -0
- data/lib/rlsl/prism/ir/definitions.rb +82 -0
- data/lib/rlsl/prism/ir/expressions.rb +201 -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 +66 -0
- data/lib/rlsl/prism/mutation_analyzer.rb +30 -0
- data/lib/rlsl/prism/node_traversal.rb +41 -0
- data/lib/rlsl/prism/parameter_list.rb +46 -0
- data/lib/rlsl/prism/return_flow_validator.rb +73 -0
- data/lib/rlsl/prism/source_extractor/block_locator.rb +50 -0
- data/lib/rlsl/prism/source_extractor.rb +19 -137
- data/lib/rlsl/prism/source_unit/parser.rb +88 -0
- data/lib/rlsl/prism/source_unit.rb +42 -0
- data/lib/rlsl/prism/target_capability_validator.rb +110 -0
- data/lib/rlsl/prism/transpiler.rb +99 -59
- data/lib/rlsl/prism/type_inference/call_type_resolver.rb +59 -0
- data/lib/rlsl/prism/type_inference/call_validator.rb +75 -0
- data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +106 -0
- data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +147 -0
- data/lib/rlsl/prism/type_inference/definition_inferer.rb +56 -0
- data/lib/rlsl/prism/type_inference/expression_inferer.rb +96 -0
- data/lib/rlsl/prism/type_inference/field_type_resolver.rb +38 -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 +120 -249
- data/lib/rlsl/runtime_shader.rb +47 -0
- data/lib/rlsl/shader_builder/build_service.rb +104 -0
- data/lib/rlsl/shader_builder/native_extension_compiler.rb +97 -0
- data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
- data/lib/rlsl/shader_builder/source_resolver.rb +109 -0
- data/lib/rlsl/shader_builder.rb +60 -111
- data/lib/rlsl/shader_name.rb +18 -0
- 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 +86 -0
- data/lib/rlsl/types.rb +9 -31
- data/lib/rlsl/uniform_context.rb +22 -11
- data/lib/rlsl/version.rb +1 -1
- data/lib/rlsl/wgsl/translator.rb +46 -39
- data/lib/rlsl/wgsl/uniform_layout.rb +25 -0
- data/lib/rlsl.rb +38 -15
- metadata +76 -11
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
class ShaderBuilder
|
|
5
|
+
class ShaderDefinition
|
|
6
|
+
attr_reader :uniforms, :custom_functions, :helpers_block, :helpers_mode, :fragment_block, :fragment_mode
|
|
7
|
+
|
|
8
|
+
def initialize(
|
|
9
|
+
uniforms: {},
|
|
10
|
+
custom_functions: {},
|
|
11
|
+
helpers_block: nil,
|
|
12
|
+
helpers_mode: :ruby,
|
|
13
|
+
fragment_block: nil,
|
|
14
|
+
fragment_mode: :c
|
|
15
|
+
)
|
|
16
|
+
@uniforms = normalize_hash(uniforms)
|
|
17
|
+
@custom_functions = normalize_hash(custom_functions)
|
|
18
|
+
@helpers_block = helpers_block
|
|
19
|
+
@helpers_mode = helpers_mode
|
|
20
|
+
@fragment_block = fragment_block
|
|
21
|
+
@fragment_mode = fragment_mode
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def with_uniforms(uniforms)
|
|
25
|
+
copy(uniforms: uniforms)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def with_custom_functions(custom_functions)
|
|
29
|
+
copy(custom_functions: custom_functions)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def with_helpers(mode:, block:)
|
|
33
|
+
copy(helpers_mode: mode, helpers_block: block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def with_fragment(mode:, block:)
|
|
37
|
+
copy(fragment_mode: mode, fragment_block: block)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def ruby_fragment?
|
|
41
|
+
%i[ruby ruby_source].include?(@fragment_mode)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ruby_helpers?
|
|
45
|
+
%i[ruby ruby_source].include?(@helpers_mode)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def copy(**overrides)
|
|
51
|
+
self.class.new(
|
|
52
|
+
uniforms: overrides.fetch(:uniforms, @uniforms),
|
|
53
|
+
custom_functions: overrides.fetch(:custom_functions, @custom_functions),
|
|
54
|
+
helpers_block: overrides.fetch(:helpers_block, @helpers_block),
|
|
55
|
+
helpers_mode: overrides.fetch(:helpers_mode, @helpers_mode),
|
|
56
|
+
fragment_block: overrides.fetch(:fragment_block, @fragment_block),
|
|
57
|
+
fragment_mode: overrides.fetch(:fragment_mode, @fragment_mode)
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def normalize_hash(hash)
|
|
62
|
+
hash.each_with_object({}) do |(name, value), normalized|
|
|
63
|
+
normalized[name.to_sym] = value
|
|
64
|
+
end.freeze
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
if @definition.helpers_mode == :ruby_source
|
|
32
|
+
source = @definition.helpers_block.call
|
|
33
|
+
return source_snippet(
|
|
34
|
+
helpers_transpiler.transpile_helpers_source(source, target, @definition.custom_functions),
|
|
35
|
+
format: :target
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
return source_snippet(@definition.helpers_block.call) unless ruby_helpers?
|
|
39
|
+
|
|
40
|
+
source_snippet(
|
|
41
|
+
helpers_transpiler.transpile_helpers(@definition.helpers_block, target, @definition.custom_functions),
|
|
42
|
+
format: :target
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fragment_source(target)
|
|
47
|
+
return source_snippet("") unless @definition.fragment_block
|
|
48
|
+
if @definition.fragment_mode == :ruby_source
|
|
49
|
+
source = @definition.fragment_block.call
|
|
50
|
+
return source_snippet(fragment_transpiler.transpile_source(source, target), format: :target)
|
|
51
|
+
end
|
|
52
|
+
return source_snippet(@definition.fragment_block.call) unless ruby_fragment?
|
|
53
|
+
|
|
54
|
+
source_snippet(fragment_transpiler.transpile(@definition.fragment_block, target), format: :target)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def source_snippet(code, format: :legacy)
|
|
58
|
+
BaseTranslator::SourceSnippet.new(code: code.to_s, format: format)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def helpers_transpiler
|
|
62
|
+
@helpers_transpiler ||= build_transpiler
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def fragment_transpiler
|
|
66
|
+
@fragment_transpiler ||= build_transpiler(globals: helper_globals)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_transpiler(globals: {})
|
|
70
|
+
@transpiler_class.new(@definition.uniforms, @definition.custom_functions, globals: globals)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def helper_globals
|
|
74
|
+
return {} unless ruby_helpers? && @definition.helpers_block
|
|
75
|
+
|
|
76
|
+
@helper_globals ||= begin
|
|
77
|
+
compilation = if @definition.helpers_mode == :ruby_source
|
|
78
|
+
helpers_transpiler.compile_helpers_source(
|
|
79
|
+
@definition.helpers_block.call,
|
|
80
|
+
@definition.custom_functions
|
|
81
|
+
)
|
|
82
|
+
else
|
|
83
|
+
helpers_transpiler.compile_helpers(@definition.helpers_block, @definition.custom_functions)
|
|
84
|
+
end
|
|
85
|
+
extract_global_types(compilation.ir)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def extract_global_types(ir)
|
|
90
|
+
return {} unless ir.is_a?(Prism::IR::Block)
|
|
91
|
+
|
|
92
|
+
ir.statements.each_with_object({}) do |statement, globals|
|
|
93
|
+
next unless statement.is_a?(Prism::IR::GlobalDecl)
|
|
94
|
+
next unless statement.type
|
|
95
|
+
|
|
96
|
+
globals[statement.name] = statement.type
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def ruby_helpers?
|
|
101
|
+
@definition.ruby_helpers?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def ruby_fragment?
|
|
105
|
+
@definition.ruby_fragment?
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/rlsl/shader_builder.rb
CHANGED
|
@@ -1,165 +1,114 @@
|
|
|
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
|
-
@name = name
|
|
13
|
-
@
|
|
14
|
-
@fragment_mode = :c
|
|
15
|
-
@helpers_mode = :c
|
|
16
|
-
@custom_functions = {}
|
|
12
|
+
def initialize(name, definition = ShaderDefinition.new)
|
|
13
|
+
@name = RLSL.validate_shader_name!(name)
|
|
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
|
+
update_definition(@definition.with_uniforms(ctx.uniforms))
|
|
24
22
|
else
|
|
25
|
-
@uniforms
|
|
23
|
+
@definition.uniforms
|
|
26
24
|
end
|
|
27
25
|
end
|
|
28
26
|
|
|
27
|
+
def uniform_types
|
|
28
|
+
@definition.uniforms
|
|
29
|
+
end
|
|
30
|
+
|
|
29
31
|
def helpers(mode = :ruby, &block)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
raise ArgumentError, "helpers requires a block" unless block
|
|
33
|
+
|
|
34
|
+
resolved_mode = mode.to_sym
|
|
35
|
+
raise ArgumentError, "helpers mode must be :c or :ruby" unless %i[c ruby].include?(resolved_mode)
|
|
36
|
+
|
|
37
|
+
if resolved_mode == :ruby
|
|
38
|
+
source_unit = Prism::SourceExtractor.new.extract_unit(block)
|
|
39
|
+
update_definition(@definition.with_helpers(mode: :ruby_source, block: -> { source_unit }))
|
|
40
|
+
else
|
|
41
|
+
update_definition(@definition.with_helpers(mode: :c, block: block))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def helpers_source(source)
|
|
46
|
+
update_definition(@definition.with_helpers(mode: :ruby_source, block: -> { source.to_s }))
|
|
32
47
|
end
|
|
33
48
|
|
|
34
49
|
def functions(&block)
|
|
35
50
|
ctx = FunctionContext.new
|
|
36
51
|
ctx.instance_eval(&block)
|
|
37
|
-
@
|
|
52
|
+
update_definition(@definition.with_custom_functions(ctx.functions))
|
|
38
53
|
end
|
|
39
54
|
|
|
40
|
-
def fragment(&block)
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
def fragment(mode = :auto, &block)
|
|
56
|
+
raise ArgumentError, "fragment requires a block" unless block
|
|
57
|
+
|
|
58
|
+
resolved_mode = if mode == :auto
|
|
59
|
+
block.parameters.empty? ? :c : :ruby
|
|
60
|
+
else
|
|
61
|
+
mode.to_sym
|
|
62
|
+
end
|
|
63
|
+
unless %i[c ruby].include?(resolved_mode)
|
|
64
|
+
raise ArgumentError, "fragment mode must be :c or :ruby"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if resolved_mode == :ruby
|
|
68
|
+
source_unit = Prism::SourceExtractor.new.extract_unit(block)
|
|
69
|
+
update_definition(@definition.with_fragment(mode: :ruby_source, block: -> { source_unit }))
|
|
70
|
+
else
|
|
71
|
+
update_definition(@definition.with_fragment(mode: :c, block: block))
|
|
72
|
+
end
|
|
43
73
|
end
|
|
44
74
|
|
|
45
|
-
def
|
|
46
|
-
@
|
|
75
|
+
def fragment_source(source)
|
|
76
|
+
update_definition(@definition.with_fragment(mode: :ruby_source, block: -> { source.to_s }))
|
|
47
77
|
end
|
|
48
78
|
|
|
49
79
|
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)
|
|
80
|
+
build_service.compile_and_load
|
|
62
81
|
end
|
|
63
82
|
|
|
64
83
|
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)
|
|
84
|
+
build_service.build_metal_shader
|
|
77
85
|
end
|
|
78
86
|
|
|
79
87
|
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
|
|
88
|
+
build_service.build_wgsl_shader
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
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
|
|
92
|
+
build_service.build_glsl_shader(version: version)
|
|
103
93
|
end
|
|
104
94
|
|
|
105
95
|
def transpile_fragment(target)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
transpiler = Prism::Transpiler.new(@uniforms, @custom_functions)
|
|
109
|
-
transpiler.transpile(@fragment_block, target)
|
|
96
|
+
build_service.transpile_fragment(target)
|
|
110
97
|
end
|
|
111
98
|
|
|
112
99
|
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
|
|
100
|
+
build_service.transpile_helpers(target)
|
|
121
101
|
end
|
|
122
102
|
|
|
123
103
|
private
|
|
124
104
|
|
|
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
|
|
105
|
+
def build_service
|
|
106
|
+
@build_service ||= BuildService.new(@name, @definition)
|
|
142
107
|
end
|
|
143
108
|
|
|
144
|
-
def
|
|
145
|
-
|
|
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
|
|
109
|
+
def update_definition(definition)
|
|
110
|
+
@definition = definition
|
|
111
|
+
@build_service = nil
|
|
163
112
|
end
|
|
164
113
|
end
|
|
165
114
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
IDENTIFIER_PATTERN = /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
|
5
|
+
SHADER_NAME_PATTERN = IDENTIFIER_PATTERN
|
|
6
|
+
|
|
7
|
+
def self.validate_identifier!(name, context: "identifier")
|
|
8
|
+
normalized = name.to_s
|
|
9
|
+
return normalized if normalized.match?(IDENTIFIER_PATTERN)
|
|
10
|
+
|
|
11
|
+
raise ArgumentError,
|
|
12
|
+
"Invalid #{context} #{name.inspect}: use an ASCII identifier beginning with a letter or underscore"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.validate_shader_name!(name)
|
|
16
|
+
validate_identifier!(name, context: "shader name")
|
|
17
|
+
end
|
|
18
|
+
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: "i32",
|
|
120
|
+
msl_type: "int",
|
|
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: "texture2d<float>",
|
|
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
|