rbgl 0.1.0 → 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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -1
  3. data/lib/rbgl/engine/buffer.rb +102 -33
  4. data/lib/rbgl/engine/clip_space_clipper.rb +143 -0
  5. data/lib/rbgl/engine/context.rb +117 -64
  6. data/lib/rbgl/engine/framebuffer.rb +41 -32
  7. data/lib/rbgl/engine/pipeline.rb +38 -7
  8. data/lib/rbgl/engine/rasterizer/attribute_interpolator.rb +105 -0
  9. data/lib/rbgl/engine/rasterizer/line_renderer.rb +72 -0
  10. data/lib/rbgl/engine/rasterizer/point_renderer.rb +35 -0
  11. data/lib/rbgl/engine/rasterizer/triangle_renderer.rb +87 -0
  12. data/lib/rbgl/engine/rasterizer.rb +73 -162
  13. data/lib/rbgl/engine/shader/base_shader.rb +55 -0
  14. data/lib/rbgl/engine/shader/builtins.rb +254 -0
  15. data/lib/rbgl/engine/shader/dynamic_data.rb +65 -0
  16. data/lib/rbgl/engine/shader.rb +5 -318
  17. data/lib/rbgl/engine/texture.rb +227 -38
  18. data/lib/rbgl/engine.rb +1 -0
  19. data/lib/rbgl/gui/backend.rb +12 -30
  20. data/lib/rbgl/gui/backend_factory.rb +85 -0
  21. data/lib/rbgl/gui/cocoa/backend.rb +15 -35
  22. data/lib/rbgl/gui/file_backend/bmp_writer.rb +63 -0
  23. data/lib/rbgl/gui/file_backend/frame_writer.rb +28 -0
  24. data/lib/rbgl/gui/file_backend/ppm_writer.rb +25 -0
  25. data/lib/rbgl/gui/file_backend.rb +25 -48
  26. data/lib/rbgl/gui/wayland/backend.rb +108 -26
  27. data/lib/rbgl/gui/wayland/codec.rb +54 -0
  28. data/lib/rbgl/gui/wayland/connection.rb +80 -240
  29. data/lib/rbgl/gui/wayland/event_dispatcher.rb +74 -0
  30. data/lib/rbgl/gui/wayland/global_binder.rb +44 -0
  31. data/lib/rbgl/gui/wayland/protocol_objects/arguments.rb +51 -0
  32. data/lib/rbgl/gui/wayland/protocol_objects/display.rb +54 -0
  33. data/lib/rbgl/gui/wayland/protocol_objects/shm.rb +146 -0
  34. data/lib/rbgl/gui/wayland/protocol_objects/surface.rb +33 -0
  35. data/lib/rbgl/gui/wayland/protocol_objects/xdg_shell.rb +45 -0
  36. data/lib/rbgl/gui/wayland/protocol_objects.rb +7 -0
  37. data/lib/rbgl/gui/window/event_dispatcher.rb +30 -0
  38. data/lib/rbgl/gui/window/render_loop.rb +58 -0
  39. data/lib/rbgl/gui/window.rb +41 -82
  40. data/lib/rbgl/gui/x11/atom_cache.rb +26 -0
  41. data/lib/rbgl/gui/x11/backend.rb +14 -28
  42. data/lib/rbgl/gui/x11/connection.rb +104 -169
  43. data/lib/rbgl/gui/x11/event_parser.rb +60 -0
  44. data/lib/rbgl/gui/x11/request_encoder.rb +154 -0
  45. data/lib/rbgl/gui/x11/transport.rb +31 -0
  46. data/lib/rbgl/gui.rb +1 -0
  47. data/lib/rbgl/version.rb +1 -1
  48. metadata +31 -4
@@ -2,16 +2,19 @@
2
2
 
3
3
  module RBGL
4
4
  module GUI
5
+ class BackendUnavailable < StandardError
6
+ end
7
+
8
+ class BackendSelectionError < ArgumentError
9
+ end
10
+
5
11
  class Backend
6
12
  attr_reader :width, :height, :title
7
13
 
8
- def initialize(width, height, title = "RBGL")
14
+ def initialize(width, height, title = "RBGL", **_options)
9
15
  @width = width
10
16
  @height = height
11
17
  @title = title
