rbgl 1.0.0 → 1.0.2

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.codespellignore +4 -0
  3. data/.rubocop.yml +3 -0
  4. data/.yamllint +16 -0
  5. data/CHANGELOG.md +11 -1
  6. data/README.md +130 -74
  7. data/Rakefile +7 -0
  8. data/bench/renderer_bench.rb +283 -0
  9. data/docs/.nojekyll +1 -0
  10. data/docs/index.html +38 -0
  11. data/examples/array_test.rb +1 -1
  12. data/examples/color_test.rb +1 -1
  13. data/examples/cube_spinning.rb +1 -1
  14. data/examples/gradient.rb +1 -1
  15. data/examples/multi_return_test.rb +1 -1
  16. data/examples/plasma.rb +1 -1
  17. data/examples/sphere_raymarch.rb +1 -1
  18. data/examples/triangle_window.rb +1 -1
  19. data/exe/rbgl +42 -0
  20. data/lib/rbgl/cli/doctor.rb +155 -0
  21. data/lib/rbgl/engine/buffer.rb +55 -9
  22. data/lib/rbgl/engine/clip_space_clipper.rb +23 -3
  23. data/lib/rbgl/engine/context.rb +23 -6
  24. data/lib/rbgl/engine/framebuffer.rb +146 -41
  25. data/lib/rbgl/engine/immutable_color.rb +32 -0
  26. data/lib/rbgl/engine/rasterizer/attribute_interpolator.rb +100 -10
  27. data/lib/rbgl/engine/rasterizer/line_renderer.rb +30 -14
  28. data/lib/rbgl/engine/rasterizer/point_renderer.rb +3 -3
  29. data/lib/rbgl/engine/rasterizer/triangle_renderer.rb +72 -23
  30. data/lib/rbgl/engine/rasterizer.rb +3 -20
  31. data/lib/rbgl/engine/shader/base_shader.rb +3 -7
  32. data/lib/rbgl/engine/shader/builtins.rb +13 -10
  33. data/lib/rbgl/engine/shader/dynamic_data.rb +18 -10
  34. data/lib/rbgl/engine/texture.rb +74 -50
  35. data/lib/rbgl/engine.rb +3 -1
  36. data/lib/rbgl/gui/backend.rb +12 -7
  37. data/lib/rbgl/gui/backend_factory.rb +7 -3
  38. data/lib/rbgl/gui/cocoa/backend.rb +50 -17
  39. data/lib/rbgl/gui/cocoa/key_mapper.rb +48 -0
  40. data/lib/rbgl/gui/event.rb +4 -2
  41. data/lib/rbgl/gui/file_backend/bmp_writer.rb +2 -2
  42. data/lib/rbgl/gui/file_backend/frame_writer.rb +7 -0
  43. data/lib/rbgl/gui/file_backend/png_writer.rb +18 -0
  44. data/lib/rbgl/gui/file_backend/ppm_writer.rb +1 -0
  45. data/lib/rbgl/gui/file_backend.rb +24 -6
  46. data/lib/rbgl/gui/wayland/backend.rb +127 -55
  47. data/lib/rbgl/gui/wayland/codec.rb +7 -11
  48. data/lib/rbgl/gui/wayland/connection.rb +137 -20
  49. data/lib/rbgl/gui/wayland/event_dispatcher.rb +103 -12
  50. data/lib/rbgl/gui/wayland/global_binder.rb +6 -4
  51. data/lib/rbgl/gui/wayland/input_mapper.rb +61 -0
  52. data/lib/rbgl/gui/wayland/protocol_objects/arguments.rb +14 -2
  53. data/lib/rbgl/gui/wayland/protocol_objects/seat.rb +115 -0
  54. data/lib/rbgl/gui/wayland/protocol_objects/shm.rb +23 -12
  55. data/lib/rbgl/gui/wayland/protocol_objects/xdg_shell.rb +15 -0
  56. data/lib/rbgl/gui/wayland/protocol_objects.rb +1 -0
  57. data/lib/rbgl/gui/window/render_loop.rb +71 -18
  58. data/lib/rbgl/gui/window.rb +39 -8
  59. data/lib/rbgl/gui/x11/atom_cache.rb +4 -1
  60. data/lib/rbgl/gui/x11/backend.rb +66 -28
  61. data/lib/rbgl/gui/x11/connection.rb +216 -86
  62. data/lib/rbgl/gui/x11/event_parser.rb +13 -2
  63. data/lib/rbgl/gui/x11/key_mapper.rb +48 -0
  64. data/lib/rbgl/gui/x11/pixel_encoder.rb +164 -0
  65. data/lib/rbgl/gui/x11/request_encoder.rb +29 -28
  66. data/lib/rbgl/gui/x11/setup_parser.rb +138 -0
  67. data/lib/rbgl/gui/x11/transport.rb +52 -2
  68. data/lib/rbgl/gui/x11/x_authority.rb +107 -0
  69. data/lib/rbgl/gui.rb +2 -5
  70. data/lib/rbgl/version.rb +1 -1
  71. metadata +38 -24
  72. data/examples/chemical_heartbeat.rb +0 -166
  73. data/examples/dark_transit.rb +0 -166
  74. data/examples/fractured_orb.rb +0 -428
  75. data/examples/fractured_orb_rb.rb +0 -598
  76. data/examples/hexagonal_flow.rb +0 -333
  77. data/examples/teapot.rb +0 -362
  78. data/examples/teapot_mcu.rb +0 -344
