Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove all the uniforms #346

Merged
merged 6 commits into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 5 additions & 26 deletions webrender/build_gfx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const MAX_INPUT_ATTRIBUTES: u32 = 16;

const DESCRIPTOR_SET_PER_PASS: u32 = 0;
const DESCRIPTOR_SET_PER_GROUP: u32 = 1;
const DESCRIPTOR_SET_PER_DRAW: u32 = 2;
const DESCRIPTOR_SET_LOCALS: u32 = 3;
const DESCRIPTOR_SET_PER_TARGET: u32 = 2;
const DESCRIPTOR_SET_PER_DRAW: u32 = 3;

#[derive(Deserialize)]
struct Shader {
Expand Down Expand Up @@ -255,17 +255,7 @@ fn process_glsl_for_spirv(file_path: &Path, file_name: &str) -> Option<PipelineR
new_data.push_str(&line);
new_data.push('\n');
} else {
if l.contains("uTransform") {
new_data.push_str("\t\t\tmat4 _transform;\n\t\t\tif (push_constants) { _transform = pushConstants.uTransform; } else { _transform = uTransform; }\n");
}
if l.contains("uMode") {
new_data.push_str("\t\t\tint _umode;\n\t\t\tif (push_constants) { _umode = pushConstants.uMode; } else { _umode = uMode; }\n");
}
new_data.push_str(
&l
.replace("uTransform", "_transform")
.replace("uMode", "_umode")
);
new_data.push_str(&l);
new_data.push('\n');
}
}
Expand Down Expand Up @@ -341,22 +331,11 @@ fn extend_sampler_definition(
}

fn replace_non_sampler_uniforms(new_data: &mut String) {
new_data.push_str(
"\tlayout(push_constant) uniform PushConsts {\n\
\t\tmat4 uTransform; // Orthographic projection\n\
\t\t// A generic uniform that shaders can optionally use to configure\n\
\t\t// an operation mode for this batch.\n\
\t\tint uMode;\n\
\t} pushConstants;\n",
);
new_data.push_str(&format!(
"\tlayout(set = {}, binding = 0) uniform Locals {{\n\
"\tlayout(set = {}, binding = 0) uniform Projection {{\n\
\t\tuniform mat4 uTransform; // Orthographic projection\n\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we still having the transform here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have a misunderstanding here, looks like I didn't payed attention what you mentioned in #345

WebRender has it associated with the target, so we can safely move it into a constant buffer within the per-target descriptor set.

Unfortunately we don't have descriptor sets on a per target basis, we have the following groups: global (for each rendering loop), per WR pass and per draw. (The per-target variant would fit somewhere between second and third one.) That's the reason why I kept the uniform block around. If you think that getting rid of the uniform block and introducing a new descriptor binding with a new set index which points to a buffer could benefit us, I can make those changes as well.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can safely just adopt the "per pass" descriptor set and increase its frequency just a bit to bind whenever the projection happens. This is still relatively rare, i.e. dozens per frame, not thousands.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's sounds totally reasonable. Also I will add a more descriptive name to it.

\t\t// A generic uniform that shaders can optionally use to configure\n\
\t\t// an operation mode for this batch.\n\
\t\tuniform int uMode;\n\
\t}};\n",
DESCRIPTOR_SET_LOCALS
DESCRIPTOR_SET_PER_TARGET
));
}

Expand Down
2 changes: 0 additions & 2 deletions webrender/res/base.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ const bool antialiasing =
false;
#endif

const bool push_constants = false;

#if defined(GL_ES)
#if GL_ES == 1
#ifdef GL_FRAGMENT_PRECISION_HIGH
Expand Down
2 changes: 1 addition & 1 deletion webrender/res/base_gfx.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ layout(constant_id = 3) const bool dithering = false;
layout(constant_id = 4) const bool debug_overdraw = false;
layout(constant_id = 5) const bool repetition = false;
layout(constant_id = 6) const bool antialiasing = false;
layout(constant_id = 7) const bool push_constants = true;
layout(constant_id = 7) const int uMode = 0;