12
- @key_callback = nil
13
- @mouse_callback = nil
14
- @resize_callback = nil
15
18
  end
16
19
 
17
20
  def present(_framebuffer)
@@ -26,6 +29,11 @@ module RBGL
26
29
  []
27
30
  end
28
31
 
32
+ def resize(width, height)
33
+ @width = width
34
+ @height = height
35
+ end
36
+
29
37
  def should_close?
30
38
  raise NotImplementedError
31
39
  end
@@ -45,32 +53,6 @@ module RBGL
45
53
  def native_handle
46
54
  nil
47
55
  end
48
-
49
- def on_key(&block)
50
- @key_callback = block
51
- end
52
-
53
- def on_mouse(&block)
54
- @mouse_callback = block
55
- end
56
-
57
- def on_resize(&block)
58
- @resize_callback = block
59
- end
60
-
61
- protected
62
-
63
- def emit_key(key, action)
64
- @key_callback&.call(key, action)
65
- end
66
-
67
- def emit_mouse(x, y, button, action)
68
- @mouse_callback&.call(x, y, button, action)
69
- end
70
-
71
- def emit_resize(width, height)
72
- @resize_callback&.call(width, height)
73
- end
74
56
  end
75
57
  end
76
58
  end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBGL
4
+ module GUI
5
+ class BackendFactory
6
+ AUTO_BACKEND_ERRORS = [LoadError, SystemCallError, BackendUnavailable].freeze
7
+
8
+ class << self
9
+ def build(backend, width:, height:, title:, platform: RUBY_PLATFORM, env: ENV, **options)
10
+ case backend
11
+ when :auto
12
+ build_auto_backend(
13
+ width: width,
14
+ height: height,
15
+ title: title,
16
+ platform: platform,
17
+ env: env,
18
+ **options
19
+ )
20
+ else
21
+ build_specific_backend(backend, width: width, height: height, title: title, env: env, **options)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def build_auto_backend(width:, height:, title:, platform:, env:, builder: nil, **options)
28
+ builder ||= method(:build_specific_backend)
29
+ errors = []
30
+
31
+ native_backend_candidates(platform: platform, env: env).each do |candidate|
32
+ return builder.call(candidate, width: width, height: height, title: title, env: env, **options)
33
+ rescue *AUTO_BACKEND_ERRORS => error
34
+ errors << [candidate, error]
35
+ end
36
+
37
+ raise_auto_backend_error(errors)
38
+ end
39
+
40
+ def build_specific_backend(backend, width:, height:, title:, env: ENV, **options)
41
+ case backend
42
+ when :file
43
+ FileBackend.new(width, height, title, **options)
44
+ when :x11
45
+ require_relative "x11/backend"
46
+ X11::Backend.new(width, height, title, env: env)
47
+ when :wayland
48
+ require_relative "wayland/backend"
49
+ Wayland::Backend.new(width, height, title, env: env)
50
+ when :cocoa
51
+ require_relative "cocoa/backend"
52
+ Cocoa::Backend.new(width, height, title, env: env)
53
+ when Backend
54
+ backend
55
+ else
56
+ raise BackendSelectionError, "Unknown backend: #{backend}"
57
+ end
58
+ end
59
+
60
+ def raise_auto_backend_error(errors)
61
+ return if errors.empty?
62
+
63
+ details = errors.map { |backend, error| "#{backend}: #{error.class}: #{error.message}" }.join(", ")
64
+ raise BackendUnavailable, "Failed to initialize any native backend (#{details})"
65
+ end
66
+
67
+ def native_backend_candidates(platform:, env:)
68
+ case platform
69
+ when /darwin/
70
+ [:cocoa]
71
+ when /linux/
72
+ candidates = []
73
+ candidates << :wayland if env["WAYLAND_DISPLAY"]
74
+ candidates << :x11 if env["DISPLAY"]
75
+ return candidates unless candidates.empty?
76
+
77
+ raise BackendUnavailable, "No display server found (DISPLAY or WAYLAND_DISPLAY not set)"
78
+ else
79
+ raise BackendUnavailable, "Unsupported platform: #{platform}"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,48 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "metaco"
5
- METACO_AVAILABLE = true
6
- rescue LoadError
7
- METACO_AVAILABLE = false
8
- end
9
-
10
3
  module RBGL