@@ -52,7 +52,7 @@ while running && !window.should_close?
52
52
 
53
53
  events = window.poll_events_raw
54
54
  events.each do |e|
55
- if e[:type] == :key_press && (e[:key] == 12 || e[:key] == "q")
55
+ if e[:type] == :key_press && %i[escape q].include?(e[:key])
56
56
  running = false
57
57
  end
58
58
  end
@@ -67,7 +67,7 @@ view = Mat4.look_at(
67
67
 
68
68
  window.on(:key_press) do |event|
69
69
  puts "Key pressed: #{event.key}"
70
- window.stop if event.key == 12 || event.key == "q" || event.key == "Escape"
70
+ window.stop if %i[escape q].include?(event.key)
71
71
  end
72
72
 
73
73
  puts "Press 'q' or Escape to quit"
data/examples/gradient.rb CHANGED
@@ -67,7 +67,7 @@ while running && !window.should_close?
67
67
  events.each do |e|
68
68
  case e[:type]
69
69
  when :key_press
70
- running = false if e[:key] == 12 || e[:key] == "q"
70
+ running = false if %i[escape q].include?(e[:key])
71
71
  end
72
72
  end
73
73
 
@@ -81,7 +81,7 @@ while running && !window.should_close?
81
81
  events.each do |e|
82
82
  case e[:type]
83
83
  when :key_press
84
- running = false if e[:key] == 12 || e[:key] == "q"
84
+ running = false if %i[escape q].include?(e[:key])
85
85
  end
86
86
  end
87
87
 
data/examples/plasma.rb CHANGED
@@ -60,7 +60,7 @@ while running && !window.should_close?
60
60
 
61
61
  events = window.poll_events_raw
62
62
  events.each do |e|
63
- if e[:type] == :key_press && (e[:key] == 12 || e[:key] == "q")
63
+ if e[:type] == :key_press && %i[escape q].include?(e[:key])
64
64
  running = false
65
65
  end
66
66
  end
@@ -108,7 +108,7 @@ while running && !window.should_close?
108
108
 
109
109
  events = window.poll_events_raw
110
110
  events.each do |e|
111
- if e[:type] == :key_press && (e[:key] == 12 || e[:key] == "q")
111
+ if e[:type] == :key_press && %i[escape q].include?(e[:key])
112
112
  running = false
113
113
  end
114
114
  end
@@ -42,7 +42,7 @@ time = 0.0
42
42
 
43
43
  window.on(:key_press) do |event|
44
44
  puts "Key: #{event.key}"
45
- window.stop if event.key == 12 || event.key == "q" || event.key == "Escape"
45
+ window.stop if %i[escape q].include?(event.key)
46
46
  end
47
47
 
48
48
  window.on(:mouse_move) do |event|
data/exe/rbgl ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "optparse"
6
+
7
+ lib_path = File.expand_path("../lib", __dir__)
8
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
9
+
10
+ require "rbgl"
11
+ require "rbgl/cli/doctor"
12
+
13
+ module RBGLCLI
14
+ def self.run(argv = ARGV, stdout: $stdout, stderr: $stderr)
15
+ options = { json: false }
16
+
17
+ parser = OptionParser.new do |parser|
18
+ parser.banner = "Usage: rbgl <command>\n\nCommands:\n doctor [--json]\n"
19
+ parser.on("--json", "Output JSON") { options[:json] = true }
20
+ parser.on("-h", "--help", "Show this help") do
21
+ stdout.puts parser
22
+ return 0
23
+ end
24
+ end
25
+
26
+ parser.parse!(argv)
27
+
28
+ command = argv.shift
29
+ unless command == "doctor"
30
+ stderr.puts parser
31
+ return 1
32
+ end
33
+
34
+ RBGL::CLI::Doctor.new(json: options[:json], io: stdout).run
35
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument => error
36
+ stderr.puts error.message
37
+ stderr.puts parser
38
+ 1
39
+ end
40
+ end
41
+
42
+ exit RBGLCLI.run
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "json"
5
+ require "tmpdir"
6
+
7
+ module RBGL
8
+ module CLI
9
+ class Doctor
10
+ class << self
11
+ def default_checks
12
+ {
13
+ file_backend: ->(doctor, env, platform) { doctor.__send__(:check_file_backend, env, platform) },
14
+ wayland: ->(doctor, env, platform) { doctor.__send__(:check_wayland, env, platform) },
15
+ x11: ->(doctor, env, platform) { doctor.__send__(:check_x11, env, platform) },
16
+ cocoa: ->(doctor, env, platform) { doctor.__send__(:check_cocoa, env, platform) },
17
+ rlsl: ->(doctor, env, platform) { doctor.__send__(:check_rlsl, env, platform) }
18
+ }
19
+ end
20
+ end
21
+
22
+ def initialize(json: false, io: $stdout, env: ENV, platform: RUBY_PLATFORM, ruby_version: RUBY_VERSION, checks: {})
23
+ @json = json
24
+ @io = io
25
+ @env = env
26
+ @platform = platform
27
+ @ruby_version = ruby_version
28
+ @checks = self.class.default_checks.merge(checks)
29
+ end
30
+
31
+ def run
32
+ report = collect
33
+
34
+ if @json
35
+ output_json(report)
36
+ else
37
+ output_text(report)
38
+ end
39
+
40
+ 0
41
+ end
42
+
43
+ def collect
44
+ {
45
+ rbgl_version: RBGL::VERSION,
46
+ ruby_version: @ruby_version,
47
+ platform: @platform,
48
+ file_backend: collect_component(:file_backend),
49
+ wayland: collect_component(:wayland),
50
+ x11: collect_component(:x11),
51
+ cocoa: collect_component(:cocoa),
52
+ rlsl: collect_component(:rlsl)
53
+ }
54
+ end
55
+
56
+ private
57
+
58
+ def collect_component(key)
59
+ @checks.fetch(key).call(self, @env, @platform)
60
+ rescue StandardError => e
61
+ { available: false, error: "#{e.class}: #{e.message}" }
62
+ end
63
+
64
+ def output_text(report)
65
+ @io.puts("RBGL version: #{report[:rbgl_version]}")
66
+ @io.puts("Ruby version: #{report[:ruby_version]}")
67
+ @io.puts("RUBY_PLATFORM: #{report[:platform]}")
68
+ @io.puts
69
+ dump_section("File backend", report[:file_backend])
70
+ dump_section("Wayland", report[:wayland])
71
+ dump_section("X11", report[:x11])
72
+ dump_section("Cocoa", report[:cocoa])
73
+ dump_section("RLSL", report[:rlsl])
74
+ end
75
+
76
+ def output_json(report)
77
+ @io.puts(JSON.pretty_generate(report))
78
+ end
79
+
80
+ def dump_section(name, values)
81
+ @io.puts("#{name}:")
82
+ values.each do |key, value|
83
+ @io.puts(" #{key}: #{format_value(value)}")
84
+ end
85
+ @io.puts
86
+ end
87
+
88
+ def format_value(value)
89
+ return value.is_a?(TrueClass) || value.is_a?(FalseClass) ? (value ? "yes" : "no") : value.inspect
90
+ end
91
+
92
+ def check_file_backend(_env, _platform)
93
+ output_dir = Dir.mktmpdir("rbgl-doctor")
94
+ backend = RBGL::GUI::FileBackend.new(1, 1, "rbgl-doctor", output_dir: output_dir)
95
+ backend.present(RBGL::Engine::Framebuffer.new(1, 1))
96
+
97
+ { available: true, output_dir: output_dir }
98
+ ensure
99
+ backend&.close
100
+ FileUtils.rm_rf(output_dir) if output_dir
101
+ end
102
+
103
+ def check_wayland(env, _platform)
104
+ require_ok, require_error = safe_require("rbgl/gui/wayland/connection")
105
+ {
106
+ display_env: env["WAYLAND_DISPLAY"],
107
+ display_available: !env["WAYLAND_DISPLAY"].nil?,
108
+ require_ok: require_ok,
109
+ require_error: require_error
110
+ }
111
+ end
112
+
113
+ def check_x11(env, _platform)
114
+ require_ok, require_error = safe_require("rbgl/gui/x11/connection")
115
+ {
116
+ display_env: env["DISPLAY"],
117
+ display_available: !env["DISPLAY"].nil?,
118
+ require_ok: require_ok,
119
+ require_error: require_error
120
+ }
121
+ end
122
+
123
+ def check_cocoa(_env, platform)
124
+ darwin = platform.include?("darwin")
125
+ return { platform: platform, supported: false } unless darwin
126
+
127
+ require_ok, require_error = safe_require("metaco")
128
+ {
129
+ platform: platform,
130
+ supported: true,
131
+ require_ok: require_ok,
132
+ require_error: require_error
133
+ }
134
+ end
135
+
136
+ def check_rlsl(_env, _platform)
137
+ begin
138
+ require "rlsl"
139
+ version = Gem.loaded_specs["rlsl"]&.version&.to_s
140
+
141
+ { require_ok: true, version: version }
142
+ rescue LoadError => e
143
+ { require_ok: false, error: "#{e.class}: #{e.message}" }
144
+ end
145
+ end
146
+
147
+ def safe_require(file)
148
+ require file
149
+ [true, nil]
150
+ rescue LoadError => e
151
+ [false, "#{e.class}: #{e.message}"]
152
+ end
153
+ end
154
+ end
155
+ end
@@ -6,6 +6,10 @@ module RBGL
6
6
  attr_reader :name, :size, :offset, :kind
7
7
 
8
8
  def initialize(name, size, offset = 0, kind: nil)
9
+ unless size.is_a?(Integer) && size.positive?
10
+ raise ArgumentError, "Vertex attribute size must be a positive Integer"
11
+ end
12
+
9
13
  @name = name.to_sym
10
14
  @size = size
11
15
  @offset = offset
@@ -16,7 +20,12 @@ module RBGL
16
20
  def serialize(value)
17
21
  values = extract_values(value)
18
22
  validate_value_size!(values)
19
- values.first(@size).map { |component| Float(component) }
23
+ values.first(@size).map do |component|
24
+ number = Float(component)
25
+ raise ArgumentError, "non-finite component" unless number.finite?
26
+
27
+ number
28
+ end
20
29
  rescue ArgumentError, TypeError => e
21
30
  raise ArgumentError, "Invalid value for attribute #{name}: #{e.message}"
22
31
  end
@@ -96,18 +105,35 @@ module RBGL
96
105
  end
97
106
 
98
107
  class VertexLayout
99
- attr_reader :attributes, :stride
108
+ attr_reader :stride
100
109
 
101
110
  def initialize(&block)
102
111
  @attributes = {}
103
112
  @offset = 0
113
+ @stride = 0
114
+ @finalized = false
104
115
  instance_eval(&block) if block_given?
105
- @stride = @offset
106
116
  end
107
117
 
108
118
  def attribute(name, size, kind: nil)
109
- @attributes[name.to_sym] = VertexAttribute.new(name, size, @offset, kind: kind)
119
+ raise ArgumentError, "Vertex layout is finalized" if @finalized
120
+
121
+ key = name.to_sym
122
+ raise ArgumentError, "Duplicate vertex attribute: #{key}" if @attributes.key?(key)
123
+
124
+ @attributes[key] = VertexAttribute.new(key, size, @offset, kind: kind)
110
125
  @offset += size
126
+ @stride = @offset
127
+ end
128
+
129
+ def attributes
130
+ @finalized ? @attributes : @attributes.dup.freeze
131
+ end
132
+
133
+ def finalize!
134
+ @finalized = true
135
+ @attributes.freeze
136
+ self
111
137
  end
112
138
 
113
139
  def self.position_only
@@ -143,7 +169,11 @@ module RBGL
143
169
  attr_reader :data, :layout, :vertex_count
144
170
 
145
171
  def initialize(layout)
146
- @layout = layout
172
+ unless layout.is_a?(VertexLayout)
173
+ raise ArgumentError, "VertexBuffer layout must be an RBGL::Engine::VertexLayout"
174
+ end
175
+
176
+ @layout = layout.finalize!
147
177
  @data = []
148
178
  @vertex_count = 0
149
179
  end
@@ -199,14 +229,16 @@ module RBGL
199
229
  end
200
230
 
201
231
  class IndexBuffer
202
- attr_reader :indices
203
-
204
232
  def initialize(indices = [])
205
- @indices = indices.map(&:to_i)
233
+ @indices = validate_indices!(indices)
234
+ end
235
+
236
+ def indices
237
+ @indices.dup.freeze
206
238
  end
207
239
 
208
240
  def add(*idx)
209
- @indices.concat(idx.flatten.map(&:to_i))
241
+ @indices.concat(validate_indices!(idx.flatten))
210
242
  self
211
243
  end
212
244
 
@@ -215,6 +247,8 @@ module RBGL
215
247
  end
216
248
 
217
249
  def get_triangle(index)
250
+ return nil unless index.is_a?(Integer) && index >= 0
251
+
218
252
  start = index * 3
219
253
  @indices[start, 3]
220
254
  end
@@ -224,6 +258,18 @@ module RBGL
224
258
 
225
259
  (0...triangle_count).each { |i| yield get_triangle(i) }
226
260
  end
261
+
262
+ private
263
+
264
+ def validate_indices!(indices)
265
+ indices.map do |index|
266
+ unless index.is_a?(Integer) && index >= 0
267
+ raise ArgumentError, "Index must be a non-negative Integer: #{index.inspect}"
268
+ end
269
+
270
+ index
271
+ end
272
+ end
227
273
  end
228
274
  end
229
275
  end
@@ -13,7 +13,10 @@ module RBGL
13
13
  ].freeze