#if defined(GL_ES)
#if GL_ES == 1
Expand Down
4 changes: 4 additions & 0 deletions webrender/src/debug_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ impl DebugRenderer {
true,
);

#[cfg(not(feature = "gl"))]
{
device.reset_draw_target(Some(&projection));
}
// Triangles
if !self.tri_vertices.is_empty() {
device.bind_program(&self.color_program);
Expand Down
162 changes: 129 additions & 33 deletions webrender/src/device/gfx/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use arrayvec::ArrayVec;
use hal;
use hal::device::Device as BackendDevice;
use rendy_descriptor::{DescriptorAllocator, DescriptorSet};
use rendy_memory::{Block, Heaps, Kind, MappedRange, MemoryBlock, MemoryUsage, MemoryUsageValue, Write};

use std::cell::Cell;
use std::sync::Arc;
use std::mem;

use super::{MAX_FRAME_COUNT};
use super::descriptor::{DescriptorData, DescriptorGroup};

pub const DOWNLOAD_BUFFER_SIZE: usize = 10 << 20; // 10MB
// Maximum number of bound projections per frame.
// Projections are bound on a per render target basis, so those should fit in the 96 limit.
// We need this limit to define a fixed size for our uniform buffers.
pub const PROJECTION_PER_FRAME: usize = 96;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are we checking if we hit this limit?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


#[derive(MallocSizeOf)]
pub struct BufferMemorySlice {
Expand Down Expand Up @@ -325,6 +334,7 @@ impl<B: hal::Backend> Buffer<B> {
let size = (data.len() * self.stride) as u64;
let range =
offset..((offset + size + non_coherent_atom_size_mask) & !non_coherent_atom_size_mask);

unsafe {
let mut mapped = self
.memory_block
Expand All @@ -333,7 +343,7 @@ impl<B: hal::Backend> Buffer<B> {
mapped
.write(device, 0..size)
.expect("Writer creation failed")
.write(&data);
.write(data);
}
self.memory_block.unmap(device);
size as usize
Expand Down Expand Up @@ -703,56 +713,142 @@ impl<B: hal::Backend> VertexBufferHandler<B> {
}
}

pub(super) struct UniformBufferHandler<B: hal::Backend> {
buffers: Vec<Buffer<B>>,
offset: usize,
buffer_usage: hal::buffer::Usage,
data_stride: usize,
pitch_alignment_mask: usize,
struct DynamicBufferBundle<B: hal::Backend> {
buffer: Buffer<B>,
buffer_offset: u32,
descriptor_set: DescriptorSet<B>,
}

impl<B: hal::Backend> UniformBufferHandler<B> {
pub(super) fn new(
impl<B: hal::Backend> DynamicBufferBundle<B> {
unsafe fn new(
buffer_usage: hal::buffer::Usage,
data_stride: usize,
pitch_alignment_mask: usize,
min_uniform_buffer_offset_alignment_mask: usize,
device: &B::Device,
heaps: &mut Heaps<B>,
descriptor_set: DescriptorSet<B>
) -> Self {
UniformBufferHandler {
buffers: vec![],
offset: 0,
debug_assert!(data_stride.is_power_of_two());
let data_stride = ((data_stride - 1) | min_uniform_buffer_offset_alignment_mask) + 1;
let buffer = Buffer::new(
device,
heaps,
MemoryUsageValue::Dynamic,
buffer_usage,
min_uniform_buffer_offset_alignment_mask,
PROJECTION_PER_FRAME,
data_stride,
pitch_alignment_mask,
);
device.write_descriptor_sets(Some(hal::pso::DescriptorSetWrite {
set: descriptor_set.raw(),
binding: 0,
array_offset: 0,
descriptors: Some(hal::pso::Descriptor::Buffer(
&buffer.buffer,
Some(0)..None,
)),
}));
DynamicBufferBundle {
buffer,
buffer_offset: 0,
descriptor_set,
}

}

fn add<T: Copy>(
&mut self,
device: &B::Device,
data: &[T],
non_coherent_atom_size_mask: u64,
) {
debug_assert!(self.buffer_offset < PROJECTION_PER_FRAME as _);
let _ = self.buffer.update(device, data, self.buffer_offset as usize, non_coherent_atom_size_mask);
self.buffer_offset += 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where are we

}

fn last_update_start_offset(&self) -> u32 {
// buffer_offset points to the end of the last update, but we need the starting offset
(self.buffer_offset - 1) * self.buffer.stride as u32
}

fn reset(&mut self) {
self.buffer_offset = 0;
}

unsafe fn deinit(self, device: &B::Device, heaps: &mut Heaps<B>, allocator: &mut DescriptorAllocator<B>) {
self.buffer.deinit(device, heaps);
allocator.free(std::iter::once(self.descriptor_set));
}
}

pub(super) struct UniformBufferHandler<B: hal::Backend> {
buffer_bundles: ArrayVec<[DynamicBufferBundle<B>; MAX_FRAME_COUNT]>,
min_uniform_buffer_offset_alignment_mask: usize,
}

pub(super) fn add<T: Copy>(&mut self, device: &B::Device, data: &[T], heaps: &mut Heaps<B>) {
if self.buffers.len() == self.offset {
self.buffers.push(Buffer::new(
impl<B: hal::Backend> UniformBufferHandler<B> {
pub(super) fn new(
data_stride: usize,
min_uniform_buffer_offset_alignment_mask: usize,
frame_count: usize,
device: &B::Device,
heaps: &mut Heaps<B>,
descriptor_allocator: &mut DescriptorAllocator<B>,
group_data: &DescriptorData<B>,
group: &DescriptorGroup,
set_index: usize,
) -> Self {
debug_assert!(frame_count <= MAX_FRAME_COUNT);
let mut descriptors = Vec::new();
let mut buffer_bundles = ArrayVec::new();
unsafe {
descriptor_allocator.allocate(
device,
heaps,
MemoryUsageValue::Dynamic,
self.buffer_usage,
self.pitch_alignment_mask,
data.len(),
self.data_stride,
));
group_data.descriptor_layout(group, set_index),
group_data.ranges(group, set_index),
frame_count as u32,
&mut descriptors,
).expect("Allocate descriptor sets failed");
for _ in 0..frame_count {
buffer_bundles.push(DynamicBufferBundle::new(
hal::buffer::Usage::UNIFORM,
data_stride,
min_uniform_buffer_offset_alignment_mask,
device,
heaps,
descriptors.pop().unwrap(),
));
}
}

UniformBufferHandler {
buffer_bundles,
min_uniform_buffer_offset_alignment_mask,
}
self.buffers[self.offset].update_all(device, data, self.pitch_alignment_mask as u64);
self.offset += 1;
}

pub(super) fn buffer(&self) -> &Buffer<B> {
&self.buffers[self.offset - 1]
pub(super) fn add<T: Copy>(
&mut self,
device: &B::Device,
data: &[T],
next_id: usize,
) {
self.buffer_bundles[next_id].add(device, data, self.min_uniform_buffer_offset_alignment_mask as u64);
}

pub(super) fn reset(&mut self) {
self.offset = 0;
pub(super) fn buffer_info(&self, next_id: usize) -> (&B::DescriptorSet, u32) {
let ref buffer = self.buffer_bundles[next_id];
(buffer.descriptor_set.raw(), buffer.last_update_start_offset())
}

pub(super) fn deinit(self, device: &B::Device, heaps: &mut Heaps<B>) {
for buffer in self.buffers {
buffer.deinit(device, heaps);
pub(super) fn reset(&mut self, next_id: usize) {
self.buffer_bundles[next_id].reset()
}

pub(super) unsafe fn deinit(self, device: &B::Device, heaps: &mut Heaps<B>, allocator: &mut DescriptorAllocator<B>) {
for bundle in self.buffer_bundles {
bundle.deinit(device, heaps, allocator);
}
}
}
Loading