mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-18 18:08:07 +03:00
blade: Use BufferBelt from blade-utils (#12411)
Release Notes: - N/A Follow-up to #12340 Carries https://github.com/kvark/blade/pull/122 and https://github.com/kvark/blade/pull/119
This commit is contained in:
parent
c34d36161d
commit
44c50da94f
18
Cargo.lock
generated
18
Cargo.lock
generated
@ -1509,7 +1509,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "blade-graphics"
|
name = "blade-graphics"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/kvark/blade?rev=9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a#9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a"
|
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ash",
|
"ash",
|
||||||
"ash-window",
|
"ash-window",
|
||||||
@ -1539,13 +1539,24 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "blade-macros"
|
name = "blade-macros"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "git+https://github.com/kvark/blade?rev=9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a#9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a"
|
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.59",
|
"syn 2.0.59",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blade-util"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
|
||||||
|
dependencies = [
|
||||||
|
"blade-graphics",
|
||||||
|
"bytemuck",
|
||||||
|
"log",
|
||||||
|
"profiling",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block"
|
name = "block"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -3378,7 +3389,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.0",
|
"libloading 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4689,6 +4700,7 @@ dependencies = [
|
|||||||
"bindgen 0.65.1",
|
"bindgen 0.65.1",
|
||||||
"blade-graphics",
|
"blade-graphics",
|
||||||
"blade-macros",
|
"blade-macros",
|
||||||
|
"blade-util",
|
||||||
"block",
|
"block",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"calloop",
|
"calloop",
|
||||||
|
@ -262,8 +262,9 @@ async-tar = "0.4.2"
|
|||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
|
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
|
||||||
bitflags = "2.4.2"
|
bitflags = "2.4.2"
|
||||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" }
|
blade-graphics = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
|
||||||
blade-macros = { git = "https://github.com/kvark/blade", rev = "9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" }
|
blade-macros = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
|
||||||
|
blade-util = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
|
||||||
cap-std = "3.0"
|
cap-std = "3.0"
|
||||||
cargo_toml = "0.20"
|
cargo_toml = "0.20"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
@ -14,7 +14,7 @@ workspace = true
|
|||||||
default = []
|
default = []
|
||||||
test-support = ["backtrace", "collections/test-support", "util/test-support", "http/test-support"]
|
test-support = ["backtrace", "collections/test-support", "util/test-support", "http/test-support"]
|
||||||
runtime_shaders = []
|
runtime_shaders = []
|
||||||
macos-blade = ["blade-graphics", "blade-macros", "bytemuck"]
|
macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/gpui.rs"
|
path = "src/gpui.rs"
|
||||||
@ -26,6 +26,7 @@ async-task = "4.7"
|
|||||||
backtrace = { version = "0.3", optional = true }
|
backtrace = { version = "0.3", optional = true }
|
||||||
blade-graphics = { workspace = true, optional = true }
|
blade-graphics = { workspace = true, optional = true }
|
||||||
blade-macros = { workspace = true, optional = true }
|
blade-macros = { workspace = true, optional = true }
|
||||||
|
blade-util = { workspace = true, optional = true }
|
||||||
bytemuck = { version = "1", optional = true }
|
bytemuck = { version = "1", optional = true }
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
ctor.workspace = true
|
ctor.workspace = true
|
||||||
@ -96,6 +97,7 @@ flume = "0.11"
|
|||||||
#TODO: use these on all platforms
|
#TODO: use these on all platforms
|
||||||
blade-graphics.workspace = true
|
blade-graphics.workspace = true
|
||||||
blade-macros.workspace = true
|
blade-macros.workspace = true
|
||||||
|
blade-util.workspace = true
|
||||||
bytemuck = "1"
|
bytemuck = "1"
|
||||||
cosmic-text = "0.11.2"
|
cosmic-text = "0.11.2"
|
||||||
copypasta = "0.10.1"
|
copypasta = "0.10.1"
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
mod blade_atlas;
|
mod blade_atlas;
|
||||||
mod blade_belt;
|
|
||||||
mod blade_renderer;
|
mod blade_renderer;
|
||||||
|
|
||||||
pub(crate) use blade_atlas::*;
|
pub(crate) use blade_atlas::*;
|
||||||
pub(crate) use blade_renderer::*;
|
pub(crate) use blade_renderer::*;
|
||||||
|
|
||||||
use blade_belt::*;
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use super::{BladeBelt, BladeBeltDescriptor};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
||||||
Point, Size,
|
Point, Size,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use blade_graphics as gpu;
|
use blade_graphics as gpu;
|
||||||
|
use blade_util::{BufferBelt, BufferBeltDescriptor};
|
||||||
use collections::FxHashMap;
|
use collections::FxHashMap;
|
||||||
use etagere::BucketedAtlasAllocator;
|
use etagere::BucketedAtlasAllocator;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@ -22,7 +22,7 @@ struct PendingUpload {
|
|||||||
|
|
||||||
struct BladeAtlasState {
|
struct BladeAtlasState {
|
||||||
gpu: Arc<gpu::Context>,
|
gpu: Arc<gpu::Context>,
|
||||||
upload_belt: BladeBelt,
|
upload_belt: BufferBelt,
|
||||||
storage: BladeAtlasStorage,
|
storage: BladeAtlasStorage,
|
||||||
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
|
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
|
||||||
initializations: Vec<AtlasTextureId>,
|
initializations: Vec<AtlasTextureId>,
|
||||||
@ -48,7 +48,7 @@ impl BladeAtlas {
|
|||||||
pub(crate) fn new(gpu: &Arc<gpu::Context>) -> Self {
|
pub(crate) fn new(gpu: &Arc<gpu::Context>) -> Self {
|
||||||
BladeAtlas(Mutex::new(BladeAtlasState {
|
BladeAtlas(Mutex::new(BladeAtlasState {
|
||||||
gpu: Arc::clone(gpu),
|
gpu: Arc::clone(gpu),
|
||||||
upload_belt: BladeBelt::new(BladeBeltDescriptor {
|
upload_belt: BufferBelt::new(BufferBeltDescriptor {
|
||||||
memory: gpu::Memory::Upload,
|
memory: gpu::Memory::Upload,
|
||||||
min_chunk_size: 0x10000,
|
min_chunk_size: 0x10000,
|
||||||
alignment: 64, // Vulkan `optimalBufferCopyOffsetAlignment` on Intel XE
|
alignment: 64, // Vulkan `optimalBufferCopyOffsetAlignment` on Intel XE
|
||||||
@ -212,7 +212,7 @@ impl BladeAtlasState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upload_texture(&mut self, id: AtlasTextureId, bounds: Bounds<DevicePixels>, bytes: &[u8]) {
|
fn upload_texture(&mut self, id: AtlasTextureId, bounds: Bounds<DevicePixels>, bytes: &[u8]) {
|
||||||
let data = unsafe { self.upload_belt.alloc_data(bytes, &self.gpu) };
|
let data = self.upload_belt.alloc_bytes(bytes, &self.gpu);
|
||||||
self.uploads.push(PendingUpload { id, bounds, data });
|
self.uploads.push(PendingUpload { id, bounds, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
use blade_graphics as gpu;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
struct ReusableBuffer {
|
|
||||||
raw: gpu::Buffer,
|
|
||||||
size: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BladeBeltDescriptor {
|
|
||||||
pub memory: gpu::Memory,
|
|
||||||
pub min_chunk_size: u64,
|
|
||||||
pub alignment: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A belt of buffers, used by the BladeAtlas to cheaply
|
|
||||||
/// find staging space for uploads.
|
|
||||||
pub struct BladeBelt {
|
|
||||||
desc: BladeBeltDescriptor,
|
|
||||||
buffers: Vec<(ReusableBuffer, gpu::SyncPoint)>,
|
|
||||||
active: Vec<(ReusableBuffer, u64)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BladeBelt {
|
|
||||||
pub fn new(desc: BladeBeltDescriptor) -> Self {
|
|
||||||
assert_ne!(desc.alignment, 0);
|
|
||||||
Self {
|
|
||||||
desc,
|
|
||||||
buffers: Vec::new(),
|
|
||||||
active: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy(&mut self, gpu: &gpu::Context) {
|
|
||||||
for (buffer, _) in self.buffers.drain(..) {
|
|
||||||
gpu.destroy_buffer(buffer.raw);
|
|
||||||
}
|
|
||||||
for (buffer, _) in self.active.drain(..) {
|
|
||||||
gpu.destroy_buffer(buffer.raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[profiling::function]
|
|
||||||
pub fn alloc(&mut self, size: u64, gpu: &gpu::Context) -> gpu::BufferPiece {
|
|
||||||
for &mut (ref rb, ref mut offset) in self.active.iter_mut() {
|
|
||||||
let aligned = offset.next_multiple_of(self.desc.alignment);
|
|
||||||
if aligned + size <= rb.size {
|
|
||||||
let piece = rb.raw.at(aligned);
|
|
||||||
*offset = aligned + size;
|
|
||||||
return piece;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let index_maybe = self
|
|
||||||
.buffers
|
|
||||||
.iter()
|
|
||||||
.position(|(rb, sp)| size <= rb.size && gpu.wait_for(sp, 0));
|
|
||||||
if let Some(index) = index_maybe {
|
|
||||||
let (rb, _) = self.buffers.remove(index);
|
|
||||||
let piece = rb.raw.into();
|
|
||||||
self.active.push((rb, size));
|
|
||||||
return piece;
|
|
||||||
}
|
|
||||||
|
|
||||||
let chunk_index = self.buffers.len() + self.active.len();
|
|
||||||
let chunk_size = size.max(self.desc.min_chunk_size);
|
|
||||||
let chunk = gpu.create_buffer(gpu::BufferDesc {
|
|
||||||
name: &format!("chunk-{}", chunk_index),
|
|
||||||
size: chunk_size,
|
|
||||||
memory: self.desc.memory,
|
|
||||||
});
|
|
||||||
let rb = ReusableBuffer {
|
|
||||||
raw: chunk,
|
|
||||||
size: chunk_size,
|
|
||||||
};
|
|
||||||
self.active.push((rb, size));
|
|
||||||
chunk.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: T should be zeroable and ordinary data, no references, pointers, cells or other complicated data type.
|
|
||||||
pub unsafe fn alloc_data<T>(&mut self, data: &[T], gpu: &gpu::Context) -> gpu::BufferPiece {
|
|
||||||
assert!(!data.is_empty());
|
|
||||||
let type_alignment = mem::align_of::<T>() as u64;
|
|
||||||
debug_assert_eq!(
|
|
||||||
self.desc.alignment % type_alignment,
|
|
||||||
0,
|
|
||||||
"Type alignment {} is too big",
|
|
||||||
type_alignment
|
|
||||||
);
|
|
||||||
let total_bytes = std::mem::size_of_val(data);
|
|
||||||
let bp = self.alloc(total_bytes as u64, gpu);
|
|
||||||
unsafe {
|
|
||||||
std::ptr::copy_nonoverlapping(data.as_ptr() as *const u8, bp.data(), total_bytes);
|
|
||||||
}
|
|
||||||
bp
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(&mut self, sp: &gpu::SyncPoint) {
|
|
||||||
self.buffers
|
|
||||||
.extend(self.active.drain(..).map(|(rb, _)| (rb, sp.clone())));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
// Doing `if let` gives you nice scoping with passes/encoders
|
// Doing `if let` gives you nice scoping with passes/encoders
|
||||||
#![allow(irrefutable_let_patterns)]
|
#![allow(irrefutable_let_patterns)]
|
||||||
|
|
||||||
use super::{BladeAtlas, BladeBelt, BladeBeltDescriptor, PATH_TEXTURE_FORMAT};
|
use super::{BladeAtlas, PATH_TEXTURE_FORMAT};
|
||||||
use crate::{
|
use crate::{
|
||||||
AtlasTextureKind, AtlasTile, Bounds, ContentMask, Hsla, MonochromeSprite, Path, PathId,
|
AtlasTextureKind, AtlasTile, Bounds, ContentMask, Hsla, MonochromeSprite, Path, PathId,
|
||||||
PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size,
|
PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size,
|
||||||
@ -15,6 +15,7 @@ use media::core_video::CVMetalTextureCache;
|
|||||||
use std::{ffi::c_void, ptr::NonNull};
|
use std::{ffi::c_void, ptr::NonNull};
|
||||||
|
|
||||||
use blade_graphics as gpu;
|
use blade_graphics as gpu;
|
||||||
|
use blade_util::{BufferBelt, BufferBeltDescriptor};
|
||||||
use std::{mem, sync::Arc};
|
use std::{mem, sync::Arc};
|
||||||
|
|
||||||
const MAX_FRAME_TIME_MS: u32 = 1000;
|
const MAX_FRAME_TIME_MS: u32 = 1000;
|
||||||
@ -346,7 +347,7 @@ pub struct BladeRenderer {
|
|||||||
command_encoder: gpu::CommandEncoder,
|
command_encoder: gpu::CommandEncoder,
|
||||||
last_sync_point: Option<gpu::SyncPoint>,
|
last_sync_point: Option<gpu::SyncPoint>,
|
||||||
pipelines: BladePipelines,
|
pipelines: BladePipelines,
|
||||||
instance_belt: BladeBelt,
|
instance_belt: BufferBelt,
|
||||||
path_tiles: HashMap<PathId, AtlasTile>,
|
path_tiles: HashMap<PathId, AtlasTile>,
|
||||||
atlas: Arc<BladeAtlas>,
|
atlas: Arc<BladeAtlas>,
|
||||||
atlas_sampler: gpu::Sampler,
|
atlas_sampler: gpu::Sampler,
|
||||||
@ -371,7 +372,7 @@ impl BladeRenderer {
|
|||||||
buffer_count: 2,
|
buffer_count: 2,
|
||||||
});
|
});
|
||||||
let pipelines = BladePipelines::new(&gpu, surface_info);
|
let pipelines = BladePipelines::new(&gpu, surface_info);
|
||||||
let instance_belt = BladeBelt::new(BladeBeltDescriptor {
|
let instance_belt = BufferBelt::new(BufferBeltDescriptor {
|
||||||
memory: gpu::Memory::Shared,
|
memory: gpu::Memory::Shared,
|
||||||
min_chunk_size: 0x1000,
|
min_chunk_size: 0x1000,
|
||||||
alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe
|
alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe
|
||||||
@ -492,7 +493,7 @@ impl BladeRenderer {
|
|||||||
pad: 0,
|
pad: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vertex_buf = unsafe { self.instance_belt.alloc_data(&vertices, &self.gpu) };
|
let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) };
|
||||||
let mut pass = self.command_encoder.render(gpu::RenderTargetSet {
|
let mut pass = self.command_encoder.render(gpu::RenderTargetSet {
|
||||||
colors: &[gpu::RenderTarget {
|
colors: &[gpu::RenderTarget {
|
||||||
view: tex_info.raw_view,
|
view: tex_info.raw_view,
|
||||||
@ -557,7 +558,7 @@ impl BladeRenderer {
|
|||||||
match batch {
|
match batch {
|
||||||
PrimitiveBatch::Quads(quads) => {
|
PrimitiveBatch::Quads(quads) => {
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(quads, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(quads, &self.gpu) };
|
||||||
let mut encoder = pass.with(&self.pipelines.quads);
|
let mut encoder = pass.with(&self.pipelines.quads);
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
@ -570,7 +571,7 @@ impl BladeRenderer {
|
|||||||
}
|
}
|
||||||
PrimitiveBatch::Shadows(shadows) => {
|
PrimitiveBatch::Shadows(shadows) => {
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(shadows, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(shadows, &self.gpu) };
|
||||||
let mut encoder = pass.with(&self.pipelines.shadows);
|
let mut encoder = pass.with(&self.pipelines.shadows);
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
@ -598,7 +599,7 @@ impl BladeRenderer {
|
|||||||
}];
|
}];
|
||||||
|
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(&sprites, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(&sprites, &self.gpu) };
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
&ShaderPathsData {
|
&ShaderPathsData {
|
||||||
@ -613,7 +614,7 @@ impl BladeRenderer {
|
|||||||
}
|
}
|
||||||
PrimitiveBatch::Underlines(underlines) => {
|
PrimitiveBatch::Underlines(underlines) => {
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(underlines, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(underlines, &self.gpu) };
|
||||||
let mut encoder = pass.with(&self.pipelines.underlines);
|
let mut encoder = pass.with(&self.pipelines.underlines);
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
@ -630,7 +631,7 @@ impl BladeRenderer {
|
|||||||
} => {
|
} => {
|
||||||
let tex_info = self.atlas.get_texture_info(texture_id);
|
let tex_info = self.atlas.get_texture_info(texture_id);
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(sprites, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) };
|
||||||
let mut encoder = pass.with(&self.pipelines.mono_sprites);
|
let mut encoder = pass.with(&self.pipelines.mono_sprites);
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
@ -649,7 +650,7 @@ impl BladeRenderer {
|
|||||||
} => {
|
} => {
|
||||||
let tex_info = self.atlas.get_texture_info(texture_id);
|
let tex_info = self.atlas.get_texture_info(texture_id);
|
||||||
let instance_buf =
|
let instance_buf =
|
||||||
unsafe { self.instance_belt.alloc_data(sprites, &self.gpu) };
|
unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) };
|
||||||
let mut encoder = pass.with(&self.pipelines.poly_sprites);
|
let mut encoder = pass.with(&self.pipelines.poly_sprites);
|
||||||
encoder.bind(
|
encoder.bind(
|
||||||
0,
|
0,
|
||||||
|
Loading…
Reference in New Issue
Block a user