metal renderer: Increase instance buffer size dynamically (#11849)
Previously, we had an instance buffer pool that could only allocate buffers with a fixed size (hardcoded to 2mb). This caused certain scenes to render partially, e.g. when showing tens of thousands of glyphs on a big screen. With this commit, when `MetalRenderer` detects that a scene would be too large to render using the current instance buffer size, it will: - Clear the existing instance buffers - Allocate new instance buffers that are twice as large - Retry rendering the scene that failed with the newly-allocated buffers during the same frame. This fixes #11615. Release Notes: - Fixed rendering issues that could arise when having large amounts of text displayed on a large display. Fixed by dynamically increasing the size of the buffers used on the GPU. ([#11615](https://github.com/zed-industries/zed/issues/11615)). Before: https://github.com/zed-industries/zed/assets/1185253/464463be-b61c-4149-a417-01701699decb After: https://github.com/zed-industries/zed/assets/1185253/4feacf5a-d862-4a6b-90b8-317ac74e9851 Co-authored-by: Antonio <me@as-cii.com>
This commit is contained in:
parent
26ffdaffe2
commit
43d79af94a
1 changed files with 172 additions and 92 deletions
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
Hsla, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad,
|
Hsla, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad,
|
||||||
ScaledPixels, Scene, Shadow, Size, Surface, Underline,
|
ScaledPixels, Scene, Shadow, Size, Surface, Underline,
|
||||||
};
|
};
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use block::ConcreteBlock;
|
use block::ConcreteBlock;
|
||||||
use cocoa::{
|
use cocoa::{
|
||||||
base::{NO, YES},
|
base::{NO, YES},
|
||||||
|
@ -27,9 +28,8 @@ pub(crate) type PointF = crate::Point<f32>;
|
||||||
const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
||||||
#[cfg(feature = "runtime_shaders")]
|
#[cfg(feature = "runtime_shaders")]
|
||||||
const SHADERS_SOURCE_FILE: &str = include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal"));
|
const SHADERS_SOURCE_FILE: &str = include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal"));
|
||||||
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 type Context = Arc<Mutex<Vec<metal::Buffer>>>;
|
pub type Context = Arc<Mutex<InstanceBufferPool>>;
|
||||||
pub type Renderer = MetalRenderer;
|
pub type Renderer = MetalRenderer;
|
||||||
|
|
||||||
pub unsafe fn new_renderer(
|
pub unsafe fn new_renderer(
|
||||||
|
@ -42,6 +42,51 @@ pub unsafe fn new_renderer(
|
||||||
MetalRenderer::new(context)
|
MetalRenderer::new(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct InstanceBufferPool {
|
||||||
|
buffer_size: usize,
|
||||||
|
buffers: Vec<metal::Buffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InstanceBufferPool {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
buffer_size: 2 * 1024 * 1024,
|
||||||
|
buffers: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct InstanceBuffer {
|
||||||
|
metal_buffer: metal::Buffer,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceBufferPool {
|
||||||
|
pub(crate) fn reset(&mut self, buffer_size: usize) {
|
||||||
|
self.buffer_size = buffer_size;
|
||||||
|
self.buffers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn acquire(&mut self, device: &metal::Device) -> InstanceBuffer {
|
||||||
|
let buffer = self.buffers.pop().unwrap_or_else(|| {
|
||||||
|
device.new_buffer(
|
||||||
|
self.buffer_size as u64,
|
||||||
|
MTLResourceOptions::StorageModeManaged,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
InstanceBuffer {
|
||||||
|
metal_buffer: buffer,
|
||||||
|
size: self.buffer_size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn release(&mut self, buffer: InstanceBuffer) {
|
||||||
|
if buffer.size == self.buffer_size {
|
||||||
|
self.buffers.push(buffer.metal_buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct MetalRenderer {
|
pub(crate) struct MetalRenderer {
|
||||||
device: metal::Device,
|
device: metal::Device,
|
||||||
layer: metal::MetalLayer,
|
layer: metal::MetalLayer,
|
||||||
|
@ -57,13 +102,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_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>,
|
instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>,
|
||||||
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(instance_buffer_pool: Arc<Mutex<Vec<metal::Buffer>>>) -> Self {
|
pub fn new(instance_buffer_pool: Arc<Mutex<InstanceBufferPool>>) -> 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 {
|
||||||
|
@ -256,24 +301,74 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut instance_buffer = self.instance_buffer_pool.lock().pop().unwrap_or_else(|| {
|
|
||||||
self.device.new_buffer(
|
loop {
|
||||||
INSTANCE_BUFFER_SIZE as u64,
|
let mut instance_buffer = self.instance_buffer_pool.lock().acquire(&self.device);
|
||||||
MTLResourceOptions::StorageModeManaged,
|
|
||||||
)
|
let command_buffer =
|
||||||
});
|
self.draw_primitives(scene, &mut instance_buffer, drawable, viewport_size);
|
||||||
|
|
||||||
|
match command_buffer {
|
||||||
|
Ok(command_buffer) => {
|
||||||
|
let instance_buffer_pool = self.instance_buffer_pool.clone();
|
||||||
|
let instance_buffer = Cell::new(Some(instance_buffer));
|
||||||
|
let block = ConcreteBlock::new(move |_| {
|
||||||
|
if let Some(instance_buffer) = instance_buffer.take() {
|
||||||
|
instance_buffer_pool.lock().release(instance_buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let block = block.copy();
|
||||||
|
command_buffer.add_completed_handler(&block);
|
||||||
|
|
||||||
|
if self.presents_with_transaction {
|
||||||
|
command_buffer.commit();
|
||||||
|
command_buffer.wait_until_scheduled();
|
||||||
|
drawable.present();
|
||||||
|
} else {
|
||||||
|
command_buffer.present_drawable(drawable);
|
||||||
|
command_buffer.commit();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!(
|
||||||
|
"failed to render: {}. retrying with larger instance buffer size",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
let mut instance_buffer_pool = self.instance_buffer_pool.lock();
|
||||||
|
let buffer_size = instance_buffer_pool.buffer_size;
|
||||||
|
if buffer_size >= 256 * 1024 * 1024 {
|
||||||
|
log::error!("instance buffer size grew too large: {}", buffer_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instance_buffer_pool.reset(buffer_size * 2);
|
||||||
|
log::info!(
|
||||||
|
"increased instance buffer size to {}",
|
||||||
|
instance_buffer_pool.buffer_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_primitives(
|
||||||
|
&mut self,
|
||||||
|
scene: &Scene,
|
||||||
|
instance_buffer: &mut InstanceBuffer,
|
||||||
|
drawable: &metal::MetalDrawableRef,
|
||||||
|
viewport_size: Size<DevicePixels>,
|
||||||
|
) -> Result<metal::CommandBuffer> {
|
||||||
let command_queue = self.command_queue.clone();
|
let command_queue = self.command_queue.clone();
|
||||||
let command_buffer = command_queue.new_command_buffer();
|
let command_buffer = command_queue.new_command_buffer();
|
||||||
let mut instance_offset = 0;
|
let mut instance_offset = 0;
|
||||||
|
|
||||||
let Some(path_tiles) = self.rasterize_paths(
|
let Some(path_tiles) = self.rasterize_paths(
|
||||||
scene.paths(),
|
scene.paths(),
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
command_buffer,
|
command_buffer,
|
||||||
) else {
|
) else {
|
||||||
log::error!("failed to rasterize {} paths", scene.paths().len());
|
return Err(anyhow!("failed to rasterize {} paths", scene.paths().len()));
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||||
|
@ -302,14 +397,14 @@ impl MetalRenderer {
|
||||||
let ok = match batch {
|
let ok = match batch {
|
||||||
PrimitiveBatch::Shadows(shadows) => self.draw_shadows(
|
PrimitiveBatch::Shadows(shadows) => self.draw_shadows(
|
||||||
shadows,
|
shadows,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
),
|
),
|
||||||
PrimitiveBatch::Quads(quads) => self.draw_quads(
|
PrimitiveBatch::Quads(quads) => self.draw_quads(
|
||||||
quads,
|
quads,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
@ -317,14 +412,14 @@ impl MetalRenderer {
|
||||||
PrimitiveBatch::Paths(paths) => self.draw_paths(
|
PrimitiveBatch::Paths(paths) => self.draw_paths(
|
||||||
paths,
|
paths,
|
||||||
&path_tiles,
|
&path_tiles,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
),
|
),
|
||||||
PrimitiveBatch::Underlines(underlines) => self.draw_underlines(
|
PrimitiveBatch::Underlines(underlines) => self.draw_underlines(
|
||||||
underlines,
|
underlines,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
@ -335,7 +430,7 @@ impl MetalRenderer {
|
||||||
} => self.draw_monochrome_sprites(
|
} => self.draw_monochrome_sprites(
|
||||||
texture_id,
|
texture_id,
|
||||||
sprites,
|
sprites,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
@ -346,14 +441,14 @@ impl MetalRenderer {
|
||||||
} => self.draw_polychrome_sprites(
|
} => self.draw_polychrome_sprites(
|
||||||
texture_id,
|
texture_id,
|
||||||
sprites,
|
sprites,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
),
|
),
|
||||||
PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces(
|
PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces(
|
||||||
surfaces,
|
surfaces,
|
||||||
&mut instance_buffer,
|
instance_buffer,
|
||||||
&mut instance_offset,
|
&mut instance_offset,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
@ -361,7 +456,8 @@ impl MetalRenderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log::error!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
|
command_encoder.end_encoding();
|
||||||
|
return Err(anyhow!("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(),
|
||||||
|
@ -369,47 +465,28 @@ 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
command_encoder.end_encoding();
|
command_encoder.end_encoding();
|
||||||
|
|
||||||
instance_buffer.did_modify_range(NSRange {
|
instance_buffer.metal_buffer.did_modify_range(NSRange {
|
||||||
location: 0,
|
location: 0,
|
||||||
length: instance_offset as NSUInteger,
|
length: instance_offset as NSUInteger,
|
||||||
});
|
});
|
||||||
|
Ok(command_buffer.to_owned())
|
||||||
let instance_buffer_pool = self.instance_buffer_pool.clone();
|
|
||||||
let instance_buffer = Cell::new(Some(instance_buffer));
|
|
||||||
let block = ConcreteBlock::new(move |_| {
|
|
||||||
if let Some(instance_buffer) = instance_buffer.take() {
|
|
||||||
instance_buffer_pool.lock().push(instance_buffer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let block = block.copy();
|
|
||||||
command_buffer.add_completed_handler(&block);
|
|
||||||
|
|
||||||
self.sprite_atlas.clear_textures(AtlasTextureKind::Path);
|
|
||||||
|
|
||||||
if self.presents_with_transaction {
|
|
||||||
command_buffer.commit();
|
|
||||||
command_buffer.wait_until_scheduled();
|
|
||||||
drawable.present();
|
|
||||||
} else {
|
|
||||||
command_buffer.present_drawable(drawable);
|
|
||||||
command_buffer.commit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rasterize_paths(
|
fn rasterize_paths(
|
||||||
&mut self,
|
&mut self,
|
||||||
paths: &[Path<ScaledPixels>],
|
paths: &[Path<ScaledPixels>],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
command_buffer: &metal::CommandBufferRef,
|
command_buffer: &metal::CommandBufferRef,
|
||||||
) -> Option<HashMap<PathId, AtlasTile>> {
|
) -> Option<HashMap<PathId, AtlasTile>> {
|
||||||
|
self.sprite_atlas.clear_textures(AtlasTextureKind::Path);
|
||||||
|
|
||||||
let mut tiles = HashMap::default();
|
let mut tiles = HashMap::default();
|
||||||
let mut vertices_by_texture_id = HashMap::default();
|
let mut vertices_by_texture_id = HashMap::default();
|
||||||
for path in paths {
|
for path in paths {
|
||||||
|
@ -436,7 +513,7 @@ impl MetalRenderer {
|
||||||
align_offset(instance_offset);
|
align_offset(instance_offset);
|
||||||
let vertices_bytes_len = mem::size_of_val(vertices.as_slice());
|
let vertices_bytes_len = mem::size_of_val(vertices.as_slice());
|
||||||
let next_offset = *instance_offset + vertices_bytes_len;
|
let next_offset = *instance_offset + vertices_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +532,7 @@ impl MetalRenderer {
|
||||||
command_encoder.set_render_pipeline_state(&self.paths_rasterization_pipeline_state);
|
command_encoder.set_render_pipeline_state(&self.paths_rasterization_pipeline_state);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
PathRasterizationInputIndex::Vertices as u64,
|
PathRasterizationInputIndex::Vertices as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
let texture_size = Size {
|
let texture_size = Size {
|
||||||
|
@ -468,8 +545,9 @@ impl MetalRenderer {
|
||||||
&texture_size as *const Size<DevicePixels> as *const _,
|
&texture_size as *const Size<DevicePixels> as *const _,
|
||||||
);
|
);
|
||||||
|
|
||||||
let buffer_contents =
|
let buffer_contents = unsafe {
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
(instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset)
|
||||||
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(
|
||||||
vertices.as_ptr() as *const u8,
|
vertices.as_ptr() as *const u8,
|
||||||
|
@ -493,7 +571,7 @@ impl MetalRenderer {
|
||||||
fn draw_shadows(
|
fn draw_shadows(
|
||||||
&mut self,
|
&mut self,
|
||||||
shadows: &[Shadow],
|
shadows: &[Shadow],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -511,12 +589,12 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
ShadowInputIndex::Shadows as u64,
|
ShadowInputIndex::Shadows as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
ShadowInputIndex::Shadows as u64,
|
ShadowInputIndex::Shadows as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -528,10 +606,10 @@ impl MetalRenderer {
|
||||||
|
|
||||||
let shadow_bytes_len = mem::size_of_val(shadows);
|
let shadow_bytes_len = mem::size_of_val(shadows);
|
||||||
let buffer_contents =
|
let buffer_contents =
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
unsafe { (instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset) };
|
||||||
|
|
||||||
let next_offset = *instance_offset + shadow_bytes_len;
|
let next_offset = *instance_offset + shadow_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +634,7 @@ impl MetalRenderer {
|
||||||
fn draw_quads(
|
fn draw_quads(
|
||||||
&mut self,
|
&mut self,
|
||||||
quads: &[Quad],
|
quads: &[Quad],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -574,12 +652,12 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
QuadInputIndex::Quads as u64,
|
QuadInputIndex::Quads as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
QuadInputIndex::Quads as u64,
|
QuadInputIndex::Quads as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -591,10 +669,10 @@ impl MetalRenderer {
|
||||||
|
|
||||||
let quad_bytes_len = mem::size_of_val(quads);
|
let quad_bytes_len = mem::size_of_val(quads);
|
||||||
let buffer_contents =
|
let buffer_contents =
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
unsafe { (instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset) };
|
||||||
|
|
||||||
let next_offset = *instance_offset + quad_bytes_len;
|
let next_offset = *instance_offset + quad_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,7 +694,7 @@ impl MetalRenderer {
|
||||||
&mut self,
|
&mut self,
|
||||||
paths: &[Path<ScaledPixels>],
|
paths: &[Path<ScaledPixels>],
|
||||||
tiles_by_path_id: &HashMap<PathId, AtlasTile>,
|
tiles_by_path_id: &HashMap<PathId, AtlasTile>,
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -675,7 +753,7 @@ impl MetalRenderer {
|
||||||
|
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_bytes(
|
command_encoder.set_vertex_bytes(
|
||||||
|
@ -685,7 +763,7 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder
|
command_encoder
|
||||||
|
@ -693,12 +771,13 @@ impl MetalRenderer {
|
||||||
|
|
||||||
let sprite_bytes_len = mem::size_of_val(sprites.as_slice());
|
let sprite_bytes_len = mem::size_of_val(sprites.as_slice());
|
||||||
let next_offset = *instance_offset + sprite_bytes_len;
|
let next_offset = *instance_offset + sprite_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer_contents =
|
let buffer_contents = unsafe {
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
(instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset)
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(
|
||||||
|
@ -724,7 +803,7 @@ impl MetalRenderer {
|
||||||
fn draw_underlines(
|
fn draw_underlines(
|
||||||
&mut self,
|
&mut self,
|
||||||
underlines: &[Underline],
|
underlines: &[Underline],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -742,12 +821,12 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
UnderlineInputIndex::Underlines as u64,
|
UnderlineInputIndex::Underlines as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
UnderlineInputIndex::Underlines as u64,
|
UnderlineInputIndex::Underlines as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -759,10 +838,10 @@ impl MetalRenderer {
|
||||||
|
|
||||||
let underline_bytes_len = mem::size_of_val(underlines);
|
let underline_bytes_len = mem::size_of_val(underlines);
|
||||||
let buffer_contents =
|
let buffer_contents =
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
unsafe { (instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset) };
|
||||||
|
|
||||||
let next_offset = *instance_offset + underline_bytes_len;
|
let next_offset = *instance_offset + underline_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,7 +867,7 @@ impl MetalRenderer {
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
sprites: &[MonochromeSprite],
|
sprites: &[MonochromeSprite],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -798,6 +877,15 @@ impl MetalRenderer {
|
||||||
}
|
}
|
||||||
align_offset(instance_offset);
|
align_offset(instance_offset);
|
||||||
|
|
||||||
|
let sprite_bytes_len = mem::size_of_val(sprites);
|
||||||
|
let buffer_contents =
|
||||||
|
unsafe { (instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset) };
|
||||||
|
|
||||||
|
let next_offset = *instance_offset + sprite_bytes_len;
|
||||||
|
if next_offset > instance_buffer.size {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let texture = self.sprite_atlas.metal_texture(texture_id);
|
let texture = self.sprite_atlas.metal_texture(texture_id);
|
||||||
let texture_size = size(
|
let texture_size = size(
|
||||||
DevicePixels(texture.width() as i32),
|
DevicePixels(texture.width() as i32),
|
||||||
|
@ -811,7 +899,7 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_bytes(
|
command_encoder.set_vertex_bytes(
|
||||||
|
@ -826,20 +914,11 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture));
|
command_encoder.set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture));
|
||||||
|
|
||||||
let sprite_bytes_len = mem::size_of_val(sprites);
|
|
||||||
let buffer_contents =
|
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
|
||||||
|
|
||||||
let next_offset = *instance_offset + sprite_bytes_len;
|
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(
|
ptr::copy_nonoverlapping(
|
||||||
sprites.as_ptr() as *const u8,
|
sprites.as_ptr() as *const u8,
|
||||||
|
@ -862,7 +941,7 @@ impl MetalRenderer {
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
sprites: &[PolychromeSprite],
|
sprites: &[PolychromeSprite],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -885,7 +964,7 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_bytes(
|
command_encoder.set_vertex_bytes(
|
||||||
|
@ -900,17 +979,17 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_buffer(
|
command_encoder.set_fragment_buffer(
|
||||||
SpriteInputIndex::Sprites as u64,
|
SpriteInputIndex::Sprites as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture));
|
command_encoder.set_fragment_texture(SpriteInputIndex::AtlasTexture as u64, Some(&texture));
|
||||||
|
|
||||||
let sprite_bytes_len = mem::size_of_val(sprites);
|
let sprite_bytes_len = mem::size_of_val(sprites);
|
||||||
let buffer_contents =
|
let buffer_contents =
|
||||||
unsafe { (instance_buffer.contents() as *mut u8).add(*instance_offset) };
|
unsafe { (instance_buffer.metal_buffer.contents() as *mut u8).add(*instance_offset) };
|
||||||
|
|
||||||
let next_offset = *instance_offset + sprite_bytes_len;
|
let next_offset = *instance_offset + sprite_bytes_len;
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,7 +1014,7 @@ impl MetalRenderer {
|
||||||
fn draw_surfaces(
|
fn draw_surfaces(
|
||||||
&mut self,
|
&mut self,
|
||||||
surfaces: &[Surface],
|
surfaces: &[Surface],
|
||||||
instance_buffer: &mut metal::Buffer,
|
instance_buffer: &mut InstanceBuffer,
|
||||||
instance_offset: &mut usize,
|
instance_offset: &mut usize,
|
||||||
viewport_size: Size<DevicePixels>,
|
viewport_size: Size<DevicePixels>,
|
||||||
command_encoder: &metal::RenderCommandEncoderRef,
|
command_encoder: &metal::RenderCommandEncoderRef,
|
||||||
|
@ -990,13 +1069,13 @@ impl MetalRenderer {
|
||||||
|
|
||||||
align_offset(instance_offset);
|
align_offset(instance_offset);
|
||||||
let next_offset = *instance_offset + mem::size_of::<Surface>();
|
let next_offset = *instance_offset + mem::size_of::<Surface>();
|
||||||
if next_offset > INSTANCE_BUFFER_SIZE {
|
if next_offset > instance_buffer.size {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
command_encoder.set_vertex_buffer(
|
command_encoder.set_vertex_buffer(
|
||||||
SurfaceInputIndex::Surfaces as u64,
|
SurfaceInputIndex::Surfaces as u64,
|
||||||
Some(instance_buffer),
|
Some(&instance_buffer.metal_buffer),
|
||||||
*instance_offset as u64,
|
*instance_offset as u64,
|
||||||
);
|
);
|
||||||
command_encoder.set_vertex_bytes(
|
command_encoder.set_vertex_bytes(
|
||||||
|
@ -1014,7 +1093,8 @@ impl MetalRenderer {
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let buffer_contents = (instance_buffer.contents() as *mut u8).add(*instance_offset)
|
let buffer_contents = (instance_buffer.metal_buffer.contents() as *mut u8)
|
||||||
|
.add(*instance_offset)
|
||||||
as *mut SurfaceBounds;
|
as *mut SurfaceBounds;
|
||||||
ptr::write(
|
ptr::write(
|
||||||
buffer_contents,
|
buffer_contents,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue