ability to fetch memory usage by the graphics server

This commit is contained in:
Dmitry Stepanov
2025-06-19 23:52:04 +03:00
parent a40704ce80
commit ea3d0914ac
5 changed files with 89 additions and 50 deletions
+2
View File
@@ -75,6 +75,7 @@ impl GlBuffer {
kind,
usage,
} = desc;
server.memory_usage.borrow_mut().buffers += size;
unsafe {
let gl_kind = kind.into_gl();
let gl_usage = usage.into_gl();
@@ -102,6 +103,7 @@ impl Drop for GlBuffer {
fn drop(&mut self) {
unsafe {
if let Some(state) = self.state.upgrade() {
state.memory_usage.borrow_mut().buffers -= self.size.get();
state.gl.delete_buffer(self.id);
}
}
+7
View File
@@ -29,6 +29,7 @@ use crate::{
texture::GlTexture,
ToGlConstant,
};
use fyrox_graphics::server::ServerMemoryUsage;
use fyrox_graphics::{
buffer::{GpuBuffer, GpuBufferDescriptor},
core::{color::Color, log::Log, math::Rect},
@@ -267,6 +268,7 @@ impl InnerState {
pub struct GlGraphicsServer {
pub gl: glow::Context,
pub(crate) state: RefCell<InnerState>,
pub(crate) memory_usage: RefCell<ServerMemoryUsage>,
this: RefCell<Option<Weak<GlGraphicsServer>>>,
}
@@ -578,6 +580,7 @@ impl GlGraphicsServer {
#[cfg(not(target_arch = "wasm32"))]
gl_surface,
)),
memory_usage: Default::default(),
this: Default::default(),
};
@@ -1196,4 +1199,8 @@ impl GraphicsServer for GlGraphicsServer {
}
}
}
fn memory_usage(&self) -> ServerMemoryUsage {
self.memory_usage.borrow().clone()
}
}
+62 -48
View File
@@ -62,6 +62,7 @@ pub struct GlTexture {
texture: glow::Texture,
kind: Cell<GpuTextureKind>,
pixel_kind: Cell<PixelKind>,
size_bytes: Cell<usize>,
// Force compiler to not implement Send and Sync, because OpenGL is not thread-safe.
thread_mark: PhantomData<*const u8>,
}
@@ -281,10 +282,14 @@ impl GlTexture {
texture,
kind: desc.kind.into(),
pixel_kind: desc.pixel_kind.into(),
size_bytes: Cell::new(0),
thread_mark: PhantomData,
};
result.set_data(desc.kind, desc.pixel_kind, desc.mip_count, desc.data)?;
let byte_count =
result.set_data(desc.kind, desc.pixel_kind, desc.mip_count, desc.data)?;
server.memory_usage.borrow_mut().textures += byte_count;
let mut binding = result.make_temp_binding();
if server.gl.supports_debug() {
@@ -332,12 +337,63 @@ impl Drop for GlTexture {
fn drop(&mut self) {
if let Some(state) = self.state.upgrade() {
unsafe {
state.memory_usage.borrow_mut().textures -= self.size_bytes.get();
state.gl.delete_texture(self.texture);
}
}
}
}
fn desired_byte_count(kind: GpuTextureKind, mip_count: usize, pixel_kind: PixelKind) -> usize {
let mut desired_byte_count = 0;
'mip_loop: for mip in 0..mip_count {
match kind {
GpuTextureKind::Line { length } => {
if let Some(length) = length.checked_shr(mip as u32) {
desired_byte_count += image_1d_size_bytes(pixel_kind, length);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Rectangle { width, height } => {
if let (Some(width), Some(height)) = (
width.checked_shr(mip as u32),
height.checked_shr(mip as u32),
) {
desired_byte_count += image_2d_size_bytes(pixel_kind, width, height);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Cube { size } => {
if let Some(size) = size.checked_shr(mip as u32) {
desired_byte_count += 6 * image_2d_size_bytes(pixel_kind, size, size);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Volume {
width,
height,
depth,
} => {
if let (Some(width), Some(height), Some(depth)) = (
width.checked_shr(mip as u32),
height.checked_shr(mip as u32),
depth.checked_shr(mip as u32),
) {
desired_byte_count += image_3d_size_bytes(pixel_kind, width, height, depth);
} else {
break 'mip_loop;
}
}
};
}
desired_byte_count
}
impl GpuTextureTrait for GlTexture {
fn set_data(
&self,
@@ -345,54 +401,10 @@ impl GpuTextureTrait for GlTexture {
pixel_kind: PixelKind,
mip_count: usize,
data: Option<&[u8]>,
) -> Result<(), FrameworkError> {
) -> Result<usize, FrameworkError> {
let mip_count = mip_count.max(1);
let mut desired_byte_count = 0;
'mip_loop: for mip in 0..mip_count {
match kind {
GpuTextureKind::Line { length } => {
if let Some(length) = length.checked_shr(mip as u32) {
desired_byte_count += image_1d_size_bytes(pixel_kind, length);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Rectangle { width, height } => {
if let (Some(width), Some(height)) = (
width.checked_shr(mip as u32),
height.checked_shr(mip as u32),
) {
desired_byte_count += image_2d_size_bytes(pixel_kind, width, height);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Cube { size } => {
if let Some(size) = size.checked_shr(mip as u32) {
desired_byte_count += 6 * image_2d_size_bytes(pixel_kind, size, size);
} else {
break 'mip_loop;
}
}
GpuTextureKind::Volume {
width,
height,
depth,
} => {
if let (Some(width), Some(height), Some(depth)) = (
width.checked_shr(mip as u32),
height.checked_shr(mip as u32),
depth.checked_shr(mip as u32),
) {
desired_byte_count += image_3d_size_bytes(pixel_kind, width, height, depth);
} else {
break 'mip_loop;
}
}
};
}
let desired_byte_count = desired_byte_count(kind, mip_count, pixel_kind);
if let Some(data) = data {
let actual_data_size = data.len();
@@ -404,6 +416,8 @@ impl GpuTextureTrait for GlTexture {
}
}
self.size_bytes.set(desired_byte_count);
self.kind.set(kind);
self.pixel_kind.set(pixel_kind);
@@ -616,7 +630,7 @@ impl GpuTextureTrait for GlTexture {
}
}
Ok(())
Ok(desired_byte_count)
}
fn kind(&self) -> GpuTextureKind {
+3 -2
View File
@@ -497,14 +497,15 @@ define_as_any_trait!(GpuTextureAsAny => GpuTextureTrait);
/// ```
pub trait GpuTextureTrait: GpuTextureAsAny {
/// Sets the new data of the texture. This method is also able to change the kind of the texture
/// and its pixel kind.
/// and its pixel kind. Returns the number of bytes occupied by the texture in the video memory.
/// If there's no data specified, the texture will still take the space defined by its metrics.
fn set_data(
&self,
kind: GpuTextureKind,
pixel_kind: PixelKind,
mip_count: usize,
data: Option<&[u8]>,
) -> Result<(), FrameworkError>;
) -> Result<usize, FrameworkError>;
/// Returns kind of the texture.
fn kind(&self) -> GpuTextureKind;
+15
View File
@@ -51,6 +51,18 @@ pub struct ServerCapabilities {
pub max_lod_bias: f32,
}
/// Contains information about used memory per each category of GPU resource. This is not precise
/// data; it only calculates total requested memory by the user of a graphics server and does not
/// include additional memory overhead in the video driver. Yet this information could still be
/// useful.
#[derive(Default, Debug, Clone)]
pub struct ServerMemoryUsage {
/// Total number of bytes used by all textures (including render targets).
pub textures: usize,
/// Total number of bytes used by all buffers (vertex, index, uniform, etc.)
pub buffers: usize,
}
/// A shared reference to a graphics server.
pub type SharedGraphicsServer = Rc<dyn GraphicsServer>;
@@ -168,6 +180,9 @@ pub trait GraphicsServer: GraphicsServerAsAny {
/// way of mipmaps generation, depending on the underlying GAPI capabilities.
fn generate_mipmap(&self, texture: &GpuTexture);
/// Fetches the total amount of memory used by the graphics server.
fn memory_usage(&self) -> ServerMemoryUsage;
/// A shortcut for [`Self::create_texture`], that creates a rectangular texture with the given
/// size and pixel kind.
fn create_2d_render_target(