Associate texture parameters in shaders with specific texture units, to work

around a macOS Radeon driver bug.

Also, ensure there is always a dummy texture bound to every parameter in the
OpenGL backend.

These together stop the macOS Radeon drivers from recompiling the shader on
every drawcall.

Possibly addresses #300.
This commit is contained in:
Patrick Walton 2020-05-12 15:06:20 -07:00
parent cbceee85e6
commit ef0c0e0679
7 changed files with 570 additions and 321 deletions

View File

@ -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<GLDevice>) {
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<GLTextureParameter, GLTexture>],
image_bindings: &[ImageBinding<GLImageParameter, GLTexture>]) {
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<GLDevice>) {
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();
}
render_state.uniforms.iter().for_each(|(uniform, data)| self.unset_uniform(uniform, data));
for texture_binding in render_state.textures {
self.unbind_texture(texture_binding.0.texture_unit);
gl::Uniform1i(texture_binding.0.uniform.location, 0); ck();
}
}
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);
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_unit in 0..(compute_state.textures.len() as u32) {
self.unbind_texture(texture_unit);
for texture_binding in compute_state.textures {
self.unbind_texture(texture_binding.0.texture_unit);
gl::Uniform1i(texture_binding.0.uniform.location, 0); ck();
}
for (uniform, data) in compute_state.uniforms {
self.unset_uniform(uniform, data);
}
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<GLDevice>, unit: u32) {
fn bind_image(&self, binding: &ImageBinding<GLImageParameter, GLTexture>) {
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<GLShader>,
parameters: RefCell<GLProgramParameters>,
}
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<GLUniform>,
// Mapping from image unit number to uniform location.
images: Vec<GLUniform>,
}
pub struct GLShader {
gl_shader: GLuint,
}

View File

@ -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<Self::VertexAttr>;
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 {

View File

@ -221,6 +221,18 @@ pub struct MetalUniform {
name: String,
}
#[derive(Clone)]
pub struct MetalTextureParameter {
indices: RefCell<Option<MetalTextureIndices>>,
name: String,
}
#[derive(Clone)]
pub struct MetalImageParameter {
indices: RefCell<Option<MetalImageIndices>>,
name: String,
}
#[derive(Clone)]
pub struct MetalStorageBuffer {
indices: RefCell<Option<MetalStorageBufferIndices>>,
@ -231,13 +243,28 @@ pub struct MetalStorageBuffer {
pub struct MetalUniformIndices(ProgramKind<Option<MetalUniformIndex>>);
#[derive(Clone, Copy, Debug)]
pub struct MetalUniformIndex {
pub struct MetalUniformIndex(u64);
#[derive(Clone, Copy)]
pub struct MetalTextureIndices(ProgramKind<Option<MetalTextureIndex>>);
#[derive(Clone, Copy, Debug)]
pub struct MetalTextureIndex {
main: u64,
sampler: Option<u64>,
sampler: u64,
}
#[derive(Clone, Copy)]
pub struct MetalStorageBufferIndices(ProgramKind<Option<u64>>);
pub struct MetalImageIndices(ProgramKind<Option<MetalImageIndex>>);
#[derive(Clone, Copy, Debug)]
pub struct MetalImageIndex(u64);
#[derive(Clone, Copy)]
pub struct MetalStorageBufferIndices(ProgramKind<Option<MetalStorageBufferIndex>>);
#[derive(Clone, Copy, Debug)]
pub struct MetalStorageBufferIndex(u64);
#[derive(Clone)]
pub struct MetalFence(Arc<MetalFenceInfo>);
@ -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<MetalTextureIndex> {
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<u64> {
fn get_image_index(&self, shader: &MetalShader, name: &str) -> Option<MetalImageIndex> {
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<MetalStorageBufferIndex> {
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);
}
}
// 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,
render_state);
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<MetalDevice>) {
// 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::<NativeEndian>(vector.z()).unwrap();
uniform_buffer_data.write_f32::<NativeEndian>(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<usize>,
render_command_encoder: &RenderCommandEncoderRef,
render_state: &RenderState<MetalDevice>) {
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: &RenderCommandEncoderRef) {
render_command_encoder.set_vertex_bytes(
argument_index.main,
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<usize>,
render_command_encoder: &RenderCommandEncoderRef,
render_state: &RenderState<MetalDevice>) {
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: &RenderCommandEncoderRef) {
render_command_encoder.set_fragment_bytes(
argument_index.main,
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<usize>,
compute_command_encoder: &ComputeCommandEncoderRef,
compute_state: &ComputeState<MetalDevice>) {
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: &ComputeCommandEncoderRef) {
compute_command_encoder.set_bytes(
argument_index.main,
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,
fn encode_vertex_texture_parameter(&self,
argument_index: MetalTextureIndex,
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));
}
render_command_encoder.set_vertex_sampler_state(argument_index.sampler, Some(sampler));
}
fn encode_fragment_texture_uniform(&self,
argument_index: MetalUniformIndex,
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));
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_fragment_sampler_state(argument_index.sampler, Some(sampler));
}
fn encode_compute_texture_uniform(&self,
argument_index: MetalUniformIndex,
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));
}
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)
}
}
}