11
4
  module GUI
12
5
  module Cocoa
6
+ METACO_AVAILABLE = begin
7
+ require "metaco"
8
+ true
9
+ rescue LoadError
10
+ false
11
+ end
12
+
13
13
  class Backend < GUI::Backend
14
- def initialize(width, height, title = "RBGL")
14
+ def initialize(width, height, title = "RBGL", env: ENV)
15
+ @env = env
15
16
  unless METACO_AVAILABLE
16
17
  raise LoadError, "metaco gem is required for Cocoa backend. Install it with: gem install metaco"
17
18
  end
18
19
 
19
- super
20
+ super(width, height, title)
20
21
  Metaco.init
21
22
  @handle = Metaco.window_create(width, height, title)
22
23
  end
23
24
 
24
25
  def present(framebuffer)
25
- return unless @handle
26
+ return false unless @handle
26
27
 
27
28
  Metaco.set_pixels(@handle, framebuffer.to_rgba_bytes, framebuffer.width, framebuffer.height)
28
29
  Metaco.present(@handle)
30
+ true
29
31
  end
30
32
 
31
33
  def poll_events
32
34
  return [] unless @handle
33
35
 
34
36
  raw_events = Metaco.poll_events(@handle)
35
- events = []
36
-
37
- raw_events.each do |e|
38
- event = convert_event(e)
39
- if event
40
- events << event
41
- emit_from_event(event)
42
- end
43
- end
44
-
45
- events
37
+ raw_events.filter_map { |event| convert_event(event) }
46
38
  end
47
39
 
48
40
  def poll_events_raw
@@ -97,24 +89,12 @@ module RBGL
97
89
  Event.new(:mouse_release, x: raw[:x], y: raw[:y], button: raw[:button])
98
90
  when :mouse_move
99
91
  Event.new(:mouse_move, x: raw[:x], y: raw[:y])
92
+ when :resize
93
+ Event.new(:resize, width: raw[:width], height: raw[:height])
100
94
  else
101
95
  nil
102
96
  end
103
97
  end
104
-
105
- def emit_from_event(event)
106
- case event.type
107
- when :key_press, :key_release
108
- emit_key(event.key, event.type == :key_press ? :press : :release)
109
- when :mouse_press, :mouse_release, :mouse_move
110
- action = case event.type
111
- when :mouse_press then :press
112
- when :mouse_release then :release
113
- else :move
114
- end
115
- emit_mouse(event.x, event.y, event[:button], action)
116
- end
117
- end
118
98
  end
119
99
  end
120
100
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBGL
4
+ module GUI
5
+ class FileBackend < Backend
6
+ class BmpWriter < FrameWriter
7
+ def extension
8
+ "bmp"
9
+ end
10
+
11
+ def write(filename, framebuffer)
12
+ File.binwrite(filename, encode(framebuffer))
13
+ end
14
+
15
+ private
16
+
17
+ def encode(framebuffer)
18
+ width = framebuffer.width
19
+ height = framebuffer.height
20
+ row_size = ((24 * width + 31) / 32) * 4
21
+ pixel_data_size = row_size * height
22
+ file_size = 54 + pixel_data_size
23
+
24
+ header = [
25
+ 0x42, 0x4D,
26
+ file_size,
27
+ 0, 0,
28
+ 54
29
+ ].pack("CCVvvV")
30
+
31
+ dib = [
32
+ 40,
33
+ width, height,
34
+ 1,
35
+ 24,
36
+ 0,
37
+ pixel_data_size,
38
+ 2835, 2835,
39
+ 0, 0
40
+ ].pack("VVVvvVVVVVV")
41
+
42
+ header + dib + pixel_rows(framebuffer, width, height, row_size)
43
+ end
44
+
45
+ def pixel_rows(framebuffer, width, height, row_size)
46
+ pixels = +""
47
+
48
+ (height - 1).downto(0) do |y|
49
+ row = +""
50
+ width.times do |x|
51
+ bytes = framebuffer.get_pixel(x, y).to_bytes
52
+ row << [bytes[2], bytes[1], bytes[0]].pack("CCC")
53
+ end
54
+ row << "\x00" * (row_size - width * 3)
55
+ pixels << row
56
+ end
57
+
58
+ pixels
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBGL
4
+ module GUI
5
+ class FileBackend < Backend
6
+ class FrameWriter
7
+ def self.build(format, ppm_mode: :ascii)
8
+ case format
9
+ when :ppm
10
+ PpmWriter.new(binary: ppm_mode == :binary)
11
+ when :bmp
12
+ BmpWriter.new
13
+ else
14
+ raise ArgumentError, "Unsupported file backend format: #{format}"
15
+ end
16
+ end
17
+
18
+ def extension
19
+ raise NotImplementedError
20
+ end
21
+
22
+ def write(_filename, _framebuffer)
23
+ raise NotImplementedError
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBGL
4
+ module GUI
5
+ class FileBackend < Backend
6
+ class PpmWriter < FrameWriter
7
+ def initialize(binary:)
8
+ @binary = binary
9
+ end
10
+
11
+ def extension
12
+ "ppm"
13
+ end
14
+
15
+ def write(filename, framebuffer)
16
+ if @binary
17
+ File.binwrite(filename, framebuffer.to_ppm_binary)
18
+ else
19
+ File.write(filename, framebuffer.to_ppm)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,11 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "file_backend/frame_writer"
4
+ require_relative "file_backend/ppm_writer"
5
+ require_relative "file_backend/bmp_writer"
6
+
3
7
  module RBGL
