diff --git a/gl/src/lib.rs b/gl/src/lib.rs index dabfec0c..6f5b45d6 100644 --- a/gl/src/lib.rs +++ b/gl/src/lib.rs @@ -21,29 +21,43 @@ use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps}; use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, FeatureLevel}; use pathfinder_gpu::{ImageAccess, ImageBinding, Primitive, ProgramKind, RenderOptions}; -use pathfinder_gpu::{RenderState, RenderTarget, ShaderKind, StencilFunc, TextureData}; +use pathfinder_gpu::{RenderState, RenderTarget, ShaderKind, StencilFunc, TextureBinding, TextureData}; use pathfinder_gpu::{TextureDataRef, TextureFormat, TextureSamplingFlags, UniformData}; use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_resources::ResourceLoader; use pathfinder_simd::default::F32x4; +use std::cell::RefCell; use std::ffi::CString; use std::mem; use std::ptr; use std::str; use std::time::Duration; +const DUMMY_TEXTURE_LENGTH: i32 = 16; + pub struct GLDevice { version: GLVersion, default_framebuffer: GLuint, + dummy_texture: GLTexture, } impl GLDevice { #[inline] pub fn new(version: GLVersion, default_framebuffer: GLuint) -> GLDevice { - GLDevice { - version, - default_framebuffer, - } + let dummy_texture = GLTexture { + gl_texture: 0, + size: Vector2I::zero(), + format: TextureFormat::RGBA8, + }; + + let mut device = GLDevice { version, default_framebuffer, dummy_texture }; + let dummy_texture_data = + [0; DUMMY_TEXTURE_LENGTH as usize * DUMMY_TEXTURE_LENGTH as usize * 4]; + device.dummy_texture = + device.create_texture_from_data(TextureFormat::RGBA8, + Vector2I::splat(DUMMY_TEXTURE_LENGTH), + TextureDataRef::U8(&dummy_texture_data)); + device } pub fn set_default_framebuffer(&mut self, framebuffer: GLuint) { @@ -64,9 +78,10 @@ impl GLDevice { self.use_program(render_state.program); self.bind_vertex_array(render_state.vertex_array); - for (texture_unit, texture) in render_state.textures.iter().enumerate() { - self.bind_texture(texture, texture_unit as u32); - } + + self.bind_textures_and_images(&render_state.program, + &render_state.textures, + &render_state.images); render_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); @@ -75,12 +90,10 @@ impl GLDevice { fn set_compute_state(&self, compute_state: &ComputeState) { self.use_program(compute_state.program); - for (texture_unit, texture) in compute_state.textures.iter().enumerate() { - self.bind_texture(texture, texture_unit as u32); - } - for (image_unit, image) in compute_state.images.iter().enumerate() { - self.bind_image(image, image_unit as u32); - } + + self.bind_textures_and_images(&compute_state.program, + &compute_state.textures, + &compute_state.images); compute_state.uniforms.iter().for_each(|(uniform, data)| self.set_uniform(uniform, data)); @@ -89,6 +102,43 @@ impl GLDevice { } } + fn bind_textures_and_images(&self, + program: &GLProgram, + texture_bindings: &[TextureBinding], + image_bindings: &[ImageBinding]) { + let (mut textures_bound, mut images_bound) = (0, 0); + for &(texture_parameter, texture) in texture_bindings { + self.bind_texture(texture, texture_parameter.texture_unit); + textures_bound |= 1 << texture_parameter.texture_unit as u64; + } + for image_binding in image_bindings { + self.bind_image(image_binding); + images_bound |= 1 << image_binding.0.image_unit as u64; + } + + unsafe { + let parameters = program.parameters.borrow(); + for (texture_unit, uniform) in parameters.textures.iter().enumerate() { + if (textures_bound & (1 << texture_unit as u64)) == 0 { + self.bind_texture(&self.dummy_texture, texture_unit as GLuint); + } + gl::Uniform1i(uniform.location, texture_unit as GLint); ck(); + } + for (image_unit, uniform) in parameters.images.iter().enumerate() { + if (images_bound & (1 << image_unit as u64)) == 0 { + gl::BindImageTexture(image_unit as GLuint, + self.dummy_texture.gl_texture, + 0, + gl::FALSE, + 0, + gl::READ_ONLY, + gl::RGBA8 as GLenum); ck(); + } + gl::Uniform1i(uniform.location, image_unit as GLint); ck(); + } + } + } + fn set_render_options(&self, render_options: &RenderOptions) { unsafe { // Set blend. @@ -183,21 +233,6 @@ impl GLDevice { UniformData::Vec4(data) => { gl::Uniform4f(uniform.location, data.x(), data.y(), data.z(), data.w()); ck(); } - UniformData::TextureUnit(unit) | UniformData::ImageUnit(unit) => { - gl::Uniform1i(uniform.location, unit as GLint); ck(); - } - } - } - } - - // Workaround for a macOS driver bug, it seems. - fn unset_uniform(&self, uniform: &GLUniform, data: &UniformData) { - unsafe { - match *data { - UniformData::TextureUnit(_) => { - gl::Uniform1i(uniform.location, 0); ck(); - } - _ => {} } } } @@ -218,10 +253,18 @@ impl GLDevice { fn reset_render_state(&self, render_state: &RenderState) { self.reset_render_options(&render_state.options); - for texture_unit in 0..(render_state.textures.len() as u32) { - self.unbind_texture(texture_unit); + + unsafe { + for image_binding in render_state.images { + self.unbind_image(image_binding.0.image_unit); + gl::Uniform1i(image_binding.0.uniform.location, 0); ck(); + } + for texture_binding in render_state.textures { + self.unbind_texture(texture_binding.0.texture_unit); + gl::Uniform1i(texture_binding.0.uniform.location, 0); ck(); + } } - render_state.uniforms.iter().for_each(|(uniform, data)| self.unset_uniform(uniform, data)); + self.unuse_program(); self.unbind_vertex_array(); } @@ -230,15 +273,18 @@ impl GLDevice { for &(storage_buffer, _) in compute_state.storage_buffers { self.unset_storage_buffer(storage_buffer); } - for image_unit in 0..(compute_state.images.len() as u32) { - self.unbind_image(image_unit); - } - for texture_unit in 0..(compute_state.textures.len() as u32) { - self.unbind_texture(texture_unit); - } - for (uniform, data) in compute_state.uniforms { - self.unset_uniform(uniform, data); + + unsafe { + for image_binding in compute_state.images { + self.unbind_image(image_binding.0.image_unit); + gl::Uniform1i(image_binding.0.uniform.location, 0); ck(); + } + for texture_binding in compute_state.textures { + self.unbind_texture(texture_binding.0.texture_unit); + gl::Uniform1i(texture_binding.0.uniform.location, 0); ck(); + } } + self.unuse_program(); } @@ -266,11 +312,13 @@ impl Device for GLDevice { type Buffer = GLBuffer; type Fence = GLFence; type Framebuffer = GLFramebuffer; + type ImageParameter = GLImageParameter; type Program = GLProgram; type Shader = GLShader; type StorageBuffer = GLStorageBuffer; type Texture = GLTexture; type TextureDataReceiver = GLTextureDataReceiver; + type TextureParameter = GLTextureParameter; type TimerQuery = GLTimerQuery; type Uniform = GLUniform; type VertexArray = GLVertexArray; @@ -402,7 +450,9 @@ impl Device for GLDevice { } } - GLProgram { gl_program, shaders } + let parameters = GLProgramParameters { textures: vec![], images: vec![] }; + + GLProgram { gl_program, shaders, parameters: RefCell::new(parameters) } } #[inline] @@ -439,6 +489,34 @@ impl Device for GLDevice { GLUniform { location } } + fn get_texture_parameter(&self, program: &GLProgram, name: &str) -> GLTextureParameter { + let uniform = self.get_uniform(program, name); + let mut parameters = program.parameters.borrow_mut(); + let index = match parameters.textures.iter().position(|u| *u == uniform) { + Some(index) => index, + None => { + let index = parameters.textures.len(); + parameters.textures.push(uniform.clone()); + index + } + }; + GLTextureParameter { uniform, texture_unit: index as GLuint } + } + + fn get_image_parameter(&self, program: &GLProgram, name: &str) -> GLImageParameter { + let uniform = self.get_uniform(program, name); + let mut parameters = program.parameters.borrow_mut(); + let index = match parameters.images.iter().position(|u| *u == uniform) { + Some(index) => index, + None => { + let index = parameters.images.len(); + parameters.images.push(uniform.clone()); + index + } + }; + GLImageParameter { uniform, image_unit: index as GLuint } + } + fn get_storage_buffer(&self, _: &Self::Program, _: &str, binding: u32) -> GLStorageBuffer { GLStorageBuffer { location: binding as GLint } } @@ -872,15 +950,15 @@ impl GLDevice { } } - fn bind_image(&self, binding: &ImageBinding, unit: u32) { + fn bind_image(&self, binding: &ImageBinding) { unsafe { - gl::BindImageTexture(unit, - binding.texture.gl_texture, + gl::BindImageTexture(binding.0.image_unit, + binding.1.gl_texture, 0, gl::FALSE, 0, - binding.access.to_gl_access(), - binding.texture.format.gl_internal_format() as GLenum); ck(); + binding.2.to_gl_access(), + binding.1.format.gl_internal_format() as GLenum); ck(); } } @@ -1109,11 +1187,23 @@ impl Drop for GLBuffer { } } -#[derive(Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct GLUniform { location: GLint, } +#[derive(Debug)] +pub struct GLTextureParameter { + uniform: GLUniform, + texture_unit: GLuint, +} + +#[derive(Debug)] +pub struct GLImageParameter { + uniform: GLUniform, + image_unit: GLuint, +} + #[derive(Debug)] pub struct GLStorageBuffer { location: GLint, @@ -1123,6 +1213,7 @@ pub struct GLProgram { pub gl_program: GLuint, #[allow(dead_code)] shaders: ProgramKind, + parameters: RefCell, } impl Drop for GLProgram { @@ -1133,6 +1224,13 @@ impl Drop for GLProgram { } } +pub struct GLProgramParameters { + // Mapping from texture unit number to uniform location. + textures: Vec, + // Mapping from image unit number to uniform location. + images: Vec, +} + pub struct GLShader { gl_shader: GLuint, } diff --git a/gpu/src/lib.rs b/gpu/src/lib.rs index 50a7116f..34f7e3ec 100644 --- a/gpu/src/lib.rs +++ b/gpu/src/lib.rs @@ -28,10 +28,12 @@ pub trait Device: Sized { type Buffer; type Fence; type Framebuffer; + type ImageParameter; type Program; type Shader; type StorageBuffer; type Texture; + type TextureParameter; type TextureDataReceiver; type TimerQuery; type Uniform; @@ -57,6 +59,8 @@ pub trait Device: Sized { local_size: ComputeDimensions); fn get_vertex_attr(&self, program: &Self::Program, name: &str) -> Option; fn get_uniform(&self, program: &Self::Program, name: &str) -> Self::Uniform; + fn get_texture_parameter(&self, program: &Self::Program, name: &str) -> Self::TextureParameter; + fn get_image_parameter(&self, program: &Self::Program, name: &str) -> Self::ImageParameter; fn get_storage_buffer(&self, program: &Self::Program, name: &str, binding: u32) -> Self::StorageBuffer; fn bind_buffer(&self, @@ -237,8 +241,6 @@ pub enum UniformData { Vec2(F32x2), Vec3([f32; 3]), Vec4(F32x4), - TextureUnit(u32), - ImageUnit(u32), } #[derive(Clone, Copy)] @@ -253,9 +255,9 @@ pub struct RenderState<'a, D> where D: Device { pub program: &'a D::Program, pub vertex_array: &'a D::VertexArray, pub primitive: Primitive, - pub uniforms: &'a [(&'a D::Uniform, UniformData)], - pub textures: &'a [&'a D::Texture], - pub images: &'a [ImageBinding<'a, D>], + pub uniforms: &'a [UniformBinding<'a, D::Uniform>], + pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>], + pub images: &'a [ImageBinding<'a, D::ImageParameter, D::Texture>], pub viewport: RectI, pub options: RenderOptions, } @@ -263,17 +265,17 @@ pub struct RenderState<'a, D> where D: Device { #[derive(Clone)] pub struct ComputeState<'a, D> where D: Device { pub program: &'a D::Program, - pub uniforms: &'a [(&'a D::Uniform, UniformData)], - pub textures: &'a [&'a D::Texture], - pub images: &'a [ImageBinding<'a, D>], + pub uniforms: &'a [UniformBinding<'a, D::Uniform>], + pub textures: &'a [TextureBinding<'a, D::TextureParameter, D::Texture>], + pub images: &'a [ImageBinding<'a, D::ImageParameter, D::Texture>], pub storage_buffers: &'a [(&'a D::StorageBuffer, &'a D::Buffer)], } -#[derive(Clone, Debug)] -pub struct ImageBinding<'a, D> where D: Device { - pub texture: &'a D::Texture, - pub access: ImageAccess, -} +pub type UniformBinding<'a, U> = (&'a U, UniformData); + +pub type TextureBinding<'a, TP, T> = (&'a TP, &'a T); + +pub type ImageBinding<'a, IP, T> = (&'a IP, &'a T, ImageAccess); #[derive(Clone, Debug)] pub struct RenderOptions { diff --git a/metal/src/lib.rs b/metal/src/lib.rs index 6e85722b..e7706049 100644 --- a/metal/src/lib.rs +++ b/metal/src/lib.rs @@ -221,6 +221,18 @@ pub struct MetalUniform { name: String, } +#[derive(Clone)] +pub struct MetalTextureParameter { + indices: RefCell>, + name: String, +} + +#[derive(Clone)] +pub struct MetalImageParameter { + indices: RefCell>, + name: String, +} + #[derive(Clone)] pub struct MetalStorageBuffer { indices: RefCell>, @@ -231,13 +243,28 @@ pub struct MetalStorageBuffer { pub struct MetalUniformIndices(ProgramKind>); #[derive(Clone, Copy, Debug)] -pub struct MetalUniformIndex { +pub struct MetalUniformIndex(u64); + +#[derive(Clone, Copy)] +pub struct MetalTextureIndices(ProgramKind>); + +#[derive(Clone, Copy, Debug)] +pub struct MetalTextureIndex { main: u64, - sampler: Option, + sampler: u64, } #[derive(Clone, Copy)] -pub struct MetalStorageBufferIndices(ProgramKind>); +pub struct MetalImageIndices(ProgramKind>); + +#[derive(Clone, Copy, Debug)] +pub struct MetalImageIndex(u64); + +#[derive(Clone, Copy)] +pub struct MetalStorageBufferIndices(ProgramKind>); + +#[derive(Clone, Copy, Debug)] +pub struct MetalStorageBufferIndex(u64); #[derive(Clone)] pub struct MetalFence(Arc); @@ -263,11 +290,13 @@ impl Device for MetalDevice { type Buffer = MetalBuffer; type Fence = MetalFence; type Framebuffer = MetalFramebuffer; + type ImageParameter = MetalImageParameter; type Program = MetalProgram; type Shader = MetalShader; type StorageBuffer = MetalStorageBuffer; type Texture = MetalTexture; type TextureDataReceiver = MetalTextureDataReceiver; + type TextureParameter = MetalTextureParameter; type TimerQuery = MetalTimerQuery; type Uniform = MetalUniform; type VertexArray = MetalVertexArray; @@ -397,6 +426,14 @@ impl Device for MetalDevice { MetalUniform { indices: RefCell::new(None), name: name.to_owned() } } + fn get_texture_parameter(&self, _: &Self::Program, name: &str) -> MetalTextureParameter { + MetalTextureParameter { indices: RefCell::new(None), name: name.to_owned() } + } + + fn get_image_parameter(&self, _: &Self::Program, name: &str) -> MetalImageParameter { + MetalImageParameter { indices: RefCell::new(None), name: name.to_owned() } + } + fn get_storage_buffer(&self, _: &Self::Program, name: &str, _: u32) -> MetalStorageBuffer { MetalStorageBuffer { indices: RefCell::new(None), name: name.to_owned() } } @@ -848,6 +885,23 @@ impl MetalDevice { None => panic!("get_uniform_index() called before reflection!"), Some(ref arguments) => arguments, }; + let main_name = format!("u{}", name); + for argument_index in 0..arguments.len() { + let argument = arguments.object_at(argument_index); + let argument_name = argument.name(); + if argument_name == &main_name { + return Some(MetalUniformIndex(argument.index())) + } + } + None + } + + fn get_texture_index(&self, shader: &MetalShader, name: &str) -> Option { + let arguments = shader.arguments.borrow(); + let arguments = match *arguments { + None => panic!("get_texture_index() called before reflection!"), + Some(ref arguments) => arguments, + }; let (main_name, sampler_name) = (format!("u{}", name), format!("u{}Smplr", name)); let (mut main_argument, mut sampler_argument) = (None, None); for argument_index in 0..arguments.len() { @@ -859,14 +913,31 @@ impl MetalDevice { sampler_argument = Some(argument.index()); } } - let uniform_index = match main_argument { - None => None, - Some(main) => Some(MetalUniformIndex { main, sampler: sampler_argument }), - }; - uniform_index + match (main_argument, sampler_argument) { + (Some(main), Some(sampler)) => Some(MetalTextureIndex { main, sampler }), + _ => None, + } } - fn get_storage_buffer_index(&self, shader: &MetalShader, name: &str) -> Option { + fn get_image_index(&self, shader: &MetalShader, name: &str) -> Option { + let uniforms = shader.arguments.borrow(); + let arguments = match *uniforms { + None => panic!("get_image_index() called before reflection!"), + Some(ref arguments) => arguments, + }; + let main_name = format!("u{}", name); + for argument_index in 0..arguments.len() { + let argument = arguments.object_at(argument_index); + let argument_name = argument.name(); + if argument_name == &main_name { + return Some(MetalImageIndex(argument.index())) + } + } + None + } + + fn get_storage_buffer_index(&self, shader: &MetalShader, name: &str) + -> Option { let uniforms = shader.arguments.borrow(); let arguments = match *uniforms { None => panic!("get_storage_buffer_index() called before reflection!"), @@ -889,11 +960,7 @@ impl MetalDevice { main_argument = Some(argument.index()); } } - let storage_buffer_index = match main_argument { - None => None, - Some(main) => Some(main), - }; - storage_buffer_index + main_argument.map(MetalStorageBufferIndex) } fn populate_uniform_indices_if_necessary(&self, @@ -921,6 +988,56 @@ impl MetalDevice { } } + fn populate_texture_indices_if_necessary(&self, + texture_parameter: &MetalTextureParameter, + program: &MetalProgram) { + let mut indices = texture_parameter.indices.borrow_mut(); + if indices.is_some() { + return; + } + + *indices = match program { + MetalProgram::Raster(MetalRasterProgram { + ref vertex_shader, + ref fragment_shader, + }) => { + Some(MetalTextureIndices(ProgramKind::Raster { + vertex: self.get_texture_index(vertex_shader, &texture_parameter.name), + fragment: self.get_texture_index(fragment_shader, &texture_parameter.name), + })) + } + MetalProgram::Compute(MetalComputeProgram { ref shader, .. }) => { + let image_index = self.get_texture_index(shader, &texture_parameter.name); + Some(MetalTextureIndices(ProgramKind::Compute(image_index))) + } + } + } + + fn populate_image_indices_if_necessary(&self, + image_parameter: &MetalImageParameter, + program: &MetalProgram) { + let mut indices = image_parameter.indices.borrow_mut(); + if indices.is_some() { + return; + } + + *indices = match program { + MetalProgram::Raster(MetalRasterProgram { + ref vertex_shader, + ref fragment_shader, + }) => { + Some(MetalImageIndices(ProgramKind::Raster { + vertex: self.get_image_index(vertex_shader, &image_parameter.name), + fragment: self.get_image_index(fragment_shader, &image_parameter.name), + })) + } + MetalProgram::Compute(MetalComputeProgram { ref shader, .. }) => { + let image_index = self.get_image_index(shader, &image_parameter.name); + Some(MetalImageIndices(ProgramKind::Compute(image_index))) + } + } + } + fn populate_storage_buffer_indices_if_necessary(&self, storage_buffer: &MetalStorageBuffer, program: &MetalProgram) { @@ -976,7 +1093,7 @@ impl MetalDevice { // FIXME(pcwalton): Is this necessary? let mut blit_command_encoder = None; - for texture in render_state.textures { + for &(_, texture) in render_state.textures { if !texture.dirty.get() { continue; } @@ -1078,8 +1195,9 @@ impl MetalDevice { return; } + // Set uniforms. let uniform_buffer = self.create_uniform_buffer(&render_state.uniforms); - for (&(uniform, ref uniform_data), buffer_range) in + for (&(uniform, _), buffer_range) in render_state.uniforms.iter().zip(uniform_buffer.ranges.iter()) { self.populate_uniform_indices_if_necessary(uniform, &render_state.program); @@ -1092,19 +1210,58 @@ impl MetalDevice { if let Some(vertex_index) = *vertex_indices { self.set_vertex_uniform(vertex_index, - uniform_data, &uniform_buffer.data, buffer_range, - render_command_encoder, - render_state); + render_command_encoder); } if let Some(fragment_index) = *fragment_indices { self.set_fragment_uniform(fragment_index, - uniform_data, &uniform_buffer.data, buffer_range, - render_command_encoder, - render_state); + render_command_encoder); + } + } + + // Set textures. + for &(texture_param, texture) in render_state.textures { + self.populate_texture_indices_if_necessary(texture_param, &render_state.program); + + let indices = texture_param.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + let (vertex_indices, fragment_indices) = match indices.0 { + ProgramKind::Raster { ref vertex, ref fragment } => (vertex, fragment), + _ => unreachable!(), + }; + + if let Some(vertex_index) = *vertex_indices { + self.encode_vertex_texture_parameter(vertex_index, + render_command_encoder, + texture); + } + if let Some(fragment_index) = *fragment_indices { + self.encode_fragment_texture_parameter(fragment_index, + render_command_encoder, + texture); + } + } + + // Set images. + for &(image_param, image, _) in render_state.images { + self.populate_image_indices_if_necessary(image_param, &render_state.program); + + let indices = image_param.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + let (vertex_indices, fragment_indices) = match indices.0 { + ProgramKind::Raster { ref vertex, ref fragment } => (vertex, fragment), + _ => unreachable!(), + }; + + if let Some(vertex_index) = *vertex_indices { + render_command_encoder.set_vertex_texture(vertex_index.0, Some(&image.texture)); + } + if let Some(fragment_index) = *fragment_indices { + render_command_encoder.set_fragment_texture(fragment_index.0, + Some(&image.texture)); } } } @@ -1112,8 +1269,9 @@ impl MetalDevice { fn set_compute_uniforms(&self, compute_command_encoder: &ComputeCommandEncoderRef, compute_state: &ComputeState) { + // Set uniforms. let uniform_buffer = self.create_uniform_buffer(&compute_state.uniforms); - for (&(uniform, ref uniform_data), buffer_range) in + for (&(uniform, _), buffer_range) in compute_state.uniforms.iter().zip(uniform_buffer.ranges.iter()) { self.populate_uniform_indices_if_necessary(uniform, &compute_state.program); @@ -1124,13 +1282,43 @@ impl MetalDevice { _ => unreachable!(), }; - if let Some(index) = *indices { - self.set_compute_uniform(index, - uniform_data, + if let Some(indices) = *indices { + self.set_compute_uniform(indices, &uniform_buffer.data, buffer_range, - compute_command_encoder, - compute_state); + compute_command_encoder); + } + } + + // Set textures. + for &(texture_param, texture) in compute_state.textures { + self.populate_texture_indices_if_necessary(texture_param, &compute_state.program); + + let indices = texture_param.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + let indices = match indices.0 { + ProgramKind::Compute(ref indices) => indices, + _ => unreachable!(), + }; + + if let Some(indices) = *indices { + self.encode_compute_texture_parameter(indices, compute_command_encoder, texture); + } + } + + // Set images. + for &(image_param, image, _) in compute_state.images { + self.populate_image_indices_if_necessary(image_param, &compute_state.program); + + let indices = image_param.indices.borrow_mut(); + let indices = indices.as_ref().unwrap(); + let indices = match indices.0 { + ProgramKind::Compute(ref indices) => indices, + _ => unreachable!(), + }; + + if let Some(indices) = *indices { + compute_command_encoder.set_texture(indices.0, Some(&image.texture)); } } @@ -1148,7 +1336,7 @@ impl MetalDevice { if let Some(index) = *indices { if let Some(ref buffer) = *storage_buffer_binding.buffer.borrow() { - compute_command_encoder.set_buffer(index, Some(buffer), 0); + compute_command_encoder.set_buffer(index.0, Some(buffer), 0); } } @@ -1204,7 +1392,6 @@ impl MetalDevice { uniform_buffer_data.write_f32::(vector.z()).unwrap(); uniform_buffer_data.write_f32::(vector.w()).unwrap(); } - UniformData::TextureUnit(_) | UniformData::ImageUnit(_) => {} } let end_index = uniform_buffer_data.len(); while uniform_buffer_data.len() % 256 != 0 { @@ -1221,119 +1408,62 @@ impl MetalDevice { fn set_vertex_uniform(&self, argument_index: MetalUniformIndex, - uniform_data: &UniformData, buffer: &[u8], buffer_range: &Range, - render_command_encoder: &RenderCommandEncoderRef, - render_state: &RenderState) { - match *uniform_data { - UniformData::TextureUnit(unit) => { - let texture = render_state.textures[unit as usize]; - self.encode_vertex_texture_uniform(argument_index, - render_command_encoder, - texture); - } - UniformData::ImageUnit(unit) => { - let image = &render_state.images[unit as usize]; - render_command_encoder.set_vertex_texture(argument_index.main, - Some(&image.texture.texture)); - } - _ => { - render_command_encoder.set_vertex_bytes( - argument_index.main, - (buffer_range.end - buffer_range.start) as u64, - &buffer[buffer_range.start as usize] as *const u8 as *const _) - } - } + render_command_encoder: &RenderCommandEncoderRef) { + render_command_encoder.set_vertex_bytes( + argument_index.0, + (buffer_range.end - buffer_range.start) as u64, + &buffer[buffer_range.start as usize] as *const u8 as *const _) } fn set_fragment_uniform(&self, argument_index: MetalUniformIndex, - uniform_data: &UniformData, buffer: &[u8], buffer_range: &Range, - render_command_encoder: &RenderCommandEncoderRef, - render_state: &RenderState) { - match *uniform_data { - UniformData::TextureUnit(unit) => { - let texture = render_state.textures[unit as usize]; - self.encode_fragment_texture_uniform(argument_index, - render_command_encoder, - texture); - } - UniformData::ImageUnit(unit) => { - let image = &render_state.images[unit as usize]; - render_command_encoder.set_fragment_texture(argument_index.main, - Some(&image.texture.texture)); - } - _ => { - render_command_encoder.set_fragment_bytes( - argument_index.main, - (buffer_range.end - buffer_range.start) as u64, - &buffer[buffer_range.start as usize] as *const u8 as *const _) - } - } + render_command_encoder: &RenderCommandEncoderRef) { + render_command_encoder.set_fragment_bytes( + argument_index.0, + (buffer_range.end - buffer_range.start) as u64, + &buffer[buffer_range.start as usize] as *const u8 as *const _) } fn set_compute_uniform(&self, argument_index: MetalUniformIndex, - uniform_data: &UniformData, buffer: &[u8], buffer_range: &Range, - compute_command_encoder: &ComputeCommandEncoderRef, - compute_state: &ComputeState) { - match *uniform_data { - UniformData::TextureUnit(unit) => { - let texture = compute_state.textures[unit as usize]; - self.encode_compute_texture_uniform(argument_index, - compute_command_encoder, - texture); - } - UniformData::ImageUnit(unit) => { - let image = &compute_state.images[unit as usize]; - compute_command_encoder.set_texture(argument_index.main, - Some(&image.texture.texture)); - } - _ => { - compute_command_encoder.set_bytes( - argument_index.main, - (buffer_range.end - buffer_range.start) as u64, - &buffer[buffer_range.start as usize] as *const u8 as *const _) - } - } + compute_command_encoder: &ComputeCommandEncoderRef) { + compute_command_encoder.set_bytes( + argument_index.0, + (buffer_range.end - buffer_range.start) as u64, + &buffer[buffer_range.start as usize] as *const u8 as *const _) } - fn encode_vertex_texture_uniform(&self, - argument_index: MetalUniformIndex, - render_command_encoder: &RenderCommandEncoderRef, - texture: &MetalTexture) { - render_command_encoder.set_vertex_texture(argument_index.main, Some(&texture.texture)); - if let Some(sampler_index) = argument_index.sampler { - let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; - render_command_encoder.set_vertex_sampler_state(sampler_index, Some(sampler)); - } - } - - fn encode_fragment_texture_uniform(&self, - argument_index: MetalUniformIndex, + fn encode_vertex_texture_parameter(&self, + argument_index: MetalTextureIndex, render_command_encoder: &RenderCommandEncoderRef, texture: &MetalTexture) { - render_command_encoder.set_fragment_texture(argument_index.main, Some(&texture.texture)); - if let Some(sampler_index) = argument_index.sampler { - let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; - render_command_encoder.set_fragment_sampler_state(sampler_index, Some(sampler)); - } + render_command_encoder.set_vertex_texture(argument_index.main, Some(&texture.texture)); + let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; + render_command_encoder.set_vertex_sampler_state(argument_index.sampler, Some(sampler)); } - fn encode_compute_texture_uniform(&self, - argument_index: MetalUniformIndex, - compute_command_encoder: &ComputeCommandEncoderRef, - texture: &MetalTexture) { + fn encode_fragment_texture_parameter(&self, + argument_index: MetalTextureIndex, + render_command_encoder: &RenderCommandEncoderRef, + texture: &MetalTexture) { + render_command_encoder.set_fragment_texture(argument_index.main, Some(&texture.texture)); + let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; + render_command_encoder.set_fragment_sampler_state(argument_index.sampler, Some(sampler)); + } + + fn encode_compute_texture_parameter(&self, + argument_index: MetalTextureIndex, + compute_command_encoder: &ComputeCommandEncoderRef, + texture: &MetalTexture) { compute_command_encoder.set_texture(argument_index.main, Some(&texture.texture)); - if let Some(sampler_index) = argument_index.sampler { - let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; - compute_command_encoder.set_sampler_state(sampler_index, Some(sampler)); - } + let sampler = &self.samplers[texture.sampling_flags.get().bits() as usize]; + compute_command_encoder.set_sampler_state(argument_index.sampler, Some(sampler)); } fn prepare_pipeline_color_attachment_for_render( @@ -1691,40 +1821,39 @@ impl StencilFuncExt for StencilFunc { } trait UniformDataExt { - fn as_bytes(&self) -> Option<&[u8]>; + fn as_bytes(&self) -> &[u8]; } impl UniformDataExt for UniformData { - fn as_bytes(&self) -> Option<&[u8]> { + fn as_bytes(&self) -> &[u8] { unsafe { match *self { - UniformData::TextureUnit(_) | UniformData::ImageUnit(_) => None, UniformData::Float(ref data) => { - Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1)) + slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1) } UniformData::IVec2(ref data) => { - Some(slice::from_raw_parts(data as *const I32x2 as *const u8, 4 * 3)) + slice::from_raw_parts(data as *const I32x2 as *const u8, 4 * 3) } UniformData::IVec3(ref data) => { - Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 3)) + slice::from_raw_parts(data as *const i32 as *const u8, 4 * 3) } UniformData::Int(ref data) => { - Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1)) + slice::from_raw_parts(data as *const i32 as *const u8, 4 * 1) } UniformData::Mat2(ref data) => { - Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4)) + slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4) } UniformData::Mat4(ref data) => { - Some(slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16)) + slice::from_raw_parts(&data[0] as *const F32x4 as *const u8, 4 * 16) } UniformData::Vec2(ref data) => { - Some(slice::from_raw_parts(data as *const F32x2 as *const u8, 4 * 2)) + slice::from_raw_parts(data as *const F32x2 as *const u8, 4 * 2) } UniformData::Vec3(ref data) => { - Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 3)) + slice::from_raw_parts(data as *const f32 as *const u8, 4 * 3) } UniformData::Vec4(ref data) => { - Some(slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4)) + slice::from_raw_parts(data as *const F32x4 as *const u8, 4 * 4) } } } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 20419f52..4ddc7ff5 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -10,7 +10,8 @@ use crate::gpu::debug::DebugUIPresenter; use crate::gpu::options::{DestFramebuffer, RendererOptions}; -use crate::gpu::shaders::{BlitProgram, BlitVertexArray, ClearProgram, ClearVertexArray, ClipTileProgram, ClipTileVertexArray}; +use crate::gpu::shaders::{BlitProgram, BlitVertexArray, ClearProgram, ClearVertexArray}; +use crate::gpu::shaders::{ClipTileProgram, ClipTileVertexArray}; use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray}; use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MAX_TILES_PER_BATCH, ReprojectionProgram}; use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray}; @@ -34,9 +35,9 @@ use pathfinder_geometry::util; use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i}; use pathfinder_gpu::{BlendFactor, BlendOp, BlendState, BufferData, BufferTarget, BufferUploadMode}; use pathfinder_gpu::{ClearOps, ComputeDimensions, ComputeState, DepthFunc, DepthState, Device}; -use pathfinder_gpu::{ImageAccess, ImageBinding, Primitive, RenderOptions, RenderState}; -use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureDataRef}; -use pathfinder_gpu::{TextureFormat, UniformData}; +use pathfinder_gpu::{ImageAccess, Primitive, RenderOptions, RenderState, RenderTarget}; +use pathfinder_gpu::{StencilFunc, StencilState, TextureBinding, TextureDataRef, TextureFormat}; +use pathfinder_gpu::{UniformBinding, UniformData}; use pathfinder_resources::ResourceLoader; use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::collections::VecDeque; @@ -662,14 +663,13 @@ impl Renderer where D: Device { program: &fill_raster_program.program, vertex_array: &fill_vertex_array.vertex_array, primitive: Primitive::Triangles, - textures: &[&self.area_lut_texture], + textures: &[(&fill_raster_program.area_lut_texture, &self.area_lut_texture)], uniforms: &[ (&fill_raster_program.framebuffer_size_uniform, UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32, MASK_FRAMEBUFFER_HEIGHT as f32))), (&fill_raster_program.tile_size_uniform, UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), - (&fill_raster_program.area_lut_uniform, UniformData::TextureUnit(0)), ], images: &[], viewport: mask_viewport, @@ -761,10 +761,7 @@ impl Renderer where D: Device { &self.fill_tile_map, BufferTarget::Storage); - let image_binding = ImageBinding { - texture: self.device.framebuffer_texture(&alpha_tile_page.framebuffer), - access: ImageAccess::Write, - }; + let image_texture = self.device.framebuffer_texture(&alpha_tile_page.framebuffer); let timer_query = self.timer_query_cache.alloc(&self.device); self.device.begin_timer_query(&timer_query); @@ -773,11 +770,9 @@ impl Renderer where D: Device { let dimensions = ComputeDimensions { x: 1, y: 1, z: fill_tile_count as u32 }; self.device.dispatch_compute(dimensions, &ComputeState { program: &fill_compute_program.program, - textures: &[&self.area_lut_texture], - images: &[image_binding], + textures: &[(&fill_compute_program.area_lut_texture, &self.area_lut_texture)], + images: &[(&fill_compute_program.dest_image, image_texture, ImageAccess::Write)], uniforms: &[ - (&fill_compute_program.area_lut_uniform, UniformData::TextureUnit(0)), - (&fill_compute_program.dest_uniform, UniformData::ImageUnit(0)), (&fill_compute_program.first_tile_index_uniform, UniformData::Int(first_fill_tile as i32)), ], @@ -845,9 +840,9 @@ impl Renderer where D: Device { program: &self.tile_clip_program.program, vertex_array: &self.back_frame.tile_clip_vertex_array.vertex_array, primitive: Primitive::Triangles, - textures: &[src_texture], + textures: &[(&self.tile_clip_program.src_texture, src_texture)], images: &[], - uniforms: &[(&self.tile_clip_program.src_uniform, UniformData::TextureUnit(0))], + uniforms: &[], viewport: mask_viewport, options: RenderOptions { blend, @@ -893,7 +888,10 @@ impl Renderer where D: Device { let timer_query = self.timer_query_cache.alloc(&self.device); self.device.begin_timer_query(&timer_query); - let mut textures = vec![&self.back_frame.texture_metadata_texture]; + let mut textures = vec![ + (&self.tile_program.texture_metadata_texture, + &self.back_frame.texture_metadata_texture), + ]; let mut uniforms = vec![ (&self.tile_program.transform_uniform, UniformData::Mat4(self.tile_transform().to_columns())), @@ -901,26 +899,23 @@ impl Renderer where D: Device { UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))), (&self.tile_program.framebuffer_size_uniform, UniformData::Vec2(draw_viewport.size().to_f32().0)), - (&self.tile_program.texture_metadata_uniform, UniformData::TextureUnit(0)), (&self.tile_program.texture_metadata_size_uniform, UniformData::IVec2(I32x2::new(TEXTURE_METADATA_TEXTURE_WIDTH, TEXTURE_METADATA_TEXTURE_HEIGHT))), ]; if needs_readable_framebuffer { - uniforms.push((&self.tile_program.dest_texture_uniform, - UniformData::TextureUnit(textures.len() as u32))); - textures.push(self.device - .framebuffer_texture(&self.back_frame.dest_blend_framebuffer)); + textures.push((&self.tile_program.dest_texture, + self.device + .framebuffer_texture(&self.back_frame.dest_blend_framebuffer))); } if let Some(alpha_tile_page) = self.back_frame.alpha_tile_pages.get(&tile_page) { - uniforms.push((&self.tile_program.mask_texture_0_uniform, - UniformData::TextureUnit(textures.len() as u32))); uniforms.push((&self.tile_program.mask_texture_size_0_uniform, UniformData::Vec2(F32x2::new(MASK_FRAMEBUFFER_WIDTH as f32, MASK_FRAMEBUFFER_HEIGHT as f32)))); - textures.push(self.device.framebuffer_texture(&alpha_tile_page.framebuffer)); + textures.push((&self.tile_program.mask_texture_0, + self.device.framebuffer_texture(&alpha_tile_page.framebuffer))); } // TODO(pcwalton): Refactor. @@ -930,12 +925,10 @@ impl Renderer where D: Device { let color_texture_page = self.texture_page(color_texture.page); let color_texture_size = self.device.texture_size(color_texture_page).to_f32(); self.device.set_texture_sampling_mode(color_texture_page, - color_texture.sampling_flags); - uniforms.push((&self.tile_program.color_texture_0_uniform, - UniformData::TextureUnit(textures.len() as u32))); + color_texture.sampling_flags); + textures.push((&self.tile_program.color_texture_0, color_texture_page)); uniforms.push((&self.tile_program.color_texture_size_0_uniform, UniformData::Vec2(color_texture_size.0))); - textures.push(color_texture_page); ctrl |= color_texture.composite_op.to_combine_mode() << COMBINER_CTRL_COLOR_COMBINE_SHIFT; @@ -1022,9 +1015,7 @@ impl Renderer where D: Device { }; let draw_texture = self.device.framebuffer_texture(&draw_framebuffer); - uniforms.push((&self.tile_copy_program.src_uniform, - UniformData::TextureUnit(textures.len() as u32))); - textures.push(draw_texture); + textures.push((&self.tile_copy_program.src_texture, draw_texture)); uniforms.push((&self.tile_copy_program.framebuffer_size_uniform, UniformData::Vec2(draw_viewport.size().to_f32().0))); @@ -1106,14 +1097,13 @@ impl Renderer where D: Device { program: &self.reprojection_program.program, vertex_array: &self.back_frame.reprojection_vertex_array.vertex_array, primitive: Primitive::Triangles, - textures: &[texture], + textures: &[(&self.reprojection_program.texture, texture)], images: &[], uniforms: &[ (&self.reprojection_program.old_transform_uniform, UniformData::from_transform_3d(old_transform)), (&self.reprojection_program.new_transform_uniform, UniformData::from_transform_3d(new_transform)), - (&self.reprojection_program.texture_uniform, UniformData::TextureUnit(0)), ], viewport: self.draw_viewport(), options: RenderOptions { @@ -1181,15 +1171,15 @@ impl Renderer where D: Device { ]); } - fn set_uniforms_for_text_filter<'a>(&'a self, - textures: &mut Vec<&'a D::Texture>, - uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, - fg_color: ColorF, - bg_color: ColorF, - defringing_kernel: Option, - gamma_correction: bool) { - let gamma_lut_texture_unit = textures.len() as u32; - textures.push(&self.gamma_lut_texture); + fn set_uniforms_for_text_filter<'a>( + &'a self, + textures: &mut Vec>, + uniforms: &mut Vec>, + fg_color: ColorF, + bg_color: ColorF, + defringing_kernel: Option, + gamma_correction: bool) { + textures.push((&self.tile_program.gamma_lut_texture, &self.gamma_lut_texture)); match defringing_kernel { Some(ref kernel) => { @@ -1206,12 +1196,9 @@ impl Renderer where D: Device { params_2.set_w(gamma_correction as i32 as f32); uniforms.extend_from_slice(&[ - (&self.tile_program.gamma_lut_uniform, - UniformData::TextureUnit(gamma_lut_texture_unit)), (&self.tile_program.filter_params_1_uniform, UniformData::Vec4(bg_color.0)), (&self.tile_program.filter_params_2_uniform, UniformData::Vec4(params_2)), ]); - } fn set_uniforms_for_blur_filter<'a>(&'a self, @@ -1279,9 +1266,9 @@ impl Renderer where D: Device { let main_viewport = self.main_viewport(); - let uniforms = [(&self.blit_program.src_uniform, UniformData::TextureUnit(0))]; let textures = [ - (self.device.framebuffer_texture(&self.back_frame.intermediate_dest_framebuffer)) + (&self.blit_program.src_texture, + self.device.framebuffer_texture(&self.back_frame.intermediate_dest_framebuffer)) ]; self.device.draw_elements(6, &RenderState { @@ -1291,7 +1278,7 @@ impl Renderer where D: Device { primitive: Primitive::Triangles, textures: &textures[..], images: &[], - uniforms: &uniforms[..], + uniforms: &[], viewport: main_viewport, options: RenderOptions { clear_ops: ClearOps { diff --git a/renderer/src/gpu/shaders.rs b/renderer/src/gpu/shaders.rs index 06f419d1..ee04ff1d 100644 --- a/renderer/src/gpu/shaders.rs +++ b/renderer/src/gpu/shaders.rs @@ -355,14 +355,14 @@ impl ClipTileVertexArray where D: Device { pub struct BlitProgram where D: Device { pub program: D::Program, - pub src_uniform: D::Uniform, + pub src_texture: D::TextureParameter, } impl BlitProgram where D: Device { pub fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram { let program = device.create_raster_program(resources, "blit"); - let src_uniform = device.get_uniform(&program, "Src"); - BlitProgram { program, src_uniform } + let src_texture = device.get_texture_parameter(&program, "Src"); + BlitProgram { program, src_texture } } } @@ -406,7 +406,7 @@ pub struct FillRasterProgram where D: Device { pub program: D::Program, pub framebuffer_size_uniform: D::Uniform, pub tile_size_uniform: D::Uniform, - pub area_lut_uniform: D::Uniform, + pub area_lut_texture: D::TextureParameter, } impl FillRasterProgram where D: Device { @@ -414,20 +414,20 @@ impl FillRasterProgram where D: Device { let program = device.create_raster_program(resources, "fill"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let area_lut_uniform = device.get_uniform(&program, "AreaLUT"); + let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT"); FillRasterProgram { program, framebuffer_size_uniform, tile_size_uniform, - area_lut_uniform, + area_lut_texture, } } } pub struct FillComputeProgram where D: Device { pub program: D::Program, - pub dest_uniform: D::Uniform, - pub area_lut_uniform: D::Uniform, + pub dest_image: D::ImageParameter, + pub area_lut_texture: D::TextureParameter, pub first_tile_index_uniform: D::Uniform, pub fills_storage_buffer: D::StorageBuffer, pub next_fills_storage_buffer: D::StorageBuffer, @@ -440,8 +440,8 @@ impl FillComputeProgram where D: Device { let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 }; device.set_compute_program_local_size(&mut program, local_size); - let dest_uniform = device.get_uniform(&program, "Dest"); - let area_lut_uniform = device.get_uniform(&program, "AreaLUT"); + let dest_image = device.get_image_parameter(&program, "Dest"); + let area_lut_texture = device.get_texture_parameter(&program, "AreaLUT"); let first_tile_index_uniform = device.get_uniform(&program, "FirstTileIndex"); let fills_storage_buffer = device.get_storage_buffer(&program, "Fills", 0); let next_fills_storage_buffer = device.get_storage_buffer(&program, "NextFills", 1); @@ -449,8 +449,8 @@ impl FillComputeProgram where D: Device { FillComputeProgram { program, - dest_uniform, - area_lut_uniform, + dest_image, + area_lut_texture, first_tile_index_uniform, fills_storage_buffer, next_fills_storage_buffer, @@ -463,15 +463,15 @@ pub struct TileProgram where D: Device { pub program: D::Program, pub transform_uniform: D::Uniform, pub tile_size_uniform: D::Uniform, - pub texture_metadata_uniform: D::Uniform, + pub texture_metadata_texture: D::TextureParameter, pub texture_metadata_size_uniform: D::Uniform, - pub dest_texture_uniform: D::Uniform, - pub color_texture_0_uniform: D::Uniform, + pub dest_texture: D::TextureParameter, + pub color_texture_0: D::TextureParameter, pub color_texture_size_0_uniform: D::Uniform, - pub color_texture_1_uniform: D::Uniform, - pub mask_texture_0_uniform: D::Uniform, + pub color_texture_1: D::TextureParameter, + pub mask_texture_0: D::TextureParameter, pub mask_texture_size_0_uniform: D::Uniform, - pub gamma_lut_uniform: D::Uniform, + pub gamma_lut_texture: D::TextureParameter, pub filter_params_0_uniform: D::Uniform, pub filter_params_1_uniform: D::Uniform, pub filter_params_2_uniform: D::Uniform, @@ -484,15 +484,15 @@ impl TileProgram where D: Device { let program = device.create_raster_program(resources, "tile"); let transform_uniform = device.get_uniform(&program, "Transform"); let tile_size_uniform = device.get_uniform(&program, "TileSize"); - let texture_metadata_uniform = device.get_uniform(&program, "TextureMetadata"); + let texture_metadata_texture = device.get_texture_parameter(&program, "TextureMetadata"); let texture_metadata_size_uniform = device.get_uniform(&program, "TextureMetadataSize"); - let dest_texture_uniform = device.get_uniform(&program, "DestTexture"); - let color_texture_0_uniform = device.get_uniform(&program, "ColorTexture0"); + let dest_texture = device.get_texture_parameter(&program, "DestTexture"); + let color_texture_0 = device.get_texture_parameter(&program, "ColorTexture0"); let color_texture_size_0_uniform = device.get_uniform(&program, "ColorTextureSize0"); - let color_texture_1_uniform = device.get_uniform(&program, "ColorTexture1"); - let mask_texture_0_uniform = device.get_uniform(&program, "MaskTexture0"); + let color_texture_1 = device.get_texture_parameter(&program, "ColorTexture1"); + let mask_texture_0 = device.get_texture_parameter(&program, "MaskTexture0"); let mask_texture_size_0_uniform = device.get_uniform(&program, "MaskTextureSize0"); - let gamma_lut_uniform = device.get_uniform(&program, "GammaLUT"); + let gamma_lut_texture = device.get_texture_parameter(&program, "GammaLUT"); let filter_params_0_uniform = device.get_uniform(&program, "FilterParams0"); let filter_params_1_uniform = device.get_uniform(&program, "FilterParams1"); let filter_params_2_uniform = device.get_uniform(&program, "FilterParams2"); @@ -502,15 +502,15 @@ impl TileProgram where D: Device { program, transform_uniform, tile_size_uniform, - texture_metadata_uniform, + texture_metadata_texture, texture_metadata_size_uniform, - dest_texture_uniform, - color_texture_0_uniform, + dest_texture, + color_texture_0, color_texture_size_0_uniform, - color_texture_1_uniform, - mask_texture_0_uniform, + color_texture_1, + mask_texture_0, mask_texture_size_0_uniform, - gamma_lut_uniform, + gamma_lut_texture, filter_params_0_uniform, filter_params_1_uniform, filter_params_2_uniform, @@ -525,7 +525,7 @@ pub struct CopyTileProgram where D: Device { pub transform_uniform: D::Uniform, pub tile_size_uniform: D::Uniform, pub framebuffer_size_uniform: D::Uniform, - pub src_uniform: D::Uniform, + pub src_texture: D::TextureParameter, } impl CopyTileProgram where D: Device { @@ -534,27 +534,27 @@ impl CopyTileProgram where D: Device { let transform_uniform = device.get_uniform(&program, "Transform"); let tile_size_uniform = device.get_uniform(&program, "TileSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); - let src_uniform = device.get_uniform(&program, "Src"); + let src_texture = device.get_texture_parameter(&program, "Src"); CopyTileProgram { program, transform_uniform, tile_size_uniform, framebuffer_size_uniform, - src_uniform, + src_texture, } } } pub struct ClipTileProgram where D: Device { pub program: D::Program, - pub src_uniform: D::Uniform, + pub src_texture: D::TextureParameter, } impl ClipTileProgram where D: Device { pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileProgram { let program = device.create_raster_program(resources, "tile_clip"); - let src_uniform = device.get_uniform(&program, "Src"); - ClipTileProgram { program, src_uniform } + let src_texture = device.get_texture_parameter(&program, "Src"); + ClipTileProgram { program, src_texture } } } @@ -611,32 +611,20 @@ where } } -pub struct ReprojectionProgram -where - D: Device, -{ +pub struct ReprojectionProgram where D: Device { pub program: D::Program, pub old_transform_uniform: D::Uniform, pub new_transform_uniform: D::Uniform, - pub texture_uniform: D::Uniform, + pub texture: D::TextureParameter, } -impl ReprojectionProgram -where - D: Device, -{ +impl ReprojectionProgram where D: Device { pub fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram { let program = device.create_raster_program(resources, "reproject"); let old_transform_uniform = device.get_uniform(&program, "OldTransform"); let new_transform_uniform = device.get_uniform(&program, "NewTransform"); - let texture_uniform = device.get_uniform(&program, "Texture"); - - ReprojectionProgram { - program, - old_transform_uniform, - new_transform_uniform, - texture_uniform, - } + let texture = device.get_texture_parameter(&program, "Texture"); + ReprojectionProgram { program, old_transform_uniform, new_transform_uniform, texture } } } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 237092cf..775032db 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -412,13 +412,12 @@ impl UIPresenter where D: Device { program: &self.texture_program.program, vertex_array: &self.texture_vertex_array.vertex_array, primitive: Primitive::Triangles, - textures: &[&texture], + textures: &[(&self.texture_program.texture, &texture)], images: &[], uniforms: &[ (&self.texture_program.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())) ], @@ -566,8 +565,8 @@ struct DebugTextureProgram where D: Device { program: D::Program, framebuffer_size_uniform: D::Uniform, texture_size_uniform: D::Uniform, - texture_uniform: D::Uniform, color_uniform: D::Uniform, + texture: D::TextureParameter, } impl DebugTextureProgram where D: Device { @@ -575,14 +574,14 @@ impl DebugTextureProgram where D: Device { let program = device.create_raster_program(resources, "debug_texture"); 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"); + let texture = device.get_texture_parameter(&program, "Texture"); DebugTextureProgram { program, framebuffer_size_uniform, texture_size_uniform, - texture_uniform, color_uniform, + texture, } } } diff --git a/webgl/src/lib.rs b/webgl/src/lib.rs index ed3ddf59..08fd3620 100644 --- a/webgl/src/lib.rs +++ b/webgl/src/lib.rs @@ -16,12 +16,13 @@ extern crate log; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::vector::Vector2I; use pathfinder_gpu::{BlendFactor, BlendOp, BufferData, BufferTarget, BufferUploadMode, ClearOps}; -use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, FeatureLevel, Primitive}; -use pathfinder_gpu::{ProgramKind, RenderOptions, RenderState, RenderTarget, ShaderKind}; -use pathfinder_gpu::{StencilFunc, TextureData, TextureDataRef, TextureFormat}; -use pathfinder_gpu::{TextureSamplingFlags, UniformData, VertexAttrClass}; -use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType}; +use pathfinder_gpu::{ComputeDimensions, ComputeState, DepthFunc, Device, FeatureLevel}; +use pathfinder_gpu::{ImageBinding, Primitive, ProgramKind, RenderOptions, RenderState}; +use pathfinder_gpu::{RenderTarget, ShaderKind, StencilFunc, TextureBinding, TextureData}; +use pathfinder_gpu::{TextureDataRef, TextureFormat, TextureSamplingFlags, UniformData}; +use pathfinder_gpu::{VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_resources::ResourceLoader; +use std::cell::RefCell; use std::mem; use std::str; use std::time::Duration; @@ -170,12 +171,9 @@ impl WebGlDevice { self.context.uniform3i(location, data[0], data[1], data[2]); self.ck(); } - UniformData::TextureUnit(unit) | UniformData::ImageUnit(unit) => { - self.context.uniform1i(location, unit as i32); - self.ck(); - } } } + fn set_render_state(&self, render_state: &RenderState) { self.bind_render_target(render_state.target); @@ -187,13 +185,12 @@ impl WebGlDevice { self.clear(&render_state.options.clear_ops); } - self.context - .use_program(Some(&render_state.program.gl_program)); - self.context - .bind_vertex_array(Some(&render_state.vertex_array.gl_vertex_array)); - for (texture_unit, texture) in render_state.textures.iter().enumerate() { - self.bind_texture(texture, texture_unit as u32); - } + self.context.use_program(Some(&render_state.program.gl_program)); + self.context.bind_vertex_array(Some(&render_state.vertex_array.gl_vertex_array)); + + self.bind_textures_and_images(&render_state.program, + &render_state.textures, + &render_state.images); for (uniform, data) in render_state.uniforms { self.set_uniform(uniform, data); @@ -201,6 +198,22 @@ impl WebGlDevice { self.set_render_options(&render_state.options); } + fn bind_textures_and_images( + &self, + program: &WebGlProgram, + texture_bindings: &[TextureBinding], + _: &[ImageBinding<(), WebGlTexture>]) { + for &(texture_parameter, texture) in texture_bindings { + self.bind_texture(texture, texture_parameter.texture_unit); + } + + let parameters = program.parameters.borrow(); + for (texture_unit, uniform) in parameters.textures.iter().enumerate() { + self.context.uniform1i(uniform.location.as_ref(), texture_unit as i32); + self.ck(); + } + } + fn set_render_options(&self, render_options: &RenderOptions) { match render_options.blend { None => { @@ -415,11 +428,13 @@ impl Device for WebGlDevice { type Buffer = WebGlBuffer; type Fence = (); type Framebuffer = WebGlFramebuffer; + type ImageParameter = (); type Program = WebGlProgram; type Shader = WebGlShader; type StorageBuffer = (); type Texture = WebGlTexture; type TextureDataReceiver = (); + type TextureParameter = WebGlTextureParameter; type TimerQuery = WebGlTimerQuery; type Uniform = WebGlUniform; type VertexArray = WebGlVertexArray; @@ -566,9 +581,12 @@ impl Device for WebGlDevice { panic!("Program {:?} linking failed", name); } + let parameters = WebGlProgramParameters { textures: vec![] }; + WebGlProgram { context: self.context.clone(), gl_program, + parameters: RefCell::new(parameters), } } @@ -596,13 +614,29 @@ impl Device for WebGlDevice { fn get_uniform(&self, program: &WebGlProgram, name: &str) -> WebGlUniform { let name = format!("u{}", name); - let location = self - .context - .get_uniform_location(&program.gl_program, &name); + let location = self.context.get_uniform_location(&program.gl_program, &name); self.ck(); WebGlUniform { location: location } } + fn get_texture_parameter(&self, program: &WebGlProgram, name: &str) -> WebGlTextureParameter { + let uniform = self.get_uniform(program, name); + let mut parameters = program.parameters.borrow_mut(); + let index = match parameters.textures.iter().position(|u| *u == uniform) { + Some(index) => index, + None => { + let index = parameters.textures.len(); + parameters.textures.push(uniform.clone()); + index + } + }; + WebGlTextureParameter { uniform, texture_unit: index as u32 } + } + + fn get_image_parameter(&self, _: &WebGlProgram, _: &str) { + // TODO(pcwalton) + } + fn get_storage_buffer(&self, _: &Self::Program, _: &str, _: u32) { // TODO(pcwalton) } @@ -988,14 +1022,21 @@ impl Drop for WebGlBuffer { } } -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct WebGlUniform { location: Option, } +#[derive(Debug)] +pub struct WebGlTextureParameter { + uniform: WebGlUniform, + texture_unit: u32, +} + pub struct WebGlProgram { context: web_sys::WebGl2RenderingContext, pub gl_program: web_sys::WebGlProgram, + parameters: RefCell, } impl Drop for WebGlProgram { @@ -1004,6 +1045,11 @@ impl Drop for WebGlProgram { } } +pub struct WebGlProgramParameters { + // Mapping from texture unit number to uniform location. + textures: Vec, +} + pub struct WebGlShader { gl_shader: web_sys::WebGlShader, }