14
14
 
15
15
  def clip(v0, v1, v2)
16
- polygon = [v0, v1, v2]
16
+ polygon = [v0, v1, v2].map { |vertex| normalize_vertex(vertex) }
17
+ outcodes = polygon.map { |vertex| outcode(vertex) }
18
+ return [polygon] if outcodes.reduce(:|).zero?
19
+ return [] unless outcodes.reduce(:&).zero?
17
20
 
18
21
  CLIP_PLANES.each do |plane|
19
22
  polygon = clip_against_plane(polygon, plane)
@@ -38,6 +41,11 @@ module RBGL
38
41
  CLIP_PLANES.all? { |plane| signed_distance(vertex, plane) >= 0 }
39
42
  end
40
43
 
44
+ def clip_point(vertex)
45
+ point = normalize_vertex(vertex)
46
+ visible_point?(point) ? point : nil
47
+ end
48
+
41
49
  private
42
50
 
43
51
  def clip_against_plane(vertices, plane)
@@ -102,7 +110,13 @@ module RBGL
102
110
  end
103
111
 
104
112
  def duplicate_vertex(vertex)
105
- ShaderIO.new(vertex.to_h)
113
+ ShaderIO.new(vertex.to_h).tap do |copy|
114
+ copy[:position] = clip_position(vertex) if vertex[:position].is_a?(Larb::Vec2)
115
+ end
116
+ end
117
+
118
+ def normalize_vertex(vertex)
119
+ vertex[:position].is_a?(Larb::Vec2) ? duplicate_vertex(vertex) : vertex
106
120
  end