4
8
  module GUI
5
9
  class FileBackend < Backend
6
- def initialize(width, height, title = "RBGL", format: :ppm, output_dir: ".")
10
+ SUPPORTED_FORMATS = %i[ppm bmp].freeze
11
+ PPM_MODES = %i[ascii binary].freeze
12
+
13
+ def initialize(width, height, title = "RBGL", format: :ppm, ppm_mode: :ascii, output_dir: ".")
7
14
  super(width, height, title)
8
- @format = format
15
+ @format = normalize_format(format)
16
+ @ppm_mode = normalize_ppm_mode(ppm_mode, @format)
17
+ @writer = FrameWriter.build(@format, ppm_mode: @ppm_mode)
9
18
  @output_dir = output_dir
10
19
  @frame_count = 0
11
20
  @should_close = false
@@ -13,23 +22,17 @@ module RBGL
13
22
  end
14
23
 
15
24
  def present(framebuffer)
16
- filename = File.join(@output_dir, format("frame_%05d.#{@format}", @frame_count))
17
-
18
- case @format
19
- when :ppm
20
- File.write(filename, framebuffer.to_ppm)
21
- when :ppm_binary
22
- File.binwrite(filename, framebuffer.to_ppm_binary)
23
- when :bmp
24
- File.binwrite(filename, to_bmp(framebuffer))
25
- end
25
+ filename = File.join(@output_dir, format("frame_%05d.#{@writer.extension}", @frame_count))
26
+ @writer.write(filename, framebuffer)
26
27
 
27
28
  @frame_count += 1
28
29
 
29
30
  @should_close = true if @max_frames && @frame_count >= @max_frames
31
+ true
30
32
  end
31
33
 
32
34
  def poll_events
35
+ []
33
36
  end
34
37
 
35
38
  def should_close?
@@ -46,45 +49,19 @@ module RBGL
46
49
 
47
50
  private
48
51
 
49
- def to_bmp(framebuffer)
50
- w = framebuffer.width
51
- h = framebuffer.height
52
- row_size = ((24 * w + 31) / 32) * 4
53
- pixel_data_size = row_size * h
54
- file_size = 54 + pixel_data_size
52
+ def normalize_format(format)
53
+ normalized = format.to_sym
54
+ return normalized if SUPPORTED_FORMATS.include?(normalized)
55
55
 
56
- header = [
57
- 0x42, 0x4D,
58
- file_size,
59
- 0, 0,
60
- 54
61
- ].pack("CCVvvV")
62
-
63
- dib = [
64
- 40,
65
- w, h,
66
- 1,
67
- 24,
68
- 0,
69
- pixel_data_size,
70
- 2835, 2835,
71
- 0, 0
72
- ].pack("VVVvvVVVVVV")
56
+ raise ArgumentError, "Unsupported file backend format: #{format}"
57
+ end
73
58
 