View File

@ -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<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> 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.
@ -931,11 +926,9 @@ impl<D> Renderer<D> where D: Device {
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)));
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<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> 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)>,
fn set_uniforms_for_text_filter<'a>(
&'a self,
textures: &mut Vec<TextureBinding<'a, D::TextureParameter, D::Texture>>,
uniforms: &mut Vec<UniformBinding<'a, D::Uniform>>,
fg_color: ColorF,
bg_color: ColorF,
defringing_kernel: Option<DefringingKernel>,
gamma_correction: bool) {
let gamma_lut_texture_unit = textures.len() as u32;
textures.push(&self.gamma_lut_texture);
textures.push((&self.tile_program.gamma_lut_texture, &self.gamma_lut_texture));
match defringing_kernel {
Some(ref kernel) => {
@ -1206,12 +1196,9 @@ impl<D> Renderer<D> 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<D> Renderer<D> 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<D> Renderer<D> where D: Device {
primitive: Primitive::Triangles,
textures: &textures[..],
images: &[],
uniforms: &uniforms[..],
uniforms: &[],
viewport: main_viewport,
options: RenderOptions {
clear_ops: ClearOps {

View File

@ -355,14 +355,14 @@ impl<D> ClipTileVertexArray<D> where D: Device {
pub struct BlitProgram<D> where D: Device {
pub program: D::Program,
pub src_uniform: D::Uniform,
pub src_texture: D::TextureParameter,
}
impl<D> BlitProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
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<D> 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<D> FillRasterProgram<D> where D: Device {
@ -414,20 +414,20 @@ impl<D> FillRasterProgram<D> 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<D> 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<D> FillComputeProgram<D> 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<D> FillComputeProgram<D> 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<D> 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<D> TileProgram<D> 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<D> TileProgram<D> 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<D> 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<D> CopyTileProgram<D> where D: Device {
@ -534,27 +534,27 @@ impl<D> CopyTileProgram<D> 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<D> where D: Device {
pub program: D::Program,
pub src_uniform: D::Uniform,
pub src_texture: D::TextureParameter,
}
impl<D> ClipTileProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileProgram<D> {
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<D>
where
D: Device,
{
pub struct ReprojectionProgram<D> 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<D> ReprojectionProgram<D>
where
D: Device,
{
impl<D> ReprojectionProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> {
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 }
}
}

View File

@ -412,13 +412,12 @@ impl<D> UIPresenter<D> 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<D> 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<D> DebugTextureProgram<D> where D: Device {
@ -575,14 +574,14 @@ impl<D> DebugTextureProgram<D> 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,
}
}
}

View File

@ -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<WebGlDevice>) {
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<WebGlTextureParameter, WebGlTexture>],
_: &[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<web_sys::WebGlUniformLocation>,
}
#[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<WebGlProgramParameters>,
}
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<WebGlUniform>,
}
pub struct WebGlShader {
gl_shader: web_sys::WebGlShader,
}