107
121
 
108
122
  def interpolated_keys(start_vertex, finish_vertex)
@@ -115,7 +129,7 @@ module RBGL
115
129
 
116
130
  case start_value
117
131
  when Numeric
118
- start_value + (finish_value - start_value) * t
132
+ start_value + ((finish_value - start_value) * t)
119
133
  when Larb::Vec2, Larb::Vec3, Larb::Vec4, Larb::Color
120
134
  start_value.lerp(finish_value, t)
121
135
  else
@@ -127,6 +141,12 @@ module RBGL
127
141
  plane.call(clip_position(vertex))
128
142
  end
129
143
 
144
+ def outcode(vertex)
145
+ CLIP_PLANES.each_with_index.reduce(0) do |code, (plane, index)|
146
+ signed_distance(vertex, plane).negative? ? code | (1 << index) : code
147
+ end
148
+ end
149
+
130
150
  def clip_position(vertex)
131
151
  position = vertex[:position]
132
152
 
@@ -46,12 +46,18 @@ module RBGL
46
46
 
47
47
  def draw_arrays(mode, first, count)
48
48
  validate_draw_state!
49
- draw_vertices(mode, first...first + count)
49
+ validate_draw_range!(first, count, @vertex_buffer.vertex_count)
50
+ draw_vertices(mode, first...(first + count))
50
51
  end