74
- pixels = +""
75
- (h - 1).downto(0) do |y|
76
- row = +""
77
- w.times do |x|
78
- color = framebuffer.get_pixel(x, y)
79
- bytes = color.to_bytes
80
- row << [bytes[2], bytes[1], bytes[0]].pack("CCC")
81
- end
82
- padding = row_size - w * 3
83
- row << "\x00" * padding
84
- pixels << row
85
- end
59
+ def normalize_ppm_mode(ppm_mode, format)
60
+ normalized = ppm_mode.to_sym
61
+ raise ArgumentError, "Unsupported PPM mode: #{ppm_mode}" unless PPM_MODES.include?(normalized)
62
+ return normalized if format == :ppm || normalized == :ascii
86
63
 
87
- header + dib + pixels
64
+ raise ArgumentError, "PPM mode is only supported with :ppm format"
88
65
  end
89
66
  end
90
67
  end
@@ -6,9 +6,12 @@ module RBGL
6
6
  module GUI
7
7
  module Wayland
8
8
  class Backend < GUI::Backend
9
- def initialize(width, height, title = "RBGL")
10
- super
11
- @connection = Connection.new
9
+ BUFFER_WAIT_TIMEOUT = 0.25
10
+ BUFFER_POLL_INTERVAL = 0.016
11
+
12
+ def initialize(width, height, title = "RBGL", env: ENV, roundtrip_timeout: Connection::DEFAULT_ROUNDTRIP_TIMEOUT)
13
+ super(width, height, title)
14
+ @connection = Connection.new(env: env, roundtrip_timeout: roundtrip_timeout)
12
15
  @windows = {}
13
16
  setup_window(width, height, title)
14
17
  end
@@ -19,9 +22,11 @@ module RBGL
19
22
  toplevel = xdg_surface.get_toplevel
20
23
  toplevel.set_title(t)
21
24
 
22
- shm_buffer = create_shm_buffer(w, h)
25
+ buffers = create_shm_buffers(w, h)
26
+ shm_buffer = buffers.first
23
27
 
24
28
  surface.attach(shm_buffer, 0, 0)
29
+ shm_buffer.mark_in_use
25
30
  surface.commit
26
31
  @connection.flush
27
32
 
@@ -30,41 +35,56 @@ module RBGL
30
35
  surface: surface,
31
36
  xdg_surface: xdg_surface,
32
37
  toplevel: toplevel,
38
+ buffers: buffers,
33
39
  shm_buffer: shm_buffer,
34
40
  width: w,
35
41
  height: h,
36
- should_close: false,
37
- pending_events: []
42
+ should_close: false
38
43
  }
39
44
 
40
45
  @handle = handle
41
46
  end
42
47
 
43
48
  def present(framebuffer)
44
- return unless @handle
49
+ return false unless @handle
45
50
 
46
51
  window = @windows[@handle]
47
- return unless window
52
+ return false unless window
53
+
54
+ buffer_object = wait_for_available_buffer(window)
55
+ return false unless buffer_object
48
56
 
49
57
  buffer = convert_to_wayland_format(framebuffer)
50
- window[:shm_buffer].write(buffer)
58
+ buffer_object.write(buffer)
51
59
 
52
60
  window[:surface].damage(0, 0, framebuffer.width, framebuffer.height)
53
- window[:surface].attach(window[:shm_buffer], 0, 0)
61
+ window[:surface].attach(buffer_object, 0, 0)
62
+ buffer_object.mark_in_use
63
+ window[:shm_buffer] = buffer_object
54
64
  window[:surface].commit
55
65
  @connection.flush
66
+ true
56
67
  end
57
68
 
58
69
  def poll_events
59
- events = []
60
- @connection.dispatch_pending
70
+ @connection.dispatch_pending.filter_map { |event| convert_event(event) }
71
+ end
61
72
 
62
- if @handle && @windows[@handle]
63
- events.concat(@windows[@handle][:pending_events])
64
- @windows[@handle][:pending_events] = []
65
- end
73
+ def resize(width, height)
74
+ super
75
+ return unless @handle
66
76
 
67
- events
77
+ window = @windows[@handle]
78
+ return unless window
79
+ return if window[:width] == width && window[:height] == height
80
+
81
+ old_buffers = window.fetch(:buffers, [window[:shm_buffer]].compact)
82
+ new_buffers = create_shm_buffers(width, height)
83
+ window[:buffers] = new_buffers
84
+ window[:shm_buffer] = new_buffers.first
85
+ window[:width] = width
86
+ window[:height] = height
87
+ old_buffers.each(&:destroy)
68
88
  end
