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

Angle depth clear workaround #2126

Merged
merged 2 commits into from Nov 29, 2017
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -1603,29 +1603,11 @@ impl Device {
self.frame_id.0 += 1;
}

pub fn clear_target(&self, color: Option<[f32; 4]>, depth: Option<f32>) {
let mut clear_bits = 0;

if let Some(color) = color {
self.gl.clear_color(color[0], color[1], color[2], color[3]);
clear_bits |= gl::COLOR_BUFFER_BIT;
}

if let Some(depth) = depth {
self.gl.clear_depth(depth as f64);
clear_bits |= gl::DEPTH_BUFFER_BIT;
}

if clear_bits != 0 {
self.gl.clear(clear_bits);
}
}

pub fn clear_target_rect(
pub fn clear_target(
&self,
color: Option<[f32; 4]>,
depth: Option<f32>,
rect: DeviceIntRect,
rect: Option<DeviceIntRect>,
) {
let mut clear_bits = 0;

@@ -1635,20 +1617,28 @@ impl Device {
}

if let Some(depth) = depth {
debug_assert_ne!(self.gl.get_boolean_v(gl::DEPTH_WRITEMASK), 0);
self.gl.clear_depth(depth as f64);
clear_bits |= gl::DEPTH_BUFFER_BIT;
}

if clear_bits != 0 {
self.gl.enable(gl::SCISSOR_TEST);
self.gl.scissor(
rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height,
);
self.gl.clear(clear_bits);
self.gl.disable(gl::SCISSOR_TEST);
match rect {
Some(rect) => {
self.gl.enable(gl::SCISSOR_TEST);
self.gl.scissor(
rect.origin.x,
rect.origin.y,
rect.size.width,
rect.size.height,
);
self.gl.clear(clear_bits);
self.gl.disable(gl::SCISSOR_TEST);
}
None => {
self.gl.clear(clear_bits);
}
}
}
}

@@ -64,7 +64,8 @@ use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use texture_cache::TextureCache;
use thread_profiler::{register_thread_with_profiler, write_profile};
use tiling::{AlphaRenderTarget, ColorRenderTarget, RenderPassKind, RenderTargetKind, RenderTargetList};
use tiling::{AlphaRenderTarget, ColorRenderTarget};
use tiling::{RenderPass, RenderPassKind, RenderTargetKind, RenderTargetList};
use tiling::{BatchKey, BatchKind, BrushBatchKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
use time::precise_time_ns;
use util::TransformedRectKind;
@@ -2330,6 +2331,32 @@ impl Renderer {
(cpu_profiles, gpu_profiles)
}

/// Returns `true` if the active rendered documents (that need depth buffer)
/// intersect on the main framebuffer, in which case we don't clear
/// the whole depth and instead clear each document area separately.
fn are_documents_intersecting_depth(&self) -> bool {
let document_rects = self.active_documents
.iter()
.filter_map(|&(_, ref render_doc)| {
match render_doc.frame.passes.last() {
Some(&RenderPass { kind: RenderPassKind::MainFramebuffer(ref target), .. })
if target.needs_depth() => Some(render_doc.frame.inner_rect),
_ => None,
}
})
.collect::<Vec<_>>();

for (i, rect) in document_rects.iter().enumerate() {
for other in &document_rects[i+1 ..] {
if rect.intersects(other) {
return true
}
}
}

false
}

/// Renders the current frame.
///
/// A Frame is supplied by calling [`generate_frame()`][genframe].
@@ -2388,23 +2415,36 @@ impl Renderer {
});

profile_timers.cpu_time.profile(|| {
let clear_depth_value = if self.are_documents_intersecting_depth() {
None
} else {
Some(1.0)
};

//Note: another borrowck dance
let mut active_documents = mem::replace(&mut self.active_documents, Vec::default());
// sort by the document layer id
active_documents.sort_by_key(|&(_, ref render_doc)| render_doc.frame.layer);

let needs_clear = !active_documents
// don't clear the framebuffer if one of the rendered documents will overwrite it
let needs_color_clear = !active_documents
.iter()
.any(|&(_, RenderedDocument { ref frame, .. })| {
frame.background_color.is_some() &&
frame.inner_rect.origin == DeviceUintPoint::zero() &&
frame.inner_rect.size == framebuffer_size
});
// don't clear the framebuffer if one of the rendered documents will overwrite it
if needs_clear {
let clear_color = self.clear_color.map(|color| color.to_array());

if needs_color_clear || clear_depth_value.is_some() {
let clear_color = if needs_color_clear {
self.clear_color.map(|color| color.to_array())
} else {
None
};
self.device.bind_draw_target(None, None);
self.device.clear_target(clear_color, None);
self.device.enable_depth_write();
self.device.clear_target(clear_color, clear_depth_value, None);
self.device.disable_depth_write();
}

// Re-use whatever targets possible from the pool, before
@@ -2419,6 +2459,7 @@ impl Renderer {
self.draw_tile_frame(
frame,
framebuffer_size,
clear_depth_value.is_some(),
cpu_frame_id,
&mut stats
);
@@ -2913,6 +2954,7 @@ impl Renderer {
target: &ColorRenderTarget,
framebuffer_target_rect: DeviceUintRect,
target_size: DeviceUintSize,
depth_is_ready: bool,
clear_color: Option<[f32; 4]>,
render_tasks: &RenderTaskTree,
projection: &Transform3D<f32>,
@@ -2933,38 +2975,37 @@ impl Renderer {
self.device.disable_depth();
self.device.set_blend(false);

let depth_clear = if target.needs_depth() {
let depth_clear = if !depth_is_ready && target.needs_depth() {
self.device.enable_depth_write();
Some(1.0)
} else {
None
};

if render_target.is_some() {
let clear_rect = if render_target.is_some() {
if self.enable_clear_scissor {
// TODO(gw): Applying a scissor rect and minimal clear here
// is a very large performance win on the Intel and nVidia
// GPUs that I have tested with. It's possible it may be a
// performance penalty on other GPU types - we should test this
// and consider different code paths.
self.device.clear_target_rect(clear_color, depth_clear, target.used_rect());
Some(target.used_rect())
} else {
self.device.clear_target(clear_color, depth_clear);
None
}
} else if framebuffer_target_rect == DeviceUintRect::new(DeviceUintPoint::zero(), target_size) {
// whole screen is covered, no need for scissor
self.device.clear_target(clear_color, depth_clear);
None
} else {
// Note: for non-intersecting document rectangles,
// we can omit clearing the depth here, and instead
// just clear it for the whole framebuffer at start of the frame.
let mut clear_rect = framebuffer_target_rect.to_i32();
let mut rect = framebuffer_target_rect.to_i32();
// Note: `framebuffer_target_rect` needs a Y-flip before going to GL
// Note: at this point, the target rectangle is not guaranteed to be within the main framebuffer bounds
// but `clear_target_rect` is totally fine with negative origin, as long as width & height are positive
clear_rect.origin.y = target_size.height as i32 - clear_rect.origin.y - clear_rect.size.height;
self.device.clear_target_rect(clear_color, depth_clear, clear_rect);
}
rect.origin.y = target_size.height as i32 - rect.origin.y - rect.size.height;
Some(rect)
};

self.device.clear_target(clear_color, depth_clear, clear_rect);

if depth_clear.is_some() {
self.device.disable_depth_write();
@@ -3357,14 +3398,20 @@ impl Renderer {
// performance penalty on other GPU types - we should test this
// and consider different code paths.
let clear_color = [1.0, 1.0, 1.0, 0.0];
self.device
.clear_target_rect(Some(clear_color), None, target.used_rect());
self.device.clear_target(
Some(clear_color),
None,
Some(target.used_rect()),
);

let zero_color = [0.0, 0.0, 0.0, 0.0];
for &task_id in &target.zero_clears {
let (rect, _) = render_tasks[task_id].get_target_rect();
self.device
.clear_target_rect(Some(zero_color), None, rect);
self.device.clear_target(
Some(zero_color),
None,
Some(rect),
);
}
}

@@ -3693,6 +3740,7 @@ impl Renderer {
&mut self,
frame: &mut Frame,
framebuffer_size: DeviceUintSize,
framebuffer_depth_is_ready: bool,
frame_id: FrameId,
stats: &mut RendererStats,
) {
@@ -3742,6 +3790,7 @@ impl Renderer {
target,
frame.inner_rect,
framebuffer_size,
framebuffer_depth_is_ready,
clear_color,
&frame.render_tasks,
&projection,
@@ -3794,6 +3843,7 @@ impl Renderer {
target,
frame.inner_rect,
color.max_size,
false,
Some([0.0, 0.0, 0.0, 0.0]),
&frame.render_tasks,
&projection,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.