51
52
 
52
53
  def draw_elements(mode, count, offset = 0)
53
54
  validate_draw_state!(indexed: true)
54
- indices = @index_buffer.indices[offset, count] || []
55
+ all_indices = @index_buffer.indices
56
+ validate_draw_range!(offset, count, all_indices.size)
57
+ indices = all_indices[offset, count]
58
+ invalid_index = indices.find { |index| index >= @vertex_buffer.vertex_count }
59
+ raise ArgumentError, "Vertex index out of bounds: #{invalid_index}" if invalid_index
60
+
55
61
  draw_vertices(mode, indices, vertex_cache: {})
56
62
  end
57
63
 
@@ -75,6 +81,15 @@ module RBGL
75
81
  raise "No index buffer bound" if indexed && !@index_buffer
76
82
  end
77
83
 
84
+ def validate_draw_range!(offset, count, limit)
85
+ unless offset.is_a?(Integer) && count.is_a?(Integer) && offset >= 0 && count >= 0
86
+ raise ArgumentError, "Draw offset and count must be non-negative Integers"
87
+ end
88
+ return if offset + count <= limit
89
+
90
+ raise ArgumentError, "Draw range exceeds available data"
91
+ end
92
+
78
93
  def draw_vertices(mode, indices, vertex_cache: nil)