69
89
 
70
90
  def should_close?
@@ -83,8 +103,9 @@ module RBGL
83
103
  window[:toplevel].destroy
84
104
  window[:xdg_surface].destroy
85
105
  window[:surface].destroy
86
- window[:shm_buffer].destroy
106
+ window.fetch(:buffers, [window[:shm_buffer]].compact).each(&:destroy)
87
107
  @windows.delete(@handle)
108
+ @handle = nil
88
109
  end
89
110
 
90
111
  private
@@ -93,15 +114,77 @@ module RBGL
93
114
  framebuffer.to_bgra_bytes
94
115
  end
95
116
 
117
+ def convert_event(raw)
118
+ window = window_for_event(raw[:object_id])
119
+ return nil unless window
120
+
121
+ case raw[:type]
122
+ when :xdg_toplevel_close
123
+ window[:should_close] = true
124
+ Event.new(:close)
125
+ when :xdg_toplevel_configure
126
+ width = raw[:width]
127
+ height = raw[:height]
128
+ return nil unless width.positive? && height.positive?
129
+
130
+ window[:width] = width
131
+ window[:height] = height
132
+ Event.new(:resize, width: width, height: height)
133
+ end
134
+ end
135
+
136
+ def window_for_event(object_id)
137
+ @windows.values.find { |window| window[:toplevel].id == object_id }
138
+ end
139
+
140
+ def next_available_buffer(window)
141
+ window.fetch(:buffers, [window[:shm_buffer]].compact).find(&:available?)
142
+ end
143
+
144
+ def wait_for_available_buffer(window)
145
+ deadline = monotonic_time + BUFFER_WAIT_TIMEOUT
146
+
147
+ loop do
148
+ buffer = next_available_buffer(window)
149
+ return buffer if buffer
150
+ return nil if abort_buffer_wait?(window, deadline)
151
+
152
+ pump_connection(timeout: remaining_buffer_wait(deadline))
153
+ end
154
+ end
155
+
156
+ def pump_connection(timeout:)
157
+ if @connection.respond_to?(:pump_events)
158
+ @connection.pump_events(timeout: timeout)
159
+ else
160
+ sleep(timeout)
161
+ end
162
+ end
163
+
164
+ def abort_buffer_wait?(window, deadline)
165
+ window[:should_close] || monotonic_time >= deadline
166
+ end
167
+
168
+ def remaining_buffer_wait(deadline)
169
+ [deadline - monotonic_time, BUFFER_POLL_INTERVAL].min.clamp(0.0, BUFFER_POLL_INTERVAL)
170
+ end
171
+
172
+ def monotonic_time
173
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
174
+ end
175
+
176
+ def create_shm_buffers(width, height, count = 2)
177
+ Array.new(count) { create_shm_buffer(width, height) }
178
+ end
179
+
96
180
  def create_shm_buffer(width, height)
97
181
  size = width * height * 4
98
182
 
99
- fd = create_anonymous_file(size)
100
-
101
- pool = @connection.shm.create_pool(fd, size)
183
+ file = create_anonymous_file(size)
184
+ pool = @connection.shm.create_pool(file.fileno, size)
102
185
  buffer = pool.create_buffer(0, width, height, width * 4, :argb8888)
103
186
 
104
- ShmBuffer.new(fd, size, buffer)
187
+ ShmBuffer.new(file, pool, buffer)
105
188
  end
106
189
 
107
190
  def create_anonymous_file(size)
@@ -110,16 +193,15 @@ module RBGL
110
193
 
111
194
  file = File.open(path, File::RDWR | File::CREAT | File::EXCL, 0o600)
112
195
  file.truncate(size)
113
- fd = file.fileno
114
196
  File.unlink(path)
115
-
116
- fd
197
+ file
117
198
  rescue Errno::ENOENT
118
199
  require "tempfile"
119
200
  tmpfile = Tempfile.new("rbgl")
120
201
  tmpfile.truncate(size)
121
- tmpfile.fileno
202
+ tmpfile
122
203
  end
204
+
123
205
  end
124
206
  end
125
207
  end