diff --git a/src/canvas/canvas_state.rs b/src/canvas/canvas_state.rs index d8e72467..aa92b0a7 100644 --- a/src/canvas/canvas_state.rs +++ b/src/canvas/canvas_state.rs @@ -27,7 +27,7 @@ use std::io::Read; use rusttype::{Font, PositionedGlyph, Scale, Rect, point, GlyphId, Line, Curve, Segment}; use vulkano::pipeline::vertex::{VertexDefinition, Vertex}; use crate::canvas::managed::shader::dynamic_vertex::RuntimeVertexDef; -use crate::canvas::managed::handles::{CanvasTextureHandle, CanvasImageHandle, CanvasFontHandle, CompiledShaderHandle, Handle, DrawableHandle}; +use crate::canvas::managed::handles::{CanvasTextureHandle, CanvasImageHandle, CanvasFontHandle, CompiledShaderHandle, Handle, DrawableHandle, CompuBufferHandle, CompuKernelHandle}; use crate::canvas::managed::gpu_buffers::{CanvasImage, CanvasTexture, CanvasFont}; use crate::canvas::managed::shader::shader_common::CompiledShader; use crate::canvas::managed::shader::generic_shader::GenericShader; @@ -35,6 +35,9 @@ use crate::VertexTypeContainer; use crate::util::vertex::{TextVertex3D, TextureVertex3D, ImageVertex3D, ColorVertex3D, CanvasFrameAllocation}; use shade_runner::Input; use winit::window::Window; +use crate::canvas::managed::compu_buffer::CompuBuffers; +use crate::canvas::managed::compu_kernel::CompuKernel; +use crate::canvas::compu_frame::CompuFrame; /// Canvas state is used for storage of texture and image buffers in addition to vertex buffers @@ -58,6 +61,9 @@ pub struct CanvasState { queue: Arc, device: Arc, render_pass: Arc, + + compute_buffers: Vec, + kernels: Vec, } @@ -133,6 +139,9 @@ impl CanvasState { CanvasState { + compute_buffers: vec![], + kernels: vec![], + // TODO: Might need to move this dynamic_state: DynamicState { line_width: None, @@ -167,6 +176,133 @@ impl CanvasState { } } + + + pub fn read_compute_buffer(&mut self, handle: Arc) -> Vec { + let mut buffer : &CompuBuffers = self.compute_buffers.get(handle.handle as usize).unwrap(); + let v = buffer.read_output_buffer(); + v.into_vec() + } + + /// Write to the compute buffer, ostensibly overwriting what's already there + pub fn write_compute_buffer(&self, handle: Arc, data: Vec) { + unimplemented!("read_compute_buffer is not implemented") + } + + pub fn new_kernel(&mut self, + filename: String, + device: Arc) -> Arc { + let handle = Arc::new(CompuKernelHandle { + handle: self.kernels.len() as u32 + }); + + self.kernels.push((CompuKernel::new(filename, device.clone(), handle.clone()))); + + handle + } + + pub fn get_kernel_handle(&self, kernel_name: String) -> Option> { + for i in self.kernels.clone() { + if i.get_name() == kernel_name { + return Some(i.get_handle()); + } + } + None + } + + pub fn compute_commands(&mut self, + compute_frame: &CompuFrame, + mut command_buffer: &mut AutoCommandBufferBuilder) { + + // i = (Buffer, Kernel) + for i in &compute_frame.pure_compute { + let buffer_id = (*i.0).clone().get_handle() as usize; + let kernel_id = (*i.1).clone().get_handle() as usize; + + let buffer = self.compute_buffers.get(buffer_id).unwrap(); + let kernel = self.kernels.get(kernel_id).unwrap(); + + let pipeline = kernel.clone().get_pipeline(); + let descriptorset = buffer.get_descriptor_set(kernel.clone().get_pipeline()); + + let size = buffer.get_size(); + + command_buffer = command_buffer + .dispatch([size.0 / 8, size.1 / 8, 1], pipeline, descriptorset, ()).unwrap() + } + + // i = (Buffer, Image, Kernel) + for i in &compute_frame.swapped_to_image { + let buffer_id = (*i.0).clone().get_handle() as usize; + let image_id = i.1.clone(); + let kernel_id = (*i.2).clone().handle as usize; + + let buffer = self.compute_buffers.get(buffer_id).unwrap(); + let image = self.get_image(image_id); + let kernel = self.kernels.get(kernel_id).unwrap(); + + let p = kernel.clone().get_pipeline(); + let d = buffer.get_descriptor_set(kernel.clone().get_pipeline()); + + let dimensions = image.dimensions(); + let dimensions = (dimensions.width(), dimensions.height()); + if dimensions != buffer.get_size() { + panic!("Buffer sizes not the same"); + } + + let size = buffer.get_size(); + + command_buffer = command_buffer + .dispatch([size.0 / 8, size.1 / 8, 1], p, d, ()).unwrap() + .copy_buffer_to_image(buffer.get_output_buffer(), image).unwrap(); + } + + + // i = (Input Buffer, Output Buffer, Kernel) + // Input buffer -> Kernel -> Output buffer + for i in &compute_frame.swapped_to_buffer { + let input_buffer_id = (*i.0).clone().get_handle() as usize; + let output_buffer_id = (*i.1).clone().get_handle() as usize; + let kernel_id = (*i.2).clone().handle as usize; + + let input_buffer = self.compute_buffers.get(input_buffer_id).unwrap(); + let output_buffer = self.compute_buffers.get(output_buffer_id).unwrap(); + let kernel = self.kernels.get(kernel_id).unwrap(); + + let pipeline = kernel.clone().get_pipeline(); + let descriptor_set = input_buffer.get_descriptor_set(kernel.clone().get_pipeline()); + + if input_buffer.get_size() != output_buffer.get_size() { + panic!("Buffer sizes not the same"); + } + let size = input_buffer.get_size(); + + command_buffer = command_buffer + // .dispatch([size.0/8, size.1/8,1], pipeline, descriptor_set, ()).unwrap() + .copy_buffer( + input_buffer.get_output_buffer(), + output_buffer.get_input_buffer()).unwrap(); + } + + } + + /// Creates a 2d compute buffer from incoming data + pub fn new_compute_buffer(&mut self, + data: Vec, + dimensions: (u32, u32), + stride: u32, + device: Arc) -> Arc { + + let handle = Arc::new(CompuBufferHandle { + handle: self.compute_buffers.len() as u32 + }); + + self.compute_buffers.push( + (CompuBuffers::new(device.clone(), data, dimensions, stride, handle.clone()))); + + handle + } + /// Using the dimensions and suggested usage, load a CanvasImage and return it's handle pub fn create_image(&mut self, dimensions: (u32, u32), usage: ImageUsage) -> Arc { let handle = Arc::new(CanvasImageHandle { handle: self.image_buffers.len() as u32 }); diff --git a/src/compute/compu_frame.rs b/src/canvas/compu_frame.rs similarity index 93% rename from src/compute/compu_frame.rs rename to src/canvas/compu_frame.rs index 9c1815f2..69a8c03b 100644 --- a/src/compute/compu_frame.rs +++ b/src/canvas/compu_frame.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::canvas::managed::handles::{CanvasImageHandle}; -use crate::compute::managed::handles::{CompuKernelHandle, CompuBufferHandle}; +use crate::canvas::managed::handles::{CanvasImageHandle, CompuBufferHandle}; +use crate::canvas::managed::handles::{CompuKernelHandle}; use crate::drawables::compu_sprite::CompuSprite; use crate::canvas::canvas_frame::Drawable; use crate::util::vertex::VertexTypeContainer; diff --git a/src/compute/managed/compu_buffer.rs b/src/canvas/managed/compu_buffer.rs similarity index 98% rename from src/compute/managed/compu_buffer.rs rename to src/canvas/managed/compu_buffer.rs index f8020ef5..a10c7c2f 100644 --- a/src/compute/managed/compu_buffer.rs +++ b/src/canvas/managed/compu_buffer.rs @@ -7,8 +7,8 @@ use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, PersistentDes use image::ImageBuffer; use image::Rgba; use shade_runner::Layout; -use crate::compute::managed::handles::CompuBufferHandle; use vulkano::descriptor::PipelineLayoutAbstract; +use crate::canvas::managed::handles::CompuBufferHandle; #[derive(Clone)] diff --git a/src/compute/managed/compu_kernel.rs b/src/canvas/managed/compu_kernel.rs similarity index 98% rename from src/compute/managed/compu_kernel.rs rename to src/canvas/managed/compu_kernel.rs index c3879a2a..75cf3ab9 100644 --- a/src/compute/managed/compu_kernel.rs +++ b/src/canvas/managed/compu_kernel.rs @@ -8,7 +8,7 @@ use vulkano::descriptor::pipeline_layout::PipelineLayout; use shade_runner::{CompileError, Layout, Input, Output, CompiledShaders, Entry, CompiledShader}; use shaderc::CompileOptions; use vulkano::pipeline::shader::{ShaderModule, GraphicsEntryPoint, SpecializationConstants, SpecializationMapEntry}; -use crate::compute::managed::handles::CompuKernelHandle; +use crate::canvas::managed::handles::CompuKernelHandle; #[derive(Clone)] diff --git a/src/canvas/managed/handles.rs b/src/canvas/managed/handles.rs index a1463830..9fca76da 100644 --- a/src/canvas/managed/handles.rs +++ b/src/canvas/managed/handles.rs @@ -57,4 +57,31 @@ impl Handle for CompiledShaderHandle { } } +/// Typed wrapper for a u32 handle +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +pub struct CompuBufferHandle { + pub(in crate::canvas) handle: u32, +} + +impl Handle for CompuBufferHandle { + fn get_handle(&self) -> u32 { + self.handle + } +} + +/// Typed wrapper for a u32 handle +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +pub struct CompuKernelHandle { + pub(in crate::canvas) handle: u32, +} + +impl Handle for CompuKernelHandle { + fn get_handle(&self) -> u32 { + self.handle + } +} + + + + diff --git a/src/canvas/managed/mod.rs b/src/canvas/managed/mod.rs index 682e852c..7b42beed 100644 --- a/src/canvas/managed/mod.rs +++ b/src/canvas/managed/mod.rs @@ -3,6 +3,8 @@ pub mod shader; pub mod handles; pub mod canvas_text; pub mod gpu_buffers; +pub mod compu_buffer; +pub mod compu_kernel; use vulkano::pipeline::shader::{SpecializationConstants, SpecializationMapEntry}; diff --git a/src/canvas/mod.rs b/src/canvas/mod.rs index 71f7215a..5443118d 100644 --- a/src/canvas/mod.rs +++ b/src/canvas/mod.rs @@ -2,5 +2,6 @@ pub mod canvas_state; pub mod canvas_frame; pub mod managed; +pub mod compu_frame; diff --git a/src/compute/compu_state.rs b/src/compute/compu_state.rs deleted file mode 100644 index cbeeea9c..00000000 --- a/src/compute/compu_state.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::ffi::CStr; -use vulkano::buffer::{CpuAccessibleBuffer, BufferUsage}; -use std::sync::Arc; -use vulkano::framebuffer::RenderPassAbstract; -use vulkano::pipeline::{GraphicsPipelineAbstract, ComputePipeline}; -use vulkano::device::Device; -use image::ImageBuffer; -use image::GenericImageView; -use vulkano::image::{ImageUsage, AttachmentImage}; -use vulkano::descriptor::descriptor_set::{PersistentDescriptorSetBuf, PersistentDescriptorSet}; -use vulkano::format::Format; -use vulkano::descriptor::pipeline_layout::PipelineLayout; -use std::borrow::Borrow; -use image::Rgba; -use vulkano::command_buffer::AutoCommandBufferBuilder; -use std::path::PathBuf; -use shade_runner::{CompiledShaders, Entry, CompileError}; -use vulkano::pipeline::shader::ShaderModule; -use shaderc::CompileOptions; -use crate::compute::compu_frame::CompuFrame; -use crate::canvas::managed::handles::Handle; -use crate::compute::managed::compu_buffer::CompuBuffers; -use crate::compute::managed::handles::{CompuKernelHandle, CompuBufferHandle}; -use crate::compute::managed::compu_kernel::CompuKernel; -use crate::canvas::canvas_state::CanvasState; - - -/// State holding the compute buffers for computation and the kernels which will compute them -pub struct CompuState { - compute_buffers: Vec, - kernels: Vec, -} - -impl CompuState { - - pub fn new() -> CompuState { - CompuState { - compute_buffers: vec![], - kernels: vec![], - } - } - - /// Creates a 2d compute buffer from incoming data - pub fn new_compute_buffer(&mut self, - data: Vec, - dimensions: (u32, u32), - stride: u32, - device: Arc) -> Arc { - - let handle = Arc::new(CompuBufferHandle { - handle: self.compute_buffers.len() as u32 - }); - - self.compute_buffers.push( - (CompuBuffers::new(device.clone(), data, dimensions, stride, handle.clone()))); - - handle - } - - pub fn read_compute_buffer(&mut self, handle: Arc) -> Vec { - let mut buffer : &CompuBuffers = self.compute_buffers.get(handle.handle as usize).unwrap(); - let v = buffer.read_output_buffer(); - v.into_vec() - } - - /// Write to the compute buffer, ostensibly overwriting what's already there - pub fn write_compute_buffer(&self, handle: Arc, data: Vec) { - unimplemented!("read_compute_buffer is not implemented") - } - - pub fn new_kernel(&mut self, - filename: String, - device: Arc) -> Arc { - let handle = Arc::new(CompuKernelHandle { - handle: self.kernels.len() as u32 - }); - - self.kernels.push((CompuKernel::new(filename, device.clone(), handle.clone()))); - - handle - } - - pub fn get_kernel_handle(&self, kernel_name: String) -> Option> { - for i in self.kernels.clone() { - if i.get_name() == kernel_name { - return Some(i.get_handle()); - } - } - None - } - - pub fn compute_commands(&mut self, - compute_frame: &CompuFrame, - mut command_buffer: &mut AutoCommandBufferBuilder, - canvas: &CanvasState) { - - // i = (Buffer, Kernel) - for i in &compute_frame.pure_compute { - let buffer_id = (*i.0).clone().get_handle() as usize; - let kernel_id = (*i.1).clone().get_handle() as usize; - - let buffer = self.compute_buffers.get(buffer_id).unwrap(); - let kernel = self.kernels.get(kernel_id).unwrap(); - - let pipeline = kernel.clone().get_pipeline(); - let descriptorset = buffer.get_descriptor_set(kernel.clone().get_pipeline()); - - let size = buffer.get_size(); - - command_buffer = command_buffer - .dispatch([size.0 / 8, size.1 / 8, 1], pipeline, descriptorset, ()).unwrap() - } - - // i = (Buffer, Image, Kernel) - for i in &compute_frame.swapped_to_image { - let buffer_id = (*i.0).clone().get_handle() as usize; - let image_id = i.1.clone(); - let kernel_id = (*i.2).clone().handle as usize; - - let buffer = self.compute_buffers.get(buffer_id).unwrap(); - let image = canvas.get_image(image_id); - let kernel = self.kernels.get(kernel_id).unwrap(); - - let p = kernel.clone().get_pipeline(); - let d = buffer.get_descriptor_set(kernel.clone().get_pipeline()); - - let dimensions = image.dimensions(); - let dimensions = (dimensions[0], dimensions[1]); - if dimensions != buffer.get_size() { - panic!("Buffer sizes not the same"); - } - - let size = buffer.get_size(); - - command_buffer = command_buffer - .dispatch([size.0 / 8, size.1 / 8, 1], p, d, ()).unwrap() - .copy_buffer_to_image(buffer.get_output_buffer(), image).unwrap(); - } - - - // i = (Input Buffer, Output Buffer, Kernel) - // Input buffer -> Kernel -> Output buffer - for i in &compute_frame.swapped_to_buffer { - let input_buffer_id = (*i.0).clone().get_handle() as usize; - let output_buffer_id = (*i.1).clone().get_handle() as usize; - let kernel_id = (*i.2).clone().handle as usize; - - let input_buffer = self.compute_buffers.get(input_buffer_id).unwrap(); - let output_buffer = self.compute_buffers.get(output_buffer_id).unwrap(); - let kernel = self.kernels.get(kernel_id).unwrap(); - - let pipeline = kernel.clone().get_pipeline(); - let descriptor_set = input_buffer.get_descriptor_set(kernel.clone().get_pipeline()); - - if input_buffer.get_size() != output_buffer.get_size() { - panic!("Buffer sizes not the same"); - } - let size = input_buffer.get_size(); - - command_buffer = command_buffer - // .dispatch([size.0/8, size.1/8,1], pipeline, descriptor_set, ()).unwrap() - .copy_buffer( - input_buffer.get_output_buffer(), - output_buffer.get_input_buffer()).unwrap(); - } - - } -} - diff --git a/src/compute/managed/handles.rs b/src/compute/managed/handles.rs deleted file mode 100644 index f5338cec..00000000 --- a/src/compute/managed/handles.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::canvas::managed::handles::Handle; - -/// Typed wrapper for a u32 handle -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct CompuBufferHandle { - pub(in crate::compute) handle: u32, -} - -impl Handle for CompuBufferHandle { - fn get_handle(&self) -> u32 { - self.handle - } -} - -/// Typed wrapper for a u32 handle -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct CompuKernelHandle { - pub(in crate::compute) handle: u32, -} - -impl Handle for CompuKernelHandle { - fn get_handle(&self) -> u32 { - self.handle - } -} - - - - diff --git a/src/compute/managed/mod.rs b/src/compute/managed/mod.rs deleted file mode 100644 index a34df75a..00000000 --- a/src/compute/managed/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ - -pub mod compu_buffer; -pub mod compu_kernel; -pub mod handles; \ No newline at end of file diff --git a/src/compute/mod.rs b/src/compute/mod.rs deleted file mode 100644 index 7503ae4b..00000000 --- a/src/compute/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod compu_frame; -pub mod compu_state; -pub mod managed; - -use crate::compute::compu_state::CompuState; -use crate::compute::compu_frame::CompuFrame; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a5aa9ee8..d3df48e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,8 +28,8 @@ use winit::window::WindowBuilder; use crate::canvas::canvas_frame::{CanvasFrame, Drawable, Eventable, Updatable}; use crate::canvas::canvas_state::CanvasState; use crate::canvas::managed::handles::{CanvasFontHandle, CanvasTextureHandle, Handle}; -use crate::compute::compu_frame::CompuFrame; -use crate::compute::managed::handles::{CompuBufferHandle, CompuKernelHandle}; +use canvas::compu_frame::CompuFrame; +use crate::canvas::managed::handles::{CompuBufferHandle, CompuKernelHandle}; use crate::drawables::compu_sprite::CompuSprite; use crate::drawables::rect::Rect; use crate::drawables::sprite::Sprite; @@ -45,7 +45,6 @@ pub mod util; pub mod vkprocessor; pub mod drawables; pub mod canvas; -pub mod compute; extern crate specs; @@ -102,10 +101,11 @@ impl<'a> System<'a> for RenderSystem { struct SysA; impl<'a> System<'a> for SysA { - // These are the resources required for execution. - // You can also define a struct and `#[derive(SystemData)]`, - // see the `full` example. - type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>); + + type SystemData = ( + WriteStorage<'a, Pos>, + ReadStorage<'a, Vel> + ); fn run(&mut self, (mut pos, vel): Self::SystemData) { // The `.join()` combines multiple components, @@ -198,8 +198,13 @@ pub fn main() { + // So I would have to go full in on the ECS in order to do rendering... + // That would probably look like a canvasFrame and compuFrame component which would + // be added to the world. + // Though canvasFrame and compuFrame have to share the command_buffer + // which means I should just keep the vk processor lol // The `World` is our // container for components diff --git a/src/vkprocessor.rs b/src/vkprocessor.rs index 926f2b6c..270aaa6c 100644 --- a/src/vkprocessor.rs +++ b/src/vkprocessor.rs @@ -7,9 +7,8 @@ use vulkano::sync; use std::sync::Arc; use vulkano::swapchain::{Swapchain, PresentMode, SurfaceTransform, Surface, SwapchainCreationError, AcquireError, Capabilities, FullscreenExclusive, ColorSpace}; use vulkano::image::swapchain::SwapchainImage; -use crate::compute::compu_state::CompuState; use vulkano::image::ImageUsage; -use crate::compute::compu_frame::CompuFrame; +use crate::canvas::compu_frame::CompuFrame; use crate::canvas::canvas_frame::{CanvasFrame}; use std::time::Duration; use vulkano::pipeline::depth_stencil::{DynamicStencilValue, StencilFaceFlags}; @@ -18,7 +17,7 @@ use crate::canvas::canvas_state::CanvasState; use crate::canvas::managed::shader::generic_shader::GenericShader; use crate::canvas::managed::shader::text_shader::TextShader; use crate::canvas::managed::handles::{CanvasTextureHandle, CompiledShaderHandle, CanvasFontHandle, CanvasImageHandle}; -use crate::compute::managed::handles::{CompuKernelHandle, CompuBufferHandle}; +use crate::canvas::managed::handles::{CompuKernelHandle, CompuBufferHandle}; use crate::util::vertex::{VertexTypeContainer, ColorVertex3D, TextVertex3D, TextureVertex3D, ImageVertex3D}; use vulkano_text::DrawText; use winit::window::{Window, WindowBuilder}; @@ -46,9 +45,6 @@ pub struct VkProcessor { /// State holding textures, images, and their related vertex buffers canvas_state: CanvasState, - /// State holding - compute_state: CompuState, - capabilities: Capabilities, } @@ -86,7 +82,6 @@ impl VkProcessor { swapchain: None, swapchain_images: None, swapchain_recreate_needed: false, - compute_state: CompuState::new(), capabilities: capabilities.clone(), canvas_state: CanvasState::new(queue, device, physical, capabilities), } @@ -170,8 +165,8 @@ impl VkProcessor { /// A hardcoded list of kernels which can be preloaded from this function pub fn preload_kernels(&mut self) { - self.compute_state.new_kernel(String::from("simple-homogenize.compute"), self.device.clone()); - self.compute_state.new_kernel(String::from("simple-edge.compute"), self.device.clone()); + self.canvas_state.new_kernel(String::from("simple-homogenize.compute"), self.device.clone()); + self.canvas_state.new_kernel(String::from("simple-edge.compute"), self.device.clone()); } /// A hardcoded list of shaders which can be preloaded from this function @@ -194,7 +189,7 @@ impl VkProcessor { /// O(n) Lookup for the matching kernel string pub fn get_kernel_handle(&self, kernel_name: String) -> Option> { - self.compute_state.get_kernel_handle(kernel_name) + self.canvas_state.get_kernel_handle(kernel_name) } /// O(n) Lookup for the matching shader string @@ -217,17 +212,17 @@ impl VkProcessor { /// Builds a compute buffer and returns it's handle pub fn new_compute_buffer(&mut self, data: Vec, dimensions: (u32, u32), stride: u32) -> Arc { - self.compute_state.new_compute_buffer(data, dimensions, stride, self.device.clone()) + self.canvas_state.new_compute_buffer(data, dimensions, stride, self.device.clone()) } /// Takes a compute buffer handle and returns the read data pub fn read_compute_buffer(&mut self, handle: Arc) -> Vec { - self.compute_state.read_compute_buffer(handle) + self.canvas_state.read_compute_buffer(handle) } /// Takes a compute buffer handle and writes the received data pub fn write_compute_buffer(&self, handle: Arc, data: Vec) { - self.compute_state.write_compute_buffer(handle, data) + self.canvas_state.write_compute_buffer(handle, data) } /// Run the VKprocessor for a single frame, consuming the Canvas/Compu Frames @@ -289,7 +284,7 @@ impl VkProcessor { let g = hprof::enter("Push compute commands to command buffer"); // Add the compute commands - self.compute_state.compute_commands(compute_frame, &mut command_buffer, &self.canvas_state); + self.canvas_state.compute_commands(compute_frame, &mut command_buffer); drop(g); let g = hprof::enter("Push draw commands to command buffer");