fyrox_graphics_gl/
buffer.rs1use crate::server::GlGraphicsServer;
22use crate::ToGlConstant;
23use fyrox_graphics::buffer::GpuBufferDescriptor;
24use fyrox_graphics::{
25 buffer::{BufferKind, BufferUsage, GpuBufferTrait},
26 error::FrameworkError,
27};
28use glow::HasContext;
29use std::{cell::Cell, rc::Weak};
30
31impl ToGlConstant for BufferKind {
32 fn into_gl(self) -> u32 {
33 match self {
34 BufferKind::Vertex => glow::ARRAY_BUFFER,
35 BufferKind::Index => glow::ELEMENT_ARRAY_BUFFER,
36 BufferKind::Uniform => glow::UNIFORM_BUFFER,
37 BufferKind::PixelRead => glow::PIXEL_PACK_BUFFER,
38 BufferKind::PixelWrite => glow::PIXEL_UNPACK_BUFFER,
39 }
40 }
41}
42
43impl ToGlConstant for BufferUsage {
44 fn into_gl(self) -> u32 {
45 match self {
46 BufferUsage::StaticDraw => glow::STATIC_DRAW,
47 BufferUsage::StaticCopy => glow::STATIC_COPY,
48 BufferUsage::DynamicDraw => glow::DYNAMIC_DRAW,
49 BufferUsage::DynamicCopy => glow::DYNAMIC_COPY,
50 BufferUsage::StreamDraw => glow::STREAM_DRAW,
51 BufferUsage::StreamRead => glow::STREAM_READ,
52 BufferUsage::StreamCopy => glow::STREAM_COPY,
53 BufferUsage::StaticRead => glow::STATIC_READ,
54 BufferUsage::DynamicRead => glow::DYNAMIC_READ,
55 }
56 }
57}
58
59pub struct GlBuffer {
60 pub state: Weak<GlGraphicsServer>,
61 pub id: glow::Buffer,
62 pub size: Cell<usize>,
63 pub kind: BufferKind,
64 pub usage: BufferUsage,
65}
66
67impl GlBuffer {
68 pub fn new(
69 server: &GlGraphicsServer,
70 desc: GpuBufferDescriptor,
71 ) -> Result<Self, FrameworkError> {
72 let GpuBufferDescriptor {
73 #[allow(unused_variables)]
74 name,
75 size,
76 kind,
77 usage,
78 } = desc;
79 server.memory_usage.borrow_mut().buffers += size;
80 unsafe {
81 let gl_kind = kind.into_gl();
82 let gl_usage = usage.into_gl();
83 let id = server.gl.create_buffer()?;
84 server.gl.bind_buffer(gl_kind, Some(id));
85 #[cfg(not(target_arch = "wasm32"))]
86 if server.gl.supports_debug() && server.named_objects.get() {
87 server.gl.object_label(glow::BUFFER, id.0.get(), Some(name));
88 }
89 if size > 0 {
90 server.gl.buffer_data_size(gl_kind, size as i32, gl_usage);
91 }
92 server.gl.bind_buffer(gl_kind, None);
93 Ok(Self {
94 state: server.weak(),
95 id,
96 size: Cell::new(size),
97 kind,
98 usage,
99 })
100 }
101 }
102}
103
104impl Drop for GlBuffer {
105 fn drop(&mut self) {
106 unsafe {
107 if let Some(state) = self.state.upgrade() {
108 state.memory_usage.borrow_mut().buffers -= self.size.get();
109 state.gl.delete_buffer(self.id);
110 }
111 }
112 }
113}
114
115impl GpuBufferTrait for GlBuffer {
116 fn usage(&self) -> BufferUsage {
117 self.usage
118 }
119
120 fn kind(&self) -> BufferKind {
121 self.kind
122 }
123
124 fn size(&self) -> usize {
125 self.size.get()
126 }
127
128 fn write_data(&self, data: &[u8]) -> Result<(), FrameworkError> {
129 if data.is_empty() {
130 return Ok(());
131 }
132
133 let Some(server) = self.state.upgrade() else {
134 return Err(FrameworkError::GraphicsServerUnavailable);
135 };
136
137 let gl_kind = self.kind.into_gl();
138 let gl_usage = self.usage.into_gl();
139
140 unsafe {
141 server.gl.bind_buffer(gl_kind, Some(self.id));
142 if data.len() <= self.size.get() {
143 server.gl.buffer_sub_data_u8_slice(gl_kind, 0, data);
145 } else {
146 let mut memory_usage = server.memory_usage.borrow_mut();
147 memory_usage.buffers -= self.size.get();
148 memory_usage.buffers += data.len();
149
150 server.gl.buffer_data_u8_slice(gl_kind, data, gl_usage);
152 self.size.set(data.len());
153 }
154 }
155
156 Ok(())
157 }
158
159 fn read_data(&self, data: &mut [u8]) -> Result<(), FrameworkError> {
160 let Some(server) = self.state.upgrade() else {
161 return Err(FrameworkError::GraphicsServerUnavailable);
162 };
163
164 let gl_kind = self.kind.into_gl();
165
166 unsafe {
167 server.gl.bind_buffer(gl_kind, Some(self.id));
168
169 #[cfg(not(target_arch = "wasm32"))]
170 {
171 let gl_storage =
172 server
173 .gl
174 .map_buffer_range(gl_kind, 0, data.len() as i32, glow::MAP_READ_BIT);
175 assert_ne!(gl_storage, std::ptr::null_mut());
176 std::ptr::copy_nonoverlapping(gl_storage, data.as_mut_ptr(), data.len());
177 server.gl.unmap_buffer(gl_kind);
178 }
179
180 #[cfg(target_arch = "wasm32")]
181 {
182 server.gl.get_buffer_sub_data(gl_kind, 0, data);
185 }
186
187 server.gl.bind_buffer(gl_kind, None);
188 }
189
190 Ok(())
191 }
192}