mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #321
321: Update wgpu and use write_texture r=grovesNL a=kvark Depends on https://github.com/gfx-rs/wgpu/pull/666 Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
@@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"]
|
||||
package = "wgpu-core"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "a203333c3e144cfd431c812213966ee32ae59d98"
|
||||
rev = "4e1d76013c0b272383400beba48dc306e1a350f6"
|
||||
features = ["raw-window-handle"]
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "a203333c3e144cfd431c812213966ee32ae59d98"
|
||||
rev = "4e1d76013c0b272383400beba48dc306e1a350f6"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
|
||||
@@ -32,6 +32,7 @@ impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
// load (and compile) shaders and create shader modules
|
||||
|
||||
|
||||
@@ -76,14 +76,15 @@ async fn run() {
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &output_buffer,
|
||||
offset: 0,
|
||||
bytes_per_row: size_of::<u32>() as u32 * size,
|
||||
rows_per_image: 0,
|
||||
layout: wgpu::TextureDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: size_of::<u32>() as u32 * size,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
},
|
||||
texture_extent,
|
||||
);
|
||||
|
||||
@@ -115,12 +115,10 @@ impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
use std::mem;
|
||||
|
||||
let mut init_encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
// Create the vertex and index buffers
|
||||
let vertex_size = mem::size_of::<Vertex>();
|
||||
let (vertex_data, index_data) = create_vertices();
|
||||
@@ -180,21 +178,18 @@ impl framework::Example for Example {
|
||||
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
|
||||
});
|
||||
let texture_view = texture.create_default_view();
|
||||
let temp_buf =
|
||||
device.create_buffer_with_data(texels.as_slice(), wgpu::BufferUsage::COPY_SRC);
|
||||
init_encoder.copy_buffer_to_texture(
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &temp_buf,
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * size,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
queue.write_texture(
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
&texels,
|
||||
wgpu::TextureDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * size,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
texture_extent,
|
||||
);
|
||||
|
||||
@@ -304,7 +299,7 @@ impl framework::Example for Example {
|
||||
uniform_buf,
|
||||
pipeline,
|
||||
};
|
||||
(this, Some(init_encoder.finish()))
|
||||
(this, None)
|
||||
}
|
||||
|
||||
fn update(&mut self, _event: winit::event::WindowEvent) {
|
||||
@@ -319,7 +314,7 @@ impl framework::Example for Example {
|
||||
) {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
queue.write_buffer(bytemuck::cast_slice(mx_ref), &self.uniform_buf, 0);
|
||||
queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(mx_ref));
|
||||
}
|
||||
|
||||
fn render(
|
||||
|
||||
@@ -33,6 +33,7 @@ pub trait Example: 'static + Sized {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>);
|
||||
fn resize(
|
||||
&mut self,
|
||||
@@ -79,14 +80,7 @@ async fn run_async<E: Example>(event_loop: EventLoop<()>, window: Window) {
|
||||
},
|
||||
limits: wgpu::Limits::default(),
|
||||
},
|
||||
match trace_dir {
|
||||
Ok(ref value) if !cfg!(feature = "trace") => {
|
||||
log::error!("Unable to trace into {:?} without \"trace\" feature enabled!", value);
|
||||
None
|
||||
}
|
||||
Ok(ref value) => Some(std::path::Path::new(value)),
|
||||
Err(_) => None,
|
||||
},
|
||||
trace_dir.ok().as_ref().map(std::path::Path::new),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -106,7 +100,7 @@ async fn run_async<E: Example>(event_loop: EventLoop<()>, window: Window) {
|
||||
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||
|
||||
log::info!("Initializing the example...");
|
||||
let (mut example, init_command_buf) = E::init(&sc_desc, &device);
|
||||
let (mut example, init_command_buf) = E::init(&sc_desc, &device, &queue);
|
||||
if init_command_buf.is_some() {
|
||||
queue.submit(init_command_buf);
|
||||
}
|
||||
|
||||
@@ -211,6 +211,7 @@ impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
use std::mem;
|
||||
|
||||
@@ -275,19 +276,22 @@ impl framework::Example for Example {
|
||||
label: None,
|
||||
});
|
||||
let texture_view = texture.create_default_view();
|
||||
//Note: we could use queue.write_texture instead, and this is what other
|
||||
// examples do, but here we want to show another way to do this.
|
||||
let temp_buf =
|
||||
device.create_buffer_with_data(texels.as_slice(), wgpu::BufferUsage::COPY_SRC);
|
||||
init_encoder.copy_buffer_to_texture(
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &temp_buf,
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * size,
|
||||
rows_per_image: 0,
|
||||
layout: wgpu::TextureDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * size,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
},
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
},
|
||||
texture_extent,
|
||||
@@ -403,7 +407,7 @@ impl framework::Example for Example {
|
||||
) {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
queue.write_buffer(bytemuck::cast_slice(mx_ref), &self.uniform_buf, 0);
|
||||
queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(mx_ref));
|
||||
}
|
||||
|
||||
fn render(
|
||||
|
||||
@@ -116,6 +116,7 @@ impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
log::info!("Press left/right arrow keys to change sample_count.");
|
||||
let sample_count = 4;
|
||||
|
||||
@@ -208,6 +208,7 @@ impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
// Create the vertex and index buffers
|
||||
let vertex_size = mem::size_of::<Vertex>();
|
||||
@@ -674,9 +675,9 @@ impl framework::Example for Example {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
queue.write_buffer(
|
||||
bytemuck::cast_slice(mx_ref),
|
||||
&self.forward_pass.uniform_buf,
|
||||
0,
|
||||
bytemuck::cast_slice(mx_ref),
|
||||
);
|
||||
|
||||
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
@@ -716,16 +717,16 @@ impl framework::Example for Example {
|
||||
entity.color.a as f32,
|
||||
],
|
||||
};
|
||||
queue.write_buffer(bytemuck::bytes_of(&data), &entity.uniform_buf, 0);
|
||||
queue.write_buffer(&entity.uniform_buf, 0, bytemuck::bytes_of(&data));
|
||||
}
|
||||
|
||||
if self.lights_are_dirty {
|
||||
self.lights_are_dirty = false;
|
||||
for (i, light) in self.lights.iter().enumerate() {
|
||||
queue.write_buffer(
|
||||
bytemuck::bytes_of(&light.to_raw()),
|
||||
&self.light_uniform_buf,
|
||||
(i * mem::size_of::<LightRaw>()) as wgpu::BufferAddress,
|
||||
bytemuck::bytes_of(&light.to_raw()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,8 @@ impl framework::Example for Skybox {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
let mut init_encoder =
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
@@ -180,20 +178,21 @@ impl framework::Example for Skybox {
|
||||
image_width,
|
||||
image_height,
|
||||
);
|
||||
let image_buf = device.create_buffer_with_data(image, wgpu::BufferUsage::COPY_SRC);
|
||||
|
||||
init_encoder.copy_buffer_to_texture(
|
||||
wgpu::BufferCopyView {
|
||||
buffer: &image_buf,
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * image_width,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
queue.write_texture(
|
||||
wgpu::TextureCopyView {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
array_layer: i as u32,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
origin: wgpu::Origin3d {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: i as u32,
|
||||
},
|
||||
},
|
||||
&image,
|
||||
wgpu::TextureDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: 4 * image_width,
|
||||
rows_per_image: 0,
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: image_width,
|
||||
@@ -239,7 +238,7 @@ impl framework::Example for Skybox {
|
||||
aspect,
|
||||
uniforms,
|
||||
},
|
||||
Some(init_encoder.finish()),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -257,7 +256,7 @@ impl framework::Example for Skybox {
|
||||
let uniforms = Skybox::generate_uniforms(self.aspect);
|
||||
let mx_total = uniforms[0] * uniforms[1];
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
queue.write_buffer(bytemuck::cast_slice(mx_ref), &self.uniform_buf, 0);
|
||||
queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(mx_ref));
|
||||
}
|
||||
|
||||
fn render(
|
||||
@@ -270,9 +269,9 @@ impl framework::Example for Skybox {
|
||||
let rotation = cgmath::Matrix4::<f32>::from_angle_x(cgmath::Deg(0.25));
|
||||
self.uniforms[1] = self.uniforms[1] * rotation;
|
||||
queue.write_buffer(
|
||||
bytemuck::cast_slice(&raw_uniforms(&self.uniforms)),
|
||||
&self.uniform_buf,
|
||||
0,
|
||||
bytemuck::cast_slice(&raw_uniforms(&self.uniforms)),
|
||||
);
|
||||
|
||||
let mut encoder =
|
||||
|
||||
@@ -166,20 +166,17 @@ mod pass_impl {
|
||||
}
|
||||
}
|
||||
|
||||
fn map_buffer_copy_view(view: crate::BufferCopyView<'_>) -> wgc::command::BufferCopyView {
|
||||
fn map_buffer_copy_view(view: crate::BufferCopyView) -> wgc::command::BufferCopyView {
|
||||
wgc::command::BufferCopyView {
|
||||
buffer: view.buffer.id,
|
||||
offset: view.offset,
|
||||
bytes_per_row: view.bytes_per_row,
|
||||
rows_per_image: view.rows_per_image,
|
||||
layout: view.layout,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_texture_copy_view<'a>(view: crate::TextureCopyView<'a>) -> wgc::command::TextureCopyView {
|
||||
fn map_texture_copy_view(view: crate::TextureCopyView) -> wgc::command::TextureCopyView {
|
||||
wgc::command::TextureCopyView {
|
||||
texture: view.texture.id,
|
||||
mip_level: view.mip_level,
|
||||
array_layer: view.array_layer,
|
||||
origin: view.origin,
|
||||
}
|
||||
}
|
||||
@@ -764,7 +761,7 @@ impl crate::Context for Context {
|
||||
*encoder,
|
||||
&map_buffer_copy_view(source),
|
||||
&map_texture_copy_view(destination),
|
||||
copy_size
|
||||
©_size
|
||||
))
|
||||
}
|
||||
|
||||
@@ -779,7 +776,7 @@ impl crate::Context for Context {
|
||||
*encoder,
|
||||
&map_texture_copy_view(source),
|
||||
&map_buffer_copy_view(destination),
|
||||
copy_size
|
||||
©_size
|
||||
))
|
||||
}
|
||||
|
||||
@@ -794,7 +791,7 @@ impl crate::Context for Context {
|
||||
*encoder,
|
||||
&map_texture_copy_view(source),
|
||||
&map_texture_copy_view(destination),
|
||||
copy_size
|
||||
©_size
|
||||
))
|
||||
}
|
||||
|
||||
@@ -879,11 +876,28 @@ impl crate::Context for Context {
|
||||
fn queue_write_buffer(
|
||||
&self,
|
||||
queue: &Self::QueueId,
|
||||
data: &[u8],
|
||||
buffer: &Self::BufferId,
|
||||
offset: wgt::BufferAddress,
|
||||
data: &[u8],
|
||||
) {
|
||||
gfx_select!(*queue => self.queue_write_buffer(*queue, data, *buffer, offset))
|
||||
gfx_select!(*queue => self.queue_write_buffer(*queue, *buffer, offset, data))
|
||||
}
|
||||
|
||||
fn queue_write_texture(
|
||||
&self,
|
||||
queue: &Self::QueueId,
|
||||
texture: crate::TextureCopyView,
|
||||
data: &[u8],
|
||||
data_layout: wgt::TextureDataLayout,
|
||||
size: wgt::Extent3d,
|
||||
) {
|
||||
gfx_select!(*queue => self.queue_write_texture(
|
||||
*queue,
|
||||
&map_texture_copy_view(texture),
|
||||
data,
|
||||
&data_layout,
|
||||
&size
|
||||
))
|
||||
}
|
||||
|
||||
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
|
||||
|
||||
@@ -496,16 +496,15 @@ fn map_texture_view_dimension(
|
||||
}
|
||||
}
|
||||
|
||||
fn map_buffer_copy_view(view: crate::BufferCopyView<'_>) -> web_sys::GpuBufferCopyView {
|
||||
let mut mapped = web_sys::GpuBufferCopyView::new(&view.buffer.id.0, view.bytes_per_row);
|
||||
mapped.rows_per_image(view.rows_per_image);
|
||||
mapped.offset(view.offset as f64);
|
||||
fn map_buffer_copy_view(view: crate::BufferCopyView) -> web_sys::GpuBufferCopyView {
|
||||
let mut mapped = web_sys::GpuBufferCopyView::new(&view.buffer.id.0, view.layout.bytes_per_row);
|
||||
mapped.rows_per_image(view.layout.rows_per_image);
|
||||
mapped.offset(view.layout.offset as f64);
|
||||
mapped
|
||||
}
|
||||
|
||||
fn map_texture_copy_view<'a>(view: crate::TextureCopyView<'a>) -> web_sys::GpuTextureCopyView {
|
||||
fn map_texture_copy_view(view: crate::TextureCopyView) -> web_sys::GpuTextureCopyView {
|
||||
let mut mapped = web_sys::GpuTextureCopyView::new(&view.texture.id.0);
|
||||
mapped.array_layer(view.array_layer);
|
||||
mapped.mip_level(view.mip_level);
|
||||
mapped.origin(&map_origin_3d(view.origin));
|
||||
mapped
|
||||
@@ -1323,9 +1322,20 @@ impl crate::Context for Context {
|
||||
fn queue_write_buffer(
|
||||
&self,
|
||||
_queue: &Self::QueueId,
|
||||
_data: &[u8],
|
||||
_buffer: &Self::BufferId,
|
||||
_offset: wgt::BufferAddress,
|
||||
_data: &[u8],
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn queue_write_texture(
|
||||
&self,
|
||||
_queue: &Self::QueueId,
|
||||
_texture: crate::TextureCopyView,
|
||||
_data: &[u8],
|
||||
_data_layout: wgt::TextureDataLayout,
|
||||
_size: wgt::Extent3d,
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
45
src/lib.rs
45
src/lib.rs
@@ -23,8 +23,8 @@ pub use wgt::{
|
||||
Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp,
|
||||
Origin3d, PowerPreference, PresentMode, PrimitiveTopology, RasterizationStateDescriptor,
|
||||
ShaderLocation, ShaderStage, StencilOperation, StencilStateFaceDescriptor, StoreOp,
|
||||
SwapChainDescriptor, TextureAspect, TextureComponentType, TextureDimension, TextureFormat,
|
||||
TextureUsage, TextureViewDimension, VertexAttributeDescriptor, VertexFormat,
|
||||
SwapChainDescriptor, TextureAspect, TextureComponentType, TextureDataLayout, TextureDimension,
|
||||
TextureFormat, TextureUsage, TextureViewDimension, VertexAttributeDescriptor, VertexFormat,
|
||||
BIND_BUFFER_ALIGNMENT, MAX_BIND_GROUPS,
|
||||
};
|
||||
|
||||
@@ -291,9 +291,17 @@ trait Context: Sized {
|
||||
fn queue_write_buffer(
|
||||
&self,
|
||||
queue: &Self::QueueId,
|
||||
data: &[u8],
|
||||
buffer: &Self::BufferId,
|
||||
offset: BufferAddress,
|
||||
data: &[u8],
|
||||
);
|
||||
fn queue_write_texture(
|
||||
&self,
|
||||
queue: &Self::QueueId,
|
||||
texture: TextureCopyView,
|
||||
data: &[u8],
|
||||
data_layout: wgt::TextureDataLayout,
|
||||
size: wgt::Extent3d,
|
||||
);
|
||||
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
|
||||
&self,
|
||||
@@ -838,17 +846,8 @@ pub struct BufferCopyView<'a> {
|
||||
/// The buffer to be copied to or from.
|
||||
pub buffer: &'a Buffer,
|
||||
|
||||
/// The offset in bytes from the start of the buffer.
|
||||
/// In the future this must be aligned to 512 bytes, however the requirement is currently unimplemented.
|
||||
pub offset: BufferAddress,
|
||||
|
||||
/// The size in bytes of a single row of the texture.
|
||||
/// In the future this must be a multiple of 256 bytes, however the requirement is currently unimplemented.
|
||||
pub bytes_per_row: u32,
|
||||
|
||||
/// The height in texels of the imaginary texture view overlaid on the buffer.
|
||||
/// Must be zero for copies where `copy_size.depth == 1`.
|
||||
pub rows_per_image: u32,
|
||||
/// The layout of the texture data in this buffer.
|
||||
pub layout: wgt::TextureDataLayout,
|
||||
}
|
||||
|
||||
/// A view of a texture which can be used to copy to or from a buffer or another texture.
|
||||
@@ -860,9 +859,6 @@ pub struct TextureCopyView<'a> {
|
||||
/// The target mip level of the texture.
|
||||
pub mip_level: u32,
|
||||
|
||||
/// The target layer of the texture.
|
||||
pub array_layer: u32,
|
||||
|
||||
/// The base texel of the texture in the selected `mip_level`.
|
||||
pub origin: Origin3d,
|
||||
}
|
||||
@@ -1590,8 +1586,19 @@ impl<'a> Drop for ComputePass<'a> {
|
||||
|
||||
impl Queue {
|
||||
/// Schedule a data write into `buffer` starting at `offset`.
|
||||
pub fn write_buffer(&self, data: &[u8], buffer: &Buffer, offset: BufferAddress) {
|
||||
Context::queue_write_buffer(&*self.context, &self.id, data, &buffer.id, offset)
|
||||
pub fn write_buffer(&self, buffer: &Buffer, offset: BufferAddress, data: &[u8]) {
|
||||
Context::queue_write_buffer(&*self.context, &self.id, &buffer.id, offset, data)
|
||||
}
|
||||
|
||||
/// Schedule a data write into `texture`.
|
||||
pub fn write_texture(
|
||||
&self,
|
||||
texture: TextureCopyView,
|
||||
data: &[u8],
|
||||
data_layout: wgt::TextureDataLayout,
|
||||
size: wgt::Extent3d,
|
||||
) {
|
||||
Context::queue_write_texture(&*self.context, &self.id, texture, data, data_layout, size)
|
||||
}
|
||||
|
||||
/// Submits a series of finished command buffers for execution.
|
||||
|
||||
Reference in New Issue
Block a user