Reduce GPU memory usage (#7319)
This pull request decreases the size of each instance buffer and shares instance buffers across windows. Release Notes: - Improved GPU memory usage. --------- Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
d08d4174a5
commit
c906fd232d
3 changed files with 24 additions and 13 deletions
|
@ -24,7 +24,7 @@ const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shader
|
||||||
#[cfg(feature = "runtime_shaders")]
|
#[cfg(feature = "runtime_shaders")]
|
||||||
const SHADERS_SOURCE_FILE: &'static str =
|
const SHADERS_SOURCE_FILE: &'static str =
|
||||||
include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal"));
|
include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal"));
|
||||||
const INSTANCE_BUFFER_SIZE: usize = 32 * 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value (maybe even we could adjust dynamically...)
|
const INSTANCE_BUFFER_SIZE: usize = 2 * 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value (maybe even we could adjust dynamically...)
|
||||||
|
|
||||||
pub(crate) struct MetalRenderer {
|
pub(crate) struct MetalRenderer {
|
||||||
device: metal::Device,
|
device: metal::Device,
|
||||||
|
@ -40,13 +40,13 @@ pub(crate) struct MetalRenderer {
|
||||||
surfaces_pipeline_state: metal::RenderPipelineState,
|
surfaces_pipeline_state: metal::RenderPipelineState,
|
||||||
unit_vertices: metal::Buffer,
|
unit_vertices: metal::Buffer,
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
instance_buffers: Arc<Mutex<Vec<metal::Buffer>>>,
|
instance_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>,
|
||||||
sprite_atlas: Arc<MetalAtlas>,
|
sprite_atlas: Arc<MetalAtlas>,
|
||||||
core_video_texture_cache: CVMetalTextureCache,
|
core_video_texture_cache: CVMetalTextureCache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetalRenderer {
|
impl MetalRenderer {
|
||||||
pub fn new(is_opaque: bool) -> Self {
|
pub fn new(instance_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>) -> Self {
|
||||||
let device: metal::Device = if let Some(device) = metal::Device::system_default() {
|
let device: metal::Device = if let Some(device) = metal::Device::system_default() {
|
||||||
device
|
device
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,7 +58,7 @@ impl MetalRenderer {
|
||||||
layer.set_device(&device);
|
layer.set_device(&device);
|
||||||
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
|
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
|
||||||
layer.set_presents_with_transaction(true);
|
layer.set_presents_with_transaction(true);
|
||||||
layer.set_opaque(is_opaque);
|
layer.set_opaque(true);
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: () = msg_send![&*layer, setAllowsNextDrawableTimeout: NO];
|
let _: () = msg_send![&*layer, setAllowsNextDrawableTimeout: NO];
|
||||||
let _: () = msg_send![&*layer, setNeedsDisplayOnBoundsChange: YES];
|
let _: () = msg_send![&*layer, setNeedsDisplayOnBoundsChange: YES];
|
||||||
|
@ -181,7 +181,7 @@ impl MetalRenderer {
|
||||||
polychrome_sprites_pipeline_state,
|
polychrome_sprites_pipeline_state,
|
||||||
surfaces_pipeline_state,
|
surfaces_pipeline_state,
|
||||||
unit_vertices,
|
unit_vertices,
|
||||||
instance_buffers: Arc::default(),
|
instance_buffer_pool,
|
||||||
sprite_atlas,
|
sprite_atlas,
|
||||||
core_video_texture_cache,
|
core_video_texture_cache,
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut instance_buffer = self.instance_buffers.lock().pop().unwrap_or_else(|| {
|
let mut instance_buffer = self.instance_buffer_pool.lock().pop().unwrap_or_else(|| {
|
||||||
self.device.new_buffer(
|
self.device.new_buffer(
|
||||||
INSTANCE_BUFFER_SIZE as u64,
|
INSTANCE_BUFFER_SIZE as u64,
|
||||||
MTLResourceOptions::StorageModeManaged,
|
MTLResourceOptions::StorageModeManaged,
|
||||||
|
@ -227,7 +227,8 @@ impl MetalRenderer {
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
command_buffer,
|
command_buffer,
|
||||||
) else {
|
) else {
|
||||||
panic!("failed to rasterize {} paths", scene.paths().len());
|
log::error!("failed to rasterize {} paths", scene.paths().len());
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||||
|
@ -314,7 +315,7 @@ impl MetalRenderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
panic!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
|
log::error!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
|
||||||
scene.paths.len(),
|
scene.paths.len(),
|
||||||
scene.shadows.len(),
|
scene.shadows.len(),
|
||||||
scene.quads.len(),
|
scene.quads.len(),
|
||||||
|
@ -322,7 +323,8 @@ impl MetalRenderer {
|
||||||
scene.monochrome_sprites.len(),
|
scene.monochrome_sprites.len(),
|
||||||
scene.polychrome_sprites.len(),
|
scene.polychrome_sprites.len(),
|
||||||
scene.surfaces.len(),
|
scene.surfaces.len(),
|
||||||
)
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,11 +335,11 @@ impl MetalRenderer {
|
||||||
length: instance_offset as NSUInteger,
|
length: instance_offset as NSUInteger,
|
||||||
});
|
});
|
||||||
|
|
||||||
let instance_buffers = self.instance_buffers.clone();
|
let instance_buffer_pool = self.instance_buffer_pool.clone();
|
||||||
let instance_buffer = Cell::new(Some(instance_buffer));
|
let instance_buffer = Cell::new(Some(instance_buffer));
|
||||||
let block = ConcreteBlock::new(move |_| {
|
let block = ConcreteBlock::new(move |_| {
|
||||||
if let Some(instance_buffer) = instance_buffer.take() {
|
if let Some(instance_buffer) = instance_buffer.take() {
|
||||||
instance_buffers.lock().push(instance_buffer);
|
instance_buffer_pool.lock().push(instance_buffer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let block = block.copy();
|
let block = block.copy();
|
||||||
|
|
|
@ -146,6 +146,7 @@ pub(crate) struct MacPlatformState {
|
||||||
foreground_executor: ForegroundExecutor,
|
foreground_executor: ForegroundExecutor,
|
||||||
text_system: Arc<MacTextSystem>,
|
text_system: Arc<MacTextSystem>,
|
||||||
display_linker: MacDisplayLinker,
|
display_linker: MacDisplayLinker,
|
||||||
|
instance_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>,
|
||||||
pasteboard: id,
|
pasteboard: id,
|
||||||
text_hash_pasteboard_type: id,
|
text_hash_pasteboard_type: id,
|
||||||
metadata_pasteboard_type: id,
|
metadata_pasteboard_type: id,
|
||||||
|
@ -176,6 +177,7 @@ impl MacPlatform {
|
||||||
foreground_executor: ForegroundExecutor::new(dispatcher),
|
foreground_executor: ForegroundExecutor::new(dispatcher),
|
||||||
text_system: Arc::new(MacTextSystem::new()),
|
text_system: Arc::new(MacTextSystem::new()),
|
||||||
display_linker: MacDisplayLinker::new(),
|
display_linker: MacDisplayLinker::new(),
|
||||||
|
instance_buffer_pool: Arc::default(),
|
||||||
pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) },
|
pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) },
|
||||||
text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") },
|
text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") },
|
||||||
metadata_pasteboard_type: unsafe { ns_string("zed-metadata") },
|
metadata_pasteboard_type: unsafe { ns_string("zed-metadata") },
|
||||||
|
@ -494,7 +496,13 @@ impl Platform for MacPlatform {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Box<dyn PlatformWindow> {
|
) -> Box<dyn PlatformWindow> {
|
||||||
Box::new(MacWindow::open(handle, options, self.foreground_executor()))
|
let instance_buffer_pool = self.0.lock().instance_buffer_pool.clone();
|
||||||
|
Box::new(MacWindow::open(
|
||||||
|
handle,
|
||||||
|
options,
|
||||||
|
self.foreground_executor(),
|
||||||
|
instance_buffer_pool,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_display_link_output_callback(
|
fn set_display_link_output_callback(
|
||||||
|
|
|
@ -459,6 +459,7 @@ impl MacWindow {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
options: WindowOptions,
|
options: WindowOptions,
|
||||||
executor: ForegroundExecutor,
|
executor: ForegroundExecutor,
|
||||||
|
instance_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let pool = NSAutoreleasePool::new(nil);
|
let pool = NSAutoreleasePool::new(nil);
|
||||||
|
@ -535,7 +536,7 @@ impl MacWindow {
|
||||||
native_window,
|
native_window,
|
||||||
native_view: NonNull::new_unchecked(native_view as *mut _),
|
native_view: NonNull::new_unchecked(native_view as *mut _),
|
||||||
display_link,
|
display_link,
|
||||||
renderer: MetalRenderer::new(true),
|
renderer: MetalRenderer::new(instance_buffer_pool),
|
||||||
kind: options.kind,
|
kind: options.kind,
|
||||||
request_frame_callback: None,
|
request_frame_callback: None,
|
||||||
event_callback: None,
|
event_callback: None,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue