From 5e29b17cf0475d3cbfe77cf1f0517efcc4f176a4 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 5 Jul 2019 21:31:44 -0400 Subject: [PATCH 1/2] WIP new GPU API --- gpu/src/lib.rs | 124 ++++++++++++++++++++++++++----------------------- ui/src/lib.rs | 20 ++++---- 2 files changed, 78 insertions(+), 66 deletions(-) diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 16e101917..e01bb52b2 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -21,41 +21,81 @@ use std::time::Duration; pub mod resources; +pub trait Encoder { + fn draw_arrays(&mut self, index_count: u32, render_state: &RenderState); + fn draw_elements(&mut self, index_count: u32, render_state: &RenderState); + fn draw_elements_instanced(&mut self, + index_count: u32, + instance_count: u32, + render_state: &RenderState); + fn begin_timer_query(&mut self, query: &D::TimerQuery); + fn end_timer_query(&mut self, query: &D::TimerQuery); +} + pub trait Device: Sized { type Buffer; type Framebuffer; - type Program; + type Pipeline; type Shader; type Texture; type TimerQuery; type Uniform; - type VertexArray; - type VertexAttr; + type Encoder: Encoder; fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture; fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture; + fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { + let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); + let image = image::load_from_memory_with_format(&data, ImageFormat::PNG) + .unwrap() + .to_luma(); + let size = Vector2I::new(image.width() as i32, image.height() as i32); + self.create_texture_from_data(size, &image) + } + fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) -> Self::Shader; fn create_shader_from_source(&self, name: &str, source: &[u8], kind: ShaderKind) -> Self::Shader; - fn create_vertex_array(&self) -> Self::VertexArray; - fn create_program_from_shaders( + fn create_pipeline_from_shaders( &self, resources: &dyn ResourceLoader, name: &str, vertex_shader: Self::Shader, fragment_shader: Self::Shader, - ) -> Self::Program; - fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; - fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; + options: RenderOptions, + vertex_buffers: &[VertexBufferDescriptor], + ) -> Self::Pipeline; + fn create_pipeline_from_shader_names( + &self, + resources: &dyn ResourceLoader, + program_name: &str, + vertex_shader_name: &str, + fragment_shader_name: &str, + options: RenderOptions, + vertex_buffers: &[VertexBufferDescriptor], + ) -> Self::Pipeline { + let vertex_shader = self.create_shader(resources, vertex_shader_name, ShaderKind::Vertex); + let fragment_shader = + self.create_shader(resources, fragment_shader_name, ShaderKind::Fragment); + self.create_pipeline_from_shaders( + resources, program_name, vertex_shader, fragment_shader, options, vertex_buffers + ) + } + fn create_pipeline( + &self, + resources: &dyn ResourceLoader, + name: &str, + options: RenderOptions, + vertex_buffers: &[VertexBufferDescriptor], + ) -> Self::Pipeline { + self.create_pipeline_from_shader_names(resources, name, name, name, options, vertex_buffers) + } + + fn bind_buffer(&self, - vertex_array: &Self::VertexArray, buffer: &Self::Buffer, target: BufferTarget); - fn configure_vertex_attr(&self, - vertex_array: &Self::VertexArray, - attr: &Self::VertexAttr, - descriptor: &VertexAttrDescriptor); fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer; fn create_buffer(&self) -> Self::Buffer; fn allocate_buffer( @@ -65,48 +105,12 @@ pub trait Device: Sized { target: BufferTarget, mode: BufferUploadMode, ); - fn framebuffer_texture<'f>(&self, framebuffer: &'f Self::Framebuffer) -> &'f Self::Texture; - fn texture_size(&self, texture: &Self::Texture) -> Vector2I; fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]); fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData; - fn begin_commands(&self); - fn end_commands(&self); - fn draw_arrays(&self, index_count: u32, render_state: &RenderState); - fn draw_elements(&self, index_count: u32, render_state: &RenderState); - fn draw_elements_instanced(&self, - index_count: u32, - instance_count: u32, - render_state: &RenderState); + fn begin_commands(&self) -> Self::Encoder; + fn end_commands(&self, encoder: Self::Encoder); fn create_timer_query(&self) -> Self::TimerQuery; - fn begin_timer_query(&self, query: &Self::TimerQuery); - fn end_timer_query(&self, query: &Self::TimerQuery); fn get_timer_query(&self, query: &Self::TimerQuery) -> Option; - - fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { - let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); - let image = image::load_from_memory_with_format(&data, ImageFormat::PNG) - .unwrap() - .to_luma(); - let size = Vector2I::new(image.width() as i32, image.height() as i32); - self.create_texture_from_data(size, &image) - } - - fn create_program_from_shader_names( - &self, - resources: &dyn ResourceLoader, - program_name: &str, - vertex_shader_name: &str, - fragment_shader_name: &str, - ) -> Self::Program { - let vertex_shader = self.create_shader(resources, vertex_shader_name, ShaderKind::Vertex); - let fragment_shader = - self.create_shader(resources, fragment_shader_name, ShaderKind::Fragment); - self.create_program_from_shaders(resources, program_name, vertex_shader, fragment_shader) - } - - fn create_program(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Program { - self.create_program_from_shader_names(resources, name, name, name) - } } #[derive(Clone, Copy, Debug, PartialEq)] @@ -133,7 +137,7 @@ pub enum BufferData<'a, T> { #[derive(Clone, Copy, Debug)] pub enum BufferTarget { - Vertex, + Vertex(i8), Index, } @@ -167,13 +171,12 @@ pub enum Primitive { #[derive(Clone)] pub struct RenderState<'a, D> where D: Device { pub target: &'a RenderTarget<'a, D>, - pub program: &'a D::Program, - pub vertex_array: &'a D::VertexArray, + pub pipeline: &'a D::Pipeline, + pub vertex_buffers: &'a [D::Buffer], pub primitive: Primitive, pub uniforms: &'a [(&'a D::Uniform, UniformData)], pub textures: &'a [&'a D::Texture], pub viewport: RectI, - pub options: RenderOptions, } #[derive(Clone, Debug)] @@ -291,15 +294,20 @@ impl UniformData { } } +#[derive(Clone, Debug)] +pub struct VertexBufferDescriptor { + pub size: usize, + pub stride: usize, + pub divisor: u32, + pub attributes: Vec, +} + #[derive(Clone, Copy, Debug)] pub struct VertexAttrDescriptor { pub size: usize, pub class: VertexAttrClass, pub attr_type: VertexAttrType, - pub stride: usize, pub offset: usize, - pub divisor: u32, - pub buffer_index: u32, } #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 377cb1ed7..d7633ceba 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -123,16 +123,17 @@ impl UIPresenter where D: Device { } - pub fn draw_solid_rect(&self, device: &D, rect: RectI, color: ColorU) { - self.draw_rect(device, rect, color, true); + pub fn draw_solid_rect(&self, device: &D::Device, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + encoder.draw_rect(device, encoder, rect, color, true); } - pub fn draw_rect_outline(&self, device: &D, rect: RectI, color: ColorU) { - self.draw_rect(device, rect, color, false); + pub fn draw_rect_outline(&self, device: &D::Device, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + encoder.draw_rect(device, encoder, rect, color, false); } fn draw_rect(&self, - device: &D, + device: &D::Device, + encoder: &mut D::Encoder, rect: RectI, color: ColorU, filled: bool) { @@ -145,12 +146,14 @@ impl UIPresenter where D: Device { if filled { self.draw_solid_rects_with_vertex_data(device, + encoder, &vertex_data, &QUAD_INDICES, color, true); } else { self.draw_solid_rects_with_vertex_data(device, + encoder, &vertex_data, &RECT_LINE_INDICES, color, @@ -160,6 +163,7 @@ impl UIPresenter where D: Device { fn draw_solid_rects_with_vertex_data(&self, device: &D, + encoder: &mut D::Encoder, vertex_data: &[DebugSolidVertex], index_data: &[u32], color: ColorU, @@ -174,10 +178,10 @@ impl UIPresenter where D: Device { BufferUploadMode::Dynamic); let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; - device.draw_elements(index_data.len() as u32, &RenderState { + encoder.draw_elements(index_data.len() as u32, &RenderState { target: &RenderTarget::Default, - program: &self.solid_program.program, - vertex_array: &self.solid_vertex_array.vertex_array, + pipeline: &self.solid_program.program, + vertex_buffers: &self.solid_vertex_array.vertex_array, primitive, uniforms: &[ (&self.solid_program.framebuffer_size_uniform, From 565cb2cacb3955ce5079741c99262ef0ac4c3360 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 5 Jul 2019 22:14:05 -0400 Subject: [PATCH 2/2] Mostly ported UI --- gpu/src/lib.rs | 35 +---- ui/src/lib.rs | 352 ++++++++++++++++++++++++------------------------- 2 files changed, 176 insertions(+), 211 deletions(-) diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index e01bb52b2..9ac425104 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -44,13 +44,15 @@ pub trait Device: Sized { fn create_texture(&self, format: TextureFormat, size: Vector2I) -> Self::Texture; fn create_texture_from_data(&self, size: Vector2I, data: &[u8]) -> Self::Texture; - fn create_texture_from_png(&self, resources: &dyn ResourceLoader, name: &str) -> Self::Texture { + fn create_texture_from_png( + &self, resources: &dyn ResourceLoader, name: &str + ) -> (Self::Texture, Vector2I) { let data = resources.slurp(&format!("textures/{}.png", name)).unwrap(); let image = image::load_from_memory_with_format(&data, ImageFormat::PNG) .unwrap() .to_luma(); let size = Vector2I::new(image.width() as i32, image.height() as i32); - self.create_texture_from_data(size, &image) + (self.create_texture_from_data(size, &image), size) } fn create_shader(&self, resources: &dyn ResourceLoader, name: &str, kind: ShaderKind) @@ -92,19 +94,8 @@ pub trait Device: Sized { self.create_pipeline_from_shader_names(resources, name, name, name, options, vertex_buffers) } - - fn bind_buffer(&self, - buffer: &Self::Buffer, - target: BufferTarget); fn create_framebuffer(&self, texture: Self::Texture) -> Self::Framebuffer; - fn create_buffer(&self) -> Self::Buffer; - fn allocate_buffer( - &self, - buffer: &Self::Buffer, - data: BufferData, - target: BufferTarget, - mode: BufferUploadMode, - ); + fn create_buffer(&self, data: BufferData) -> Self::Buffer; fn upload_to_texture(&self, texture: &Self::Texture, size: Vector2I, data: &[u8]); fn read_pixels(&self, target: &RenderTarget, viewport: RectI) -> TextureData; fn begin_commands(&self) -> Self::Encoder; @@ -135,18 +126,6 @@ pub enum BufferData<'a, T> { Memory(&'a [T]), } -#[derive(Clone, Copy, Debug)] -pub enum BufferTarget { - Vertex(i8), - Index, -} - -#[derive(Clone, Copy, Debug)] -pub enum BufferUploadMode { - Static, - Dynamic, -} - #[derive(Clone, Copy, Debug, PartialEq)] pub enum ShaderKind { Vertex, @@ -172,7 +151,8 @@ pub enum Primitive { pub struct RenderState<'a, D> where D: Device { pub target: &'a RenderTarget<'a, D>, pub pipeline: &'a D::Pipeline, - pub vertex_buffers: &'a [D::Buffer], + pub index_buffer: Option<&'a D::Buffer>, + pub vertex_buffers: &'a [&'a D::Buffer], pub primitive: Primitive, pub uniforms: &'a [(&'a D::Uniform, UniformData)], pub textures: &'a [&'a D::Texture], @@ -296,7 +276,6 @@ impl UniformData { #[derive(Clone, Debug)] pub struct VertexBufferDescriptor { - pub size: usize, pub stride: usize, pub divisor: u32, pub attributes: Vec, diff --git a/ui/src/lib.rs b/ui/src/lib.rs index d7633ceba..3f6820aec 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -21,9 +21,9 @@ use pathfinder_content::color::ColorU; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_gpu::resources::ResourceLoader; -use pathfinder_gpu::{BlendState, BufferData, BufferTarget, BufferUploadMode, Device, Primitive}; +use pathfinder_gpu::{BlendState, BufferData, Device, Encoder, Primitive}; use pathfinder_gpu::{RenderOptions, RenderState, RenderTarget, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType, VertexBufferDescriptor}; use pathfinder_simd::default::F32x4; use serde_json; use std::mem; @@ -70,31 +70,28 @@ pub struct UIPresenter where D: Device { framebuffer_size: Vector2I, - texture_program: DebugTextureProgram, - texture_vertex_array: DebugTextureVertexArray, - solid_program: DebugSolidProgram, - solid_vertex_array: DebugSolidVertexArray, - font: DebugFont, + texture_pipeline: DebugTexturePipeline, + solid_pipeline: DebugSolidPipeline, + font: DebugFont, font_texture: D::Texture, + font_size: Vector2I, + corner_fill_texture: D::Texture, + corner_fill_size: Vector2I, corner_outline_texture: D::Texture, + corner_outline_size: Vector2I, } impl UIPresenter where D: Device { pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Vector2I) -> UIPresenter { - let texture_program = DebugTextureProgram::new(device, resources); - let texture_vertex_array = DebugTextureVertexArray::new(device, &texture_program); let font = DebugFont::load(resources); - - let solid_program = DebugSolidProgram::new(device, resources); - let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program); - - let font_texture = device.create_texture_from_png(resources, FONT_PNG_NAME); - let corner_fill_texture = device.create_texture_from_png(resources, CORNER_FILL_PNG_NAME); - let corner_outline_texture = device.create_texture_from_png(resources, - CORNER_OUTLINE_PNG_NAME); + let (font_texture, font_size) = device.create_texture_from_png(resources, FONT_PNG_NAME); + let (corner_fill_texture, corner_fill_size) = device.create_texture_from_png(resources, + CORNER_FILL_PNG_NAME); + let (corner_outline_texture, corner_outline_size) = device.create_texture_from_png(resources, + CORNER_OUTLINE_PNG_NAME); UIPresenter { event_queue: UIEventQueue::new(), @@ -102,15 +99,17 @@ impl UIPresenter where D: Device { framebuffer_size, - texture_program, - texture_vertex_array, - font, - solid_program, - solid_vertex_array, + texture_pipeline: DebugTexturePipeline::new(device, resources), + solid_pipeline: DebugSolidPipeline::new(device, resources), + font, font_texture, + font_size, + corner_fill_texture, + corner_fill_size, corner_outline_texture, + corner_outline_size, } } @@ -123,16 +122,16 @@ impl UIPresenter where D: Device { } - pub fn draw_solid_rect(&self, device: &D::Device, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { - encoder.draw_rect(device, encoder, rect, color, true); + pub fn draw_solid_rect(&self, device: &D, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + self.draw_rect(device, encoder, rect, color, true); } - pub fn draw_rect_outline(&self, device: &D::Device, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { - encoder.draw_rect(device, encoder, rect, color, false); + pub fn draw_rect_outline(&self, device: &D, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + self.draw_rect(device, encoder, rect, color, false); } fn draw_rect(&self, - device: &D::Device, + device: &D, encoder: &mut D::Encoder, rect: RectI, color: ColorU, @@ -168,36 +167,27 @@ impl UIPresenter where D: Device { index_data: &[u32], color: ColorU, filled: bool) { - device.allocate_buffer(&self.solid_vertex_array.vertex_buffer, - BufferData::Memory(vertex_data), - BufferTarget::Vertex, - BufferUploadMode::Dynamic); - device.allocate_buffer(&self.solid_vertex_array.index_buffer, - BufferData::Memory(index_data), - BufferTarget::Index, - BufferUploadMode::Dynamic); + let vertex_buffer = device.create_buffer(BufferData::Memory(vertex_data)); + let index_buffer = device.create_buffer(BufferData::Memory(index_data)); let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; encoder.draw_elements(index_data.len() as u32, &RenderState { target: &RenderTarget::Default, - pipeline: &self.solid_program.program, - vertex_buffers: &self.solid_vertex_array.vertex_array, + pipeline: &self.solid_pipeline.pipeline, + index_buffer: Some(&index_buffer), + vertex_buffers: &[&vertex_buffer], primitive, uniforms: &[ - (&self.solid_program.framebuffer_size_uniform, + (&self.solid_pipeline.framebuffer_size_uniform, UniformData::Vec2(self.framebuffer_size.0.to_f32x2())), - (&self.solid_program.color_uniform, get_color_uniform(color)), + (&self.solid_pipeline.color_uniform, get_color_uniform(color)), ], textures: &[], viewport: RectI::new(Vector2I::default(), self.framebuffer_size), - options: RenderOptions { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderOptions::default() - }, }); } - pub fn draw_text(&self, device: &D, string: &str, origin: Vector2I, invert: bool) { + pub fn draw_text(&self, device: &D, encoder: &mut D::Encoder, string: &str, origin: Vector2I, invert: bool) { let mut next = origin; let char_count = string.chars().count(); let mut vertex_data = Vec::with_capacity(char_count * 4); @@ -228,18 +218,22 @@ impl UIPresenter where D: Device { let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR }; self.draw_texture_with_vertex_data(device, + encoder, &vertex_data, &index_data, &self.font_texture, + self.font_size, color); } pub fn draw_texture(&self, device: &D, + encoder: &mut D::Encoder, origin: Vector2I, texture: &D::Texture, + texture_size: Vector2I, color: ColorU) { - let position_rect = RectI::new(origin, device.texture_size(&texture)); + let position_rect = RectI::new(origin, texture_size); let tex_coord_rect = RectI::new(Vector2I::default(), position_rect.size()); let vertex_data = [ DebugTextureVertex::new(position_rect.origin(), tex_coord_rect.origin()), @@ -248,7 +242,7 @@ impl UIPresenter where D: Device { DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()), ]; - self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color); + self.draw_texture_with_vertex_data(device, encoder, &vertex_data, &QUAD_INDICES, texture, texture_size, color); } pub fn measure_text(&self, string: &str) -> i32 { @@ -269,10 +263,10 @@ impl UIPresenter where D: Device { SEGMENT_SIZE * segment_count as i32 + (segment_count - 1) as i32 } - pub fn draw_solid_rounded_rect(&self, device: &D, rect: RectI, color: ColorU) { - let corner_texture = self.corner_texture(true); - let corner_rects = CornerRects::new(device, rect, corner_texture); - self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects); + pub fn draw_solid_rounded_rect(&self, device: &D, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + let (corner_texture, corner_size) = self.corner_texture(true); + let corner_rects = CornerRects::new(device, rect, corner_texture, corner_size); + self.draw_rounded_rect_corners(device, encoder, color, corner_texture, corner_size, &corner_rects); let solid_rect_mid = RectI::from_points(corner_rects.upper_left.upper_right(), corner_rects.lower_right.lower_left()); @@ -303,16 +297,17 @@ impl UIPresenter where D: Device { index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8)); self.draw_solid_rects_with_vertex_data(device, + encoder, &vertex_data, &index_data[0..18], color, true); } - pub fn draw_rounded_rect_outline(&self, device: &D, rect: RectI, color: ColorU) { - let corner_texture = self.corner_texture(false); - let corner_rects = CornerRects::new(device, rect, corner_texture); - self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects); + pub fn draw_rounded_rect_outline(&self, device: &D, encoder: &mut D::Encoder, rect: RectI, color: ColorU) { + let (corner_texture, corner_size) = self.corner_texture(false); + let corner_rects = CornerRects::new(device, rect, corner_texture, corner_size); + self.draw_rounded_rect_corners(device, encoder, color, corner_texture, corner_size, &corner_rects); let vertex_data = vec![ DebugSolidVertex::new(corner_rects.upper_left.upper_right()), @@ -326,22 +321,23 @@ impl UIPresenter where D: Device { ]; let index_data = &OUTLINE_RECT_LINE_INDICES; - self.draw_solid_rects_with_vertex_data(device, &vertex_data, index_data, color, false); + self.draw_solid_rects_with_vertex_data(device, encoder, &vertex_data, index_data, color, false); } // TODO(pcwalton): `LineSegmentI32`. - fn draw_line(&self, device: &D, from: Vector2I, to: Vector2I, color: ColorU) { + fn draw_line(&self, device: &D, encoder: &mut D::Encoder, from: Vector2I, to: Vector2I, color: ColorU) { let vertex_data = vec![DebugSolidVertex::new(from), DebugSolidVertex::new(to)]; - self.draw_solid_rects_with_vertex_data(device, &vertex_data, &[0, 1], color, false); + self.draw_solid_rects_with_vertex_data(device, encoder, &vertex_data, &[0, 1], color, false); } fn draw_rounded_rect_corners(&self, device: &D, + encoder: &mut D::Encoder, color: ColorU, texture: &D::Texture, + corner_size: Vector2I, corner_rects: &CornerRects) { - let corner_size = device.texture_size(&texture); let tex_coord_rect = RectI::new(Vector2I::default(), corner_size); let vertex_data = vec![ @@ -388,68 +384,69 @@ impl UIPresenter where D: Device { index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8)); index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12)); - self.draw_texture_with_vertex_data(device, &vertex_data, &index_data, texture, color); + self.draw_texture_with_vertex_data(device, encoder, &vertex_data, &index_data, texture, corner_size, color); } - fn corner_texture(&self, filled: bool) -> &D::Texture { - if filled { &self.corner_fill_texture } else { &self.corner_outline_texture } + fn corner_texture(&self, filled: bool) -> (&D::Texture, Vector2I) { + if filled { + (&self.corner_fill_texture, self.corner_fill_size) + } else { + (&self.corner_outline_texture, self.corner_outline_size) + } } fn draw_texture_with_vertex_data(&self, device: &D, + encoder: &mut D::Encoder, vertex_data: &[DebugTextureVertex], index_data: &[u32], texture: &D::Texture, + texture_size: Vector2I, color: ColorU) { - device.allocate_buffer(&self.texture_vertex_array.vertex_buffer, - BufferData::Memory(vertex_data), - BufferTarget::Vertex, - BufferUploadMode::Dynamic); - device.allocate_buffer(&self.texture_vertex_array.index_buffer, - BufferData::Memory(index_data), - BufferTarget::Index, - BufferUploadMode::Dynamic); - - device.draw_elements(index_data.len() as u32, &RenderState { + let vertex_buffer = device.create_buffer(BufferData::Memory(vertex_data)); + let index_buffer = device.create_buffer(BufferData::Memory(index_data)); + + encoder.draw_elements(index_data.len() as u32, &RenderState { target: &RenderTarget::Default, - program: &self.texture_program.program, - vertex_array: &self.texture_vertex_array.vertex_array, + pipeline: &self.texture_pipeline.pipeline, + index_buffer: Some(&index_buffer), + vertex_buffers: &[&vertex_buffer], primitive: Primitive::Triangles, textures: &[&texture], uniforms: &[ - (&self.texture_program.framebuffer_size_uniform, + (&self.texture_pipeline.framebuffer_size_uniform, UniformData::Vec2(self.framebuffer_size.0.to_f32x2())), - (&self.texture_program.color_uniform, get_color_uniform(color)), - (&self.texture_program.texture_uniform, UniformData::TextureUnit(0)), - (&self.texture_program.texture_size_uniform, - UniformData::Vec2(device.texture_size(&texture).0.to_f32x2())) + (&self.texture_pipeline.color_uniform, get_color_uniform(color)), + (&self.texture_pipeline.texture_uniform, UniformData::TextureUnit(0)), + (&self.texture_pipeline.texture_size_uniform, + UniformData::Vec2(texture_size.0.to_f32x2())) ], viewport: RectI::new(Vector2I::default(), self.framebuffer_size), - options: RenderOptions { - blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, - ..RenderOptions::default() - }, }); } - pub fn draw_button(&mut self, device: &D, origin: Vector2I, texture: &D::Texture) -> bool { + pub fn draw_button(&mut self, device: &D, encoder: &mut D::Encoder, origin: Vector2I, texture: &D::Texture) -> bool { let button_rect = RectI::new(origin, Vector2I::new(BUTTON_WIDTH, BUTTON_HEIGHT)); - self.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR); - self.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR); + self.draw_solid_rounded_rect(device, encoder, button_rect, WINDOW_COLOR); + self.draw_rounded_rect_outline(device, encoder, button_rect, OUTLINE_COLOR); self.draw_texture(device, + encoder, origin + Vector2I::new(PADDING, PADDING), texture, + button_rect.size(), BUTTON_ICON_COLOR); self.event_queue.handle_mouse_down_in_rect(button_rect).is_some() } pub fn draw_text_switch(&mut self, device: &D, + encoder: &mut D::Encoder, mut origin: Vector2I, segment_labels: &[&str], mut value: u8) -> u8 { if let Some(new_value) = self.draw_segmented_control(device, + encoder, origin, Some(value), segment_labels.len() as u8) { @@ -461,6 +458,7 @@ impl UIPresenter where D: Device { let label_width = self.measure_text(segment_label); let offset = SEGMENT_SIZE / 2 - label_width / 2; self.draw_text(device, + encoder, segment_label, origin + Vector2I::new(offset, 0), segment_index as u8 == value); @@ -472,12 +470,15 @@ impl UIPresenter where D: Device { pub fn draw_image_segmented_control(&mut self, device: &D, + encoder: &mut D::Encoder, mut origin: Vector2I, segment_textures: &[&D::Texture], + segment_texture_size: Vector2I, mut value: Option) -> Option { let mut clicked_segment = None; if let Some(segment_index) = self.draw_segmented_control(device, + encoder, origin, value, segment_textures.len() as u8) { @@ -488,7 +489,7 @@ impl UIPresenter where D: Device { } for (segment_index, segment_texture) in segment_textures.iter().enumerate() { - let texture_width = device.texture_size(segment_texture).x(); + let texture_width = segment_texture_size.x(); let offset = Vector2I::new(SEGMENT_SIZE / 2 - texture_width / 2, PADDING); let color = if Some(segment_index as u8) == value { WINDOW_COLOR @@ -496,7 +497,7 @@ impl UIPresenter where D: Device { TEXT_COLOR }; - self.draw_texture(device, origin + offset, segment_texture, color); + self.draw_texture(device, encoder, origin + offset, segment_texture, segment_texture_size, color); origin += Vector2I::new(SEGMENT_SIZE + 1, 0); } @@ -505,6 +506,7 @@ impl UIPresenter where D: Device { fn draw_segmented_control(&mut self, device: &D, + encoder: &mut D::Encoder, origin: Vector2I, mut value: Option, segment_count: u8) @@ -521,13 +523,14 @@ impl UIPresenter where D: Device { clicked_segment = Some(segment); } - self.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR); - self.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR); + self.draw_solid_rounded_rect(device, encoder, widget_rect, WINDOW_COLOR); + self.draw_rounded_rect_outline(device, encoder, widget_rect, OUTLINE_COLOR); if let Some(value) = value { let highlight_size = Vector2I::new(SEGMENT_SIZE, BUTTON_HEIGHT); let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1); self.draw_solid_rounded_rect(device, + encoder, RectI::new(origin + Vector2I::new(x_offset, 0), highlight_size), TEXT_COLOR); @@ -540,6 +543,7 @@ impl UIPresenter where D: Device { Some(value) if value == prev_segment_index || value == next_segment_index => {} _ => { self.draw_line(device, + encoder, segment_origin, segment_origin + Vector2I::new(0, BUTTON_HEIGHT), TEXT_COLOR); @@ -551,7 +555,7 @@ impl UIPresenter where D: Device { clicked_segment } - pub fn draw_tooltip(&self, device: &D, string: &str, rect: RectI) { + pub fn draw_tooltip(&self, device: &D, encoder: &mut D::Encoder, string: &str, rect: RectI) { if !rect.to_f32().contains_point(self.mouse_position) { return; } @@ -560,122 +564,105 @@ impl UIPresenter where D: Device { let window_size = Vector2I::new(text_size + PADDING * 2, TOOLTIP_HEIGHT); let origin = rect.origin() - Vector2I::new(0, window_size.y() + PADDING); - self.draw_solid_rounded_rect(device, RectI::new(origin, window_size), WINDOW_COLOR); + self.draw_solid_rounded_rect(device, encoder, RectI::new(origin, window_size), WINDOW_COLOR); self.draw_text(device, + encoder, string, origin + Vector2I::new(PADDING, PADDING + FONT_ASCENT), false); } } -struct DebugTextureProgram where D: Device { - program: D::Program, +struct DebugTexturePipeline where D: Device { + pipeline: D::Pipeline, + /* framebuffer_size_uniform: D::Uniform, texture_size_uniform: D::Uniform, texture_uniform: D::Uniform, color_uniform: D::Uniform, + */ } -impl DebugTextureProgram where D: Device { - fn new(device: &D, resources: &dyn ResourceLoader) -> DebugTextureProgram { - let program = device.create_program(resources, "debug_texture"); +impl DebugTexturePipeline where D: Device { + fn new(device: &D, resources: &dyn ResourceLoader) -> Self { + let pipeline = device.create_pipeline( + resources, + "debug_texture", + RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, + &[ + VertexBufferDescriptor { + stride: DEBUG_TEXTURE_VERTEX_SIZE, + divisor: 0, + attributes: vec![ + VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + offset: 0, + }, + VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + offset: 4, + }, + ], + }, + ], + ); + /* let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let texture_size_uniform = device.get_uniform(&program, "TextureSize"); let texture_uniform = device.get_uniform(&program, "Texture"); let color_uniform = device.get_uniform(&program, "Color"); - DebugTextureProgram { - program, - framebuffer_size_uniform, - texture_size_uniform, - texture_uniform, - color_uniform, - } - } -} - -struct DebugTextureVertexArray where D: Device { - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, - index_buffer: D::Buffer, -} - -impl DebugTextureVertexArray where D: Device { - fn new(device: &D, debug_texture_program: &DebugTextureProgram) - -> DebugTextureVertexArray { - let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); - let vertex_array = device.create_vertex_array(); - - let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position") - .unwrap(); - let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") - .unwrap(); - - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: DEBUG_TEXTURE_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - device.configure_vertex_attr(&vertex_array, &tex_coord_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: DEBUG_TEXTURE_VERTEX_SIZE, - offset: 4, - divisor: 0, - buffer_index: 0, - }); - - DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer } - } -} + */ -struct DebugSolidVertexArray where D: Device { - vertex_array: D::VertexArray, - vertex_buffer: D::Buffer, - index_buffer: D::Buffer, -} - -impl DebugSolidVertexArray where D: Device { - fn new(device: &D, debug_solid_program: &DebugSolidProgram) -> DebugSolidVertexArray { - let (vertex_buffer, index_buffer) = (device.create_buffer(), device.create_buffer()); - let vertex_array = device.create_vertex_array(); - - let position_attr = - device.get_vertex_attr(&debug_solid_program.program, "Position").unwrap(); - device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); - device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); - device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { - size: 2, - class: VertexAttrClass::Int, - attr_type: VertexAttrType::I16, - stride: DEBUG_SOLID_VERTEX_SIZE, - offset: 0, - divisor: 0, - buffer_index: 0, - }); - - DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer } + DebugTexturePipeline { + pipeline, + } } } -struct DebugSolidProgram where D: Device { - program: D::Program, +struct DebugSolidPipeline where D: Device { + pipeline: D::Pipeline, + /* framebuffer_size_uniform: D::Uniform, color_uniform: D::Uniform, + */ } -impl DebugSolidProgram where D: Device { - fn new(device: &D, resources: &dyn ResourceLoader) -> DebugSolidProgram { - let program = device.create_program(resources, "debug_solid"); - let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); - let color_uniform = device.get_uniform(&program, "Color"); - DebugSolidProgram { program, framebuffer_size_uniform, color_uniform } +impl DebugSolidPipeline where D: Device { + fn new(device: &D, resources: &dyn ResourceLoader) -> Self { + let pipeline = device.create_pipeline( + resources, + "debug_solid", + RenderOptions { + blend: BlendState::RGBOneAlphaOneMinusSrcAlpha, + ..RenderOptions::default() + }, + &[ + VertexBufferDescriptor { + stride: DEBUG_SOLID_VERTEX_SIZE, + divisor: 0, + attributes: vec![ + VertexAttrDescriptor { + size: 2, + class: VertexAttrClass::Int, + attr_type: VertexAttrType::I16, + offset: 0, + }, + ], + }, + ], + ); + //let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); + //let color_uniform = device.get_uniform(&program, "Color"); + DebugSolidPipeline { + pipeline, + } } } @@ -722,8 +709,7 @@ struct CornerRects { } impl CornerRects { - fn new(device: &D, rect: RectI, texture: &D::Texture) -> CornerRects where D: Device { - let size = device.texture_size(texture); + fn new(device: &D, rect: RectI, texture: &D::Texture, size: Vector2I) -> CornerRects where D: Device { CornerRects { upper_left: RectI::new(rect.origin(), size), upper_right: RectI::new(rect.upper_right() - Vector2I::new(size.x(), 0), size),