79
94
  each_primitive(mode, indices) do |primitive_indices|
80
95
  primitive = primitive_indices.map { |index| fetch_vertex(index, vertex_cache) }
@@ -95,7 +110,7 @@ module RBGL
95
110
  when :points
96
111
  vertices.each { |vertex| yield [vertex] }
97
112
  when :triangle_strip
98
- (0...vertices.size - 2).each do |index|
113
+ (0...(vertices.size - 2)).each do |index|
99
114
  if index.even?
100
115
  yield [vertices[index], vertices[index + 1], vertices[index + 2]]
101
116
  else
@@ -103,7 +118,7 @@ module RBGL
103
118
  end
104
119
  end
105
120
  when :triangle_fan
106
- (1...vertices.size - 1).each do |index|
121
+ (1...(vertices.size - 1)).each do |index|
107
122
  yield [vertices[0], vertices[index], vertices[index + 1]]
108
123
  end
109
124
  else
@@ -169,10 +184,12 @@ module RBGL
169
184
  end
170
185
 
171
186
  def draw_point(v)
172
- return unless v && point_visible?(v)
187
+ return unless v
188
+ clipped = @clipper.clip_point(v)
189
+ return unless clipped
173
190
 
174
191
  @rasterizer.rasterize_point(
175
- v,
192
+ clipped,
176
193
  @pipeline.fragment_shader,
177
194
  @uniforms,
178
195
  depth_test: @pipeline.depth_test,