Update the debug UI

This commit is contained in:
Patrick Walton 2020-06-23 12:40:51 -07:00
parent ff7c13c8fb
commit 61833168e5
21 changed files with 494 additions and 224 deletions

3
Cargo.lock generated
View File

@ -1788,8 +1788,10 @@ name = "pathfinder_gpu"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.23.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_color 0.5.0", "pathfinder_color 0.5.0",
"pathfinder_geometry 0.5.1", "pathfinder_geometry 0.5.1",
"pathfinder_resources 0.5.0", "pathfinder_resources 0.5.0",
@ -1837,6 +1839,7 @@ dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", "cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"dispatch 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"io-surface 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "io-surface 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -15,10 +15,12 @@
//! //!
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/ //! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
use crate::gpu::renderer::{RenderStats, RenderTime}; use crate::gpu::options::RendererLevel;
use pathfinder_geometry::vector::{Vector2I, vec2i}; use crate::gpu::perf::{RenderStats, RenderTime};
use pathfinder_geometry::rect::RectI; use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::{Vector2I, vec2i};
use pathfinder_gpu::Device; use pathfinder_gpu::Device;
use pathfinder_gpu::allocator::GPUMemoryAllocator;
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR}; use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UIPresenter, WINDOW_COLOR};
use std::collections::VecDeque; use std::collections::VecDeque;
@ -27,35 +29,39 @@ use std::time::Duration;
const SAMPLE_BUFFER_SIZE: usize = 60; const SAMPLE_BUFFER_SIZE: usize = 60;
const STATS_WINDOW_WIDTH: i32 = 325; const STATS_WINDOW_WIDTH: i32 = 275;
const STATS_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2; const STATS_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2;
const PERFORMANCE_WINDOW_WIDTH: i32 = 400; const PERFORMANCE_WINDOW_WIDTH: i32 = 400;
const PERFORMANCE_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 4 + PADDING + 2; const PERFORMANCE_WINDOW_HEIGHT_D3D9: i32 = LINE_HEIGHT * 8 + PADDING + 2;
const PERFORMANCE_WINDOW_HEIGHT_D3D11: i32 = LINE_HEIGHT * 10 + PADDING + 2;
pub struct DebugUIPresenter<D> const INFO_WINDOW_WIDTH: i32 = 425;
where const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
D: Device,
{ pub struct DebugUIPresenter<D> where D: Device {
pub ui_presenter: UIPresenter<D>, pub ui_presenter: UIPresenter<D>,
cpu_samples: SampleBuffer<RenderStats>, cpu_samples: SampleBuffer<RenderStats>,
gpu_samples: SampleBuffer<RenderTime>, gpu_samples: SampleBuffer<RenderTime>,
backend_name: &'static str,
device_name: String,
renderer_level: RendererLevel,
} }
impl<D> DebugUIPresenter<D> impl<D> DebugUIPresenter<D> where D: Device {
where pub fn new(device: &D,
D: Device,
{
pub fn new(
device: &D,
resources: &dyn ResourceLoader, resources: &dyn ResourceLoader,
framebuffer_size: Vector2I, framebuffer_size: Vector2I,
) -> DebugUIPresenter<D> { renderer_level: RendererLevel)
-> DebugUIPresenter<D> {
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size); let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
DebugUIPresenter { DebugUIPresenter {
ui_presenter, ui_presenter,
cpu_samples: SampleBuffer::new(), cpu_samples: SampleBuffer::new(),
gpu_samples: SampleBuffer::new(), gpu_samples: SampleBuffer::new(),
backend_name: device.backend_name(),
device_name: device.device_name(),
renderer_level,
} }
} }
@ -64,84 +70,222 @@ where
self.gpu_samples.push(rendering_time); self.gpu_samples.push(rendering_time);
} }
pub fn draw(&self, device: &D) { pub fn draw(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
self.draw_stats_window(device); self.draw_stats_window(device, allocator);
self.draw_performance_window(device); self.draw_performance_window(device, allocator);
self.draw_info_window(device, allocator);
} }
fn draw_stats_window(&self, device: &D) { #[inline]
pub fn set_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) {
self.ui_presenter.set_framebuffer_size(new_framebuffer_size)
}
fn draw_info_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
let framebuffer_size = self.ui_presenter.framebuffer_size();
let bottom = framebuffer_size.y() - PADDING;
let window_rect = RectI::new(
vec2i(framebuffer_size.x() - PADDING - INFO_WINDOW_WIDTH,
bottom - INFO_WINDOW_HEIGHT),
vec2i(INFO_WINDOW_WIDTH, INFO_WINDOW_HEIGHT),
);
self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
let level = match self.renderer_level {
RendererLevel::D3D9 => "D3D9",
RendererLevel::D3D11 => "D3D11",
};
self.ui_presenter.draw_text(device,
allocator,
&format!("{} ({} level)", self.backend_name, level),
origin + vec2i(0, LINE_HEIGHT * 0),
false);
self.ui_presenter.draw_text(device,
allocator,
&self.device_name,
origin + vec2i(0, LINE_HEIGHT * 1),
false);
}
fn performance_window_size(&self) -> Vector2I {
match self.renderer_level {
RendererLevel::D3D9 => vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT_D3D9),
RendererLevel::D3D11 => {
vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT_D3D11)
}
}
}
fn draw_stats_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
let performance_window_height = self.performance_window_size().y();
let framebuffer_size = self.ui_presenter.framebuffer_size(); let framebuffer_size = self.ui_presenter.framebuffer_size();
let bottom = framebuffer_size.y() - PADDING; let bottom = framebuffer_size.y() - PADDING;
let window_rect = RectI::new( let window_rect = RectI::new(
vec2i(framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH, vec2i(framebuffer_size.x() - PADDING - STATS_WINDOW_WIDTH,
bottom - PERFORMANCE_WINDOW_HEIGHT - PADDING - STATS_WINDOW_HEIGHT), bottom -
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT), PADDING -
); INFO_WINDOW_HEIGHT -
performance_window_height -
PADDING -
STATS_WINDOW_HEIGHT),
vec2i(STATS_WINDOW_WIDTH, STATS_WINDOW_HEIGHT));
self.ui_presenter.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR); self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
let mean_cpu_sample = self.cpu_samples.mean(); let mean_cpu_sample = self.cpu_samples.mean();
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT); let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
allocator,
&format!("Paths: {}", mean_cpu_sample.path_count), &format!("Paths: {}", mean_cpu_sample.path_count),
origin, origin,
false, false,
); );
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
&format!("Solid Tiles: {}", mean_cpu_sample.solid_tile_count), allocator,
&format!("Tiles: {}", mean_cpu_sample.total_tile_count),
origin + vec2i(0, LINE_HEIGHT * 1), origin + vec2i(0, LINE_HEIGHT * 1),
false, false,
); );
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
&format!("Alpha Tiles: {}", mean_cpu_sample.alpha_tile_count), allocator,
&format!("Masks: {}", mean_cpu_sample.alpha_tile_count),
origin + vec2i(0, LINE_HEIGHT * 2), origin + vec2i(0, LINE_HEIGHT * 2),
false, false,
); );
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
allocator,
&format!("Fills: {}", mean_cpu_sample.fill_count), &format!("Fills: {}", mean_cpu_sample.fill_count),
origin + vec2i(0, LINE_HEIGHT * 3), origin + vec2i(0, LINE_HEIGHT * 3),
false, false,
); );
} }
fn draw_performance_window(&self, device: &D) { fn draw_performance_window(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
let performance_window_size = self.performance_window_size();
let framebuffer_size = self.ui_presenter.framebuffer_size(); let framebuffer_size = self.ui_presenter.framebuffer_size();
let bottom = framebuffer_size.y() - PADDING; let bottom = framebuffer_size.y() - PADDING;
let window_rect = RectI::new( let window_rect = RectI::new(
vec2i(framebuffer_size.x() - PADDING - PERFORMANCE_WINDOW_WIDTH, vec2i(framebuffer_size.x() - PADDING - performance_window_size.x(),
bottom - PERFORMANCE_WINDOW_HEIGHT), bottom - INFO_WINDOW_HEIGHT - PADDING - performance_window_size.y()),
vec2i(PERFORMANCE_WINDOW_WIDTH, PERFORMANCE_WINDOW_HEIGHT), performance_window_size);
);
self.ui_presenter.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR); self.ui_presenter.draw_solid_rounded_rect(device, allocator, window_rect, WINDOW_COLOR);
let mean_cpu_sample = self.cpu_samples.mean(); let mean_cpu_sample = self.cpu_samples.mean();
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
self.ui_presenter.draw_text(
device,
&format!("CPU: {:.3} ms", duration_to_ms(mean_cpu_sample.cpu_build_time)),
origin,
false,
);
let mean_gpu_sample = self.gpu_samples.mean(); let mean_gpu_sample = self.gpu_samples.mean();
let origin = window_rect.origin() + vec2i(PADDING, PADDING + FONT_ASCENT);
let mut current_y = 0;
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
&format!("GPU: {:.3} ms", duration_to_ms(mean_gpu_sample.gpu_time)), allocator,
origin + vec2i(0, LINE_HEIGHT * 1), &format!("Drawcalls: {}", mean_cpu_sample.drawcall_count),
origin + vec2i(0, current_y),
false, false,
); );
current_y += LINE_HEIGHT;
let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.gpu_time),
duration_to_ms(mean_cpu_sample.cpu_build_time));
self.ui_presenter.draw_text( self.ui_presenter.draw_text(
device, device,
allocator,
&format!("VRAM Alloc.: {:.1} MB",
mean_cpu_sample.gpu_bytes_allocated as f64 / (1024.0 * 1024.0)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
self.ui_presenter.draw_text(
device,
allocator,
&format!("VRAM Commit: {:.1} MB",
mean_cpu_sample.gpu_bytes_committed as f64 / (1024.0 * 1024.0)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
self.ui_presenter.draw_text(
device,
allocator,
&format!("CPU: {:.3} ms", duration_to_ms(mean_cpu_sample.cpu_build_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
match self.renderer_level {
RendererLevel::D3D11 => {
self.ui_presenter.draw_text(
device,
allocator,
&format!("GPU Dice: {:.3} ms", duration_to_ms(mean_gpu_sample.dice_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
self.ui_presenter.draw_text(
device,
allocator,
&format!("GPU Bin: {:.3} ms", duration_to_ms(mean_gpu_sample.bin_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
}
RendererLevel::D3D9 => {}
}
self.ui_presenter.draw_text(
device,
allocator,
&format!("GPU Fill: {:.3} ms", duration_to_ms(mean_gpu_sample.fill_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
self.ui_presenter.draw_text(
device,
allocator,
&format!("GPU Comp.: {:.3} ms", duration_to_ms(mean_gpu_sample.composite_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
self.ui_presenter.draw_text(
device,
allocator,
&format!("GPU Other: {:.3} ms", duration_to_ms(mean_gpu_sample.other_time)),
origin + vec2i(0, current_y),
false,
);
current_y += LINE_HEIGHT;
let mut wallclock_time = match self.renderer_level {
RendererLevel::D3D11 => {
duration_to_ms(mean_cpu_sample.cpu_build_time) +
duration_to_ms(mean_gpu_sample.fill_time)
}
RendererLevel::D3D9 => {
f64::max(duration_to_ms(mean_cpu_sample.cpu_build_time),
duration_to_ms(mean_gpu_sample.fill_time))
}
};
wallclock_time += duration_to_ms(mean_gpu_sample.composite_time) +
duration_to_ms(mean_gpu_sample.dice_time) +
duration_to_ms(mean_gpu_sample.bin_time) +
duration_to_ms(mean_gpu_sample.other_time);
self.ui_presenter.draw_text(
device,
allocator,
&format!("Wallclock: {:.3} ms", wallclock_time), &format!("Wallclock: {:.3} ms", wallclock_time),
origin + vec2i(0, LINE_HEIGHT * 3), origin + vec2i(0, current_y),
false, false,
); );
} }

View File

@ -7,69 +7,88 @@ shaders/gl3/blit.fs.glsl
shaders/gl3/blit.vs.glsl shaders/gl3/blit.vs.glsl
shaders/gl3/clear.fs.glsl shaders/gl3/clear.fs.glsl
shaders/gl3/clear.vs.glsl shaders/gl3/clear.vs.glsl
shaders/gl3/debug_solid.fs.glsl shaders/gl3/d3d9/fill.fs.glsl
shaders/gl3/debug_solid.vs.glsl shaders/gl3/d3d9/fill.vs.glsl
shaders/gl3/debug_texture.fs.glsl shaders/gl3/d3d9/tile.fs.glsl
shaders/gl3/debug_texture.vs.glsl shaders/gl3/d3d9/tile.vs.glsl
shaders/gl3/d3d9/tile_clip_combine.fs.glsl
shaders/gl3/d3d9/tile_clip_combine.vs.glsl
shaders/gl3/d3d9/tile_clip_copy.fs.glsl
shaders/gl3/d3d9/tile_clip_copy.vs.glsl
shaders/gl3/d3d9/tile_copy.fs.glsl
shaders/gl3/d3d9/tile_copy.vs.glsl
shaders/gl3/debug/solid.fs.glsl
shaders/gl3/debug/solid.vs.glsl
shaders/gl3/debug/texture.fs.glsl
shaders/gl3/debug/texture.vs.glsl
shaders/gl3/demo_ground.fs.glsl shaders/gl3/demo_ground.fs.glsl
shaders/gl3/demo_ground.vs.glsl shaders/gl3/demo_ground.vs.glsl
shaders/gl3/fill.fs.glsl
shaders/gl3/fill.vs.glsl
shaders/gl3/reproject.fs.glsl shaders/gl3/reproject.fs.glsl
shaders/gl3/reproject.vs.glsl shaders/gl3/reproject.vs.glsl
shaders/gl3/stencil.fs.glsl shaders/gl3/stencil.fs.glsl
shaders/gl3/stencil.vs.glsl shaders/gl3/stencil.vs.glsl
shaders/gl3/tile.fs.glsl
shaders/gl3/tile.vs.glsl
shaders/gl3/tile_clip.fs.glsl
shaders/gl3/tile_clip.vs.glsl
shaders/gl3/tile_copy.fs.glsl
shaders/gl3/tile_copy.vs.glsl
shaders/gl4/blit.fs.glsl shaders/gl4/blit.fs.glsl
shaders/gl4/blit.vs.glsl shaders/gl4/blit.vs.glsl
shaders/gl4/clear.fs.glsl shaders/gl4/clear.fs.glsl
shaders/gl4/clear.vs.glsl shaders/gl4/clear.vs.glsl
shaders/gl4/debug_solid.fs.glsl shaders/gl4/d3d11/bin.cs.glsl
shaders/gl4/debug_solid.vs.glsl shaders/gl4/d3d11/bound.cs.glsl
shaders/gl4/debug_texture.fs.glsl shaders/gl4/d3d11/dice.cs.glsl
shaders/gl4/debug_texture.vs.glsl shaders/gl4/d3d11/fill.cs.glsl
shaders/gl4/d3d11/propagate.cs.glsl
shaders/gl4/d3d11/sort.cs.glsl
shaders/gl4/d3d11/tile.cs.glsl
shaders/gl4/d3d9/fill.fs.glsl
shaders/gl4/d3d9/fill.vs.glsl
shaders/gl4/d3d9/tile.fs.glsl
shaders/gl4/d3d9/tile.vs.glsl
shaders/gl4/d3d9/tile_clip_combine.fs.glsl
shaders/gl4/d3d9/tile_clip_combine.vs.glsl
shaders/gl4/d3d9/tile_clip_copy.fs.glsl
shaders/gl4/d3d9/tile_clip_copy.vs.glsl
shaders/gl4/d3d9/tile_copy.fs.glsl
shaders/gl4/d3d9/tile_copy.vs.glsl
shaders/gl4/debug/solid.fs.glsl
shaders/gl4/debug/solid.vs.glsl
shaders/gl4/debug/texture.fs.glsl
shaders/gl4/debug/texture.vs.glsl
shaders/gl4/demo_ground.fs.glsl shaders/gl4/demo_ground.fs.glsl
shaders/gl4/demo_ground.vs.glsl shaders/gl4/demo_ground.vs.glsl
shaders/gl4/fill.fs.glsl
shaders/gl4/fill.vs.glsl
shaders/gl4/reproject.fs.glsl shaders/gl4/reproject.fs.glsl
shaders/gl4/reproject.vs.glsl shaders/gl4/reproject.vs.glsl
shaders/gl4/stencil.fs.glsl shaders/gl4/stencil.fs.glsl
shaders/gl4/stencil.vs.glsl shaders/gl4/stencil.vs.glsl
shaders/gl4/tile.fs.glsl
shaders/gl4/tile.vs.glsl
shaders/gl4/tile_clip.fs.glsl
shaders/gl4/tile_clip.vs.glsl
shaders/gl4/tile_copy.fs.glsl
shaders/gl4/tile_copy.vs.glsl
shaders/metal/blit.fs.metal shaders/metal/blit.fs.metal
shaders/metal/blit.vs.metal shaders/metal/blit.vs.metal
shaders/metal/clear.fs.metal shaders/metal/clear.fs.metal
shaders/metal/clear.vs.metal shaders/metal/clear.vs.metal
shaders/metal/debug_solid.fs.metal shaders/metal/d3d11/bin.cs.metal
shaders/metal/debug_solid.vs.metal shaders/metal/d3d11/bound.cs.metal
shaders/metal/debug_texture.fs.metal shaders/metal/d3d11/dice.cs.metal
shaders/metal/debug_texture.vs.metal shaders/metal/d3d11/fill.cs.metal
shaders/metal/d3d11/propagate.cs.metal
shaders/metal/d3d11/sort.cs.metal
shaders/metal/d3d11/tile.cs.metal
shaders/metal/d3d9/fill.fs.metal
shaders/metal/d3d9/fill.vs.metal
shaders/metal/d3d9/tile.fs.metal
shaders/metal/d3d9/tile.vs.metal
shaders/metal/d3d9/tile_clip_combine.fs.metal
shaders/metal/d3d9/tile_clip_combine.vs.metal
shaders/metal/d3d9/tile_clip_copy.fs.metal
shaders/metal/d3d9/tile_clip_copy.vs.metal
shaders/metal/d3d9/tile_copy.fs.metal
shaders/metal/d3d9/tile_copy.vs.metal
shaders/metal/debug/solid.fs.metal
shaders/metal/debug/solid.vs.metal
shaders/metal/debug/texture.fs.metal
shaders/metal/debug/texture.vs.metal
shaders/metal/demo_ground.fs.metal shaders/metal/demo_ground.fs.metal
shaders/metal/demo_ground.vs.metal shaders/metal/demo_ground.vs.metal
shaders/metal/fill.cs.metal
shaders/metal/fill.fs.metal
shaders/metal/fill.vs.metal
shaders/metal/reproject.fs.metal shaders/metal/reproject.fs.metal
shaders/metal/reproject.vs.metal shaders/metal/reproject.vs.metal
shaders/metal/stencil.fs.metal shaders/metal/stencil.fs.metal
shaders/metal/stencil.vs.metal shaders/metal/stencil.vs.metal
shaders/metal/tile.fs.metal
shaders/metal/tile.vs.metal
shaders/metal/tile_clip.fs.metal
shaders/metal/tile_clip.vs.metal
shaders/metal/tile_copy.fs.metal
shaders/metal/tile_copy.vs.metal
textures/area-lut.png textures/area-lut.png
textures/debug-corner-fill.png textures/debug-corner-fill.png
textures/debug-corner-outline.png textures/debug-corner-outline.png

View File

@ -3,36 +3,47 @@ TARGET_DIR?=../resources/shaders
EMPTY= EMPTY=
SHADERS=\ SHADERS=\
d3d9/fill.fs.glsl \
d3d9/fill.vs.glsl \
d3d9/tile.fs.glsl \
d3d9/tile.vs.glsl \
d3d9/tile_clip_combine.fs.glsl \
d3d9/tile_clip_combine.vs.glsl \
d3d9/tile_clip_copy.fs.glsl \
d3d9/tile_clip_copy.vs.glsl \
d3d9/tile_copy.fs.glsl \
d3d9/tile_copy.vs.glsl \
debug/solid.fs.glsl \
debug/solid.vs.glsl \
debug/texture.fs.glsl \
debug/texture.vs.glsl \
blit.fs.glsl \ blit.fs.glsl \
blit.vs.glsl \ blit.vs.glsl \
clear.fs.glsl \ clear.fs.glsl \
clear.vs.glsl \ clear.vs.glsl \
debug_solid.fs.glsl \
debug_solid.vs.glsl \
debug_texture.fs.glsl \
debug_texture.vs.glsl \
demo_ground.fs.glsl \ demo_ground.fs.glsl \
demo_ground.vs.glsl \ demo_ground.vs.glsl \
fill.fs.glsl \
fill.vs.glsl \
reproject.fs.glsl \ reproject.fs.glsl \
reproject.vs.glsl \ reproject.vs.glsl \
stencil.fs.glsl \ stencil.fs.glsl \
stencil.vs.glsl \ stencil.vs.glsl \
tile.fs.glsl \
tile.vs.glsl \
tile_clip.fs.glsl \
tile_clip.vs.glsl \
tile_copy.fs.glsl \
tile_copy.vs.glsl \
$(EMPTY) $(EMPTY)
COMPUTE_SHADERS=\ COMPUTE_SHADERS=\
fill.cs.glsl \ d3d11/bin.cs.glsl \
d3d11/bound.cs.glsl \
d3d11/dice.cs.glsl \
d3d11/fill.cs.glsl \
d3d11/propagate.cs.glsl \
d3d11/sort.cs.glsl \
d3d11/tile.cs.glsl \
$(EMPTY) $(EMPTY)
INCLUDES=\ INCLUDES=\
fill.inc.glsl \ d3d11/fill_compute.inc.glsl \
fill_area.inc.glsl \
tile_fragment.inc.glsl \
tile_vertex.inc.glsl \
$(EMPTY) $(EMPTY)
OUT=\ OUT=\
@ -58,6 +69,10 @@ HEADER="// Automatically generated from files in pathfinder/shaders/. Do not edi
GLSL_SED_ARGS=-e "s/\#version .*//" -e "s/\#line.*$$//" GLSL_SED_ARGS=-e "s/\#version .*//" -e "s/\#line.*$$//"
GLSL_SHADER_TYPE.fs=frag
GLSL_SHADER_TYPE.vs=vert
GLSL_SHADER_TYPE.cs=comp
all: $(OUT) all: $(OUT)
.PHONY: clean .PHONY: clean
@ -65,29 +80,14 @@ all: $(OUT)
clean: clean:
rm -f $(OUT) rm -f $(OUT)
build/metal/%.fs.spv: %.fs.glsl $(INCLUDES) build/metal/%.spv: %.glsl $(INCLUDES)
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S frag -o $@ $< mkdir -p $(dir $@) && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -o $@ $<
$(TARGET_DIR)/gl3/%.fs.glsl: %.fs.glsl $(INCLUDES) $(TARGET_DIR)/gl3/%.glsl: %.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) mkdir -p $(dir $@) && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
$(TARGET_DIR)/gl4/%.fs.glsl: %.fs.glsl $(INCLUDES) $(TARGET_DIR)/gl4/%.glsl: %.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S frag -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 ) mkdir -p $(dir $@) && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S $(GLSL_SHADER_TYPE$(suffix $(basename $(notdir $<)))) -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
build/metal/%.vs.spv: %.vs.glsl $(INCLUDES)
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_VERSION) -S vert -o $@ $<
$(TARGET_DIR)/gl3/%.vs.glsl: %.vs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
$(TARGET_DIR)/gl4/%.vs.glsl: %.vs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl3 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
build/metal/%.cs.spv: %.cs.glsl $(INCLUDES)
mkdir -p build/metal && glslangValidator $(GLSLANGFLAGS_METAL) -G$(GLSL_COMPUTE_VERSION) -S comp -o $@ $<
$(TARGET_DIR)/gl4/%.cs.glsl: %.cs.glsl $(INCLUDES)
mkdir -p $(TARGET_DIR)/gl4 && echo $(GLSL_VERSION_HEADER) > $@ && echo $(HEADER) >> $@ && ( glslangValidator $(GLSLANGFLAGS) -S vert -E $< | sed $(GLSL_SED_ARGS) >> $@ ) || ( rm $@ && exit 1 )
$(TARGET_DIR)/metal/%.metal: build/metal/%.spv $(TARGET_DIR)/metal/%.metal: build/metal/%.spv
mkdir -p $(TARGET_DIR)/metal && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< >> $@ ) || ( rm $@ && exit 1 ) mkdir -p $(dir $@) && echo $(HEADER) > $@ && ( $(SPIRVCROSS) $(SPIRVCROSSFLAGS) $< >> $@ ) || ( rm $@ && exit 1 )

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/shaders/debug_solid.fs.glsl // pathfinder/shaders/debug/solid.fs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/shaders/debug_solid.vs.glsl // pathfinder/shaders/debug/solid.vs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/shaders/debug_texture.fs.glsl // pathfinder/shaders/debug/texture.fs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/shaders/debug_texture.vs.glsl // pathfinder/shaders/debug/texture.vs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //

View File

@ -20,9 +20,10 @@ use hashbrown::HashMap;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_geometry::rect::RectI; use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i}; use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i};
use pathfinder_gpu::{BlendFactor, BlendState, BufferData, BufferTarget, BufferUploadMode, Device}; use pathfinder_gpu::allocator::{BufferTag, GPUMemoryAllocator};
use pathfinder_gpu::{Primitive, RenderOptions, RenderState, RenderTarget, TextureFormat}; use pathfinder_gpu::{BlendFactor, BlendState, BufferTarget, Device, Primitive, RenderOptions};
use pathfinder_gpu::{UniformData, VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_gpu::{RenderState, RenderTarget, TextureFormat, UniformData, VertexAttrClass};
use pathfinder_gpu::{VertexAttrDescriptor, VertexAttrType};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use serde_json; use serde_json;
@ -71,9 +72,7 @@ pub struct UIPresenter<D> where D: Device {
framebuffer_size: Vector2I, framebuffer_size: Vector2I,
texture_program: DebugTextureProgram<D>, texture_program: DebugTextureProgram<D>,
texture_vertex_array: DebugTextureVertexArray<D>,
solid_program: DebugSolidProgram<D>, solid_program: DebugSolidProgram<D>,
solid_vertex_array: DebugSolidVertexArray<D>,
font: DebugFont, font: DebugFont,
font_texture: D::Texture, font_texture: D::Texture,
@ -85,11 +84,9 @@ impl<D> UIPresenter<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Vector2I) pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Vector2I)
-> UIPresenter<D> { -> UIPresenter<D> {
let texture_program = DebugTextureProgram::new(device, resources); let texture_program = DebugTextureProgram::new(device, resources);
let texture_vertex_array = DebugTextureVertexArray::new(device, &texture_program);
let font = DebugFont::load(resources); let font = DebugFont::load(resources);
let solid_program = DebugSolidProgram::new(device, resources); let solid_program = DebugSolidProgram::new(device, resources);
let solid_vertex_array = DebugSolidVertexArray::new(device, &solid_program);
let font_texture = device.create_texture_from_png(resources, let font_texture = device.create_texture_from_png(resources,
FONT_PNG_NAME, FONT_PNG_NAME,
@ -108,10 +105,8 @@ impl<D> UIPresenter<D> where D: Device {
framebuffer_size, framebuffer_size,
texture_program, texture_program,
texture_vertex_array,
font, font,
solid_program, solid_program,
solid_vertex_array,
font_texture, font_texture,
corner_fill_texture, corner_fill_texture,
@ -128,16 +123,25 @@ impl<D> UIPresenter<D> where D: Device {
} }
pub fn draw_solid_rect(&self, device: &D, rect: RectI, color: ColorU) { pub fn draw_solid_rect(&self,
self.draw_rect(device, rect, color, true); device: &D,
allocator: &mut GPUMemoryAllocator<D>,
rect: RectI,
color: ColorU) {
self.draw_rect(device, allocator, rect, color, true);
} }
pub fn draw_rect_outline(&self, device: &D, rect: RectI, color: ColorU) { pub fn draw_rect_outline(&self,
self.draw_rect(device, rect, color, false); device: &D,
allocator: &mut GPUMemoryAllocator<D>,
rect: RectI,
color: ColorU) {
self.draw_rect(device, allocator, rect, color, false);
} }
fn draw_rect(&self, fn draw_rect(&self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
rect: RectI, rect: RectI,
color: ColorU, color: ColorU,
filled: bool) { filled: bool) {
@ -150,12 +154,14 @@ impl<D> UIPresenter<D> where D: Device {
if filled { if filled {
self.draw_solid_rects_with_vertex_data(device, self.draw_solid_rects_with_vertex_data(device,
allocator,
&vertex_data, &vertex_data,
&QUAD_INDICES, &QUAD_INDICES,
color, color,
true); true);
} else { } else {
self.draw_solid_rects_with_vertex_data(device, self.draw_solid_rects_with_vertex_data(device,
allocator,
&vertex_data, &vertex_data,
&RECT_LINE_INDICES, &RECT_LINE_INDICES,
color, color,
@ -165,22 +171,33 @@ impl<D> UIPresenter<D> where D: Device {
fn draw_solid_rects_with_vertex_data(&self, fn draw_solid_rects_with_vertex_data(&self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
vertex_data: &[DebugSolidVertex], vertex_data: &[DebugSolidVertex],
index_data: &[u32], index_data: &[u32],
color: ColorU, color: ColorU,
filled: bool) { filled: bool) {
device.allocate_buffer(&self.solid_vertex_array.vertex_buffer, let vertex_buffer_id =
BufferData::Memory(vertex_data), allocator.allocate_buffer::<DebugSolidVertex>(device,
BufferTarget::Vertex); vertex_data.len() as u64,
device.allocate_buffer(&self.solid_vertex_array.index_buffer, BufferTag("SolidVertexDebug"));
BufferData::Memory(index_data), let index_buffer_id = allocator.allocate_buffer::<u32>(device,
BufferTarget::Index); index_data.len() as u64,
BufferTag("SolidIndexDebug"));
{
let vertex_buffer = allocator.get_buffer(vertex_buffer_id);
let index_buffer = allocator.get_buffer(index_buffer_id);
device.upload_to_buffer(&vertex_buffer, 0, vertex_data, BufferTarget::Vertex);
device.upload_to_buffer(&index_buffer, 0, index_data, BufferTarget::Index);
let solid_vertex_array = DebugSolidVertexArray::new(device,
&self.solid_program,
vertex_buffer,
index_buffer);
let primitive = if filled { Primitive::Triangles } else { Primitive::Lines }; let primitive = if filled { Primitive::Triangles } else { Primitive::Lines };
device.draw_elements(index_data.len() as u32, &RenderState { device.draw_elements(index_data.len() as u32, &RenderState {
target: &RenderTarget::Default, target: &RenderTarget::Default,
program: &self.solid_program.program, program: &self.solid_program.program,
vertex_array: &self.solid_vertex_array.vertex_array, vertex_array: &solid_vertex_array.vertex_array,
primitive, primitive,
uniforms: &[ uniforms: &[
(&self.solid_program.framebuffer_size_uniform, (&self.solid_program.framebuffer_size_uniform,
@ -189,6 +206,7 @@ impl<D> UIPresenter<D> where D: Device {
], ],
textures: &[], textures: &[],
images: &[], images: &[],
storage_buffers: &[],
viewport: RectI::new(Vector2I::default(), self.framebuffer_size), viewport: RectI::new(Vector2I::default(), self.framebuffer_size),
options: RenderOptions { options: RenderOptions {
blend: Some(alpha_blend_state()), blend: Some(alpha_blend_state()),
@ -197,7 +215,16 @@ impl<D> UIPresenter<D> where D: Device {
}); });
} }
pub fn draw_text(&self, device: &D, string: &str, origin: Vector2I, invert: bool) { allocator.free_buffer(index_buffer_id);
allocator.free_buffer(vertex_buffer_id);
}
pub fn draw_text(&self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
string: &str,
origin: Vector2I,
invert: bool) {
let mut next = origin; let mut next = origin;
let char_count = string.chars().count(); let char_count = string.chars().count();
let mut vertex_data = Vec::with_capacity(char_count * 4); let mut vertex_data = Vec::with_capacity(char_count * 4);
@ -227,6 +254,7 @@ impl<D> UIPresenter<D> where D: Device {
let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR }; let color = if invert { INVERTED_TEXT_COLOR } else { TEXT_COLOR };
self.draw_texture_with_vertex_data(device, self.draw_texture_with_vertex_data(device,
allocator,
&vertex_data, &vertex_data,
&index_data, &index_data,
&self.font_texture, &self.font_texture,
@ -235,6 +263,7 @@ impl<D> UIPresenter<D> where D: Device {
pub fn draw_texture(&self, pub fn draw_texture(&self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
origin: Vector2I, origin: Vector2I,
texture: &D::Texture, texture: &D::Texture,
color: ColorU) { color: ColorU) {
@ -247,7 +276,12 @@ impl<D> UIPresenter<D> where D: Device {
DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()), DebugTextureVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()),
]; ];
self.draw_texture_with_vertex_data(device, &vertex_data, &QUAD_INDICES, texture, color); self.draw_texture_with_vertex_data(device,
allocator,
&vertex_data,
&QUAD_INDICES,
texture,
color);
} }
pub fn measure_text(&self, string: &str) -> i32 { pub fn measure_text(&self, string: &str) -> i32 {
@ -268,10 +302,14 @@ impl<D> UIPresenter<D> where D: Device {
SEGMENT_SIZE * segment_count as i32 + (segment_count - 1) as i32 SEGMENT_SIZE * segment_count as i32 + (segment_count - 1) as i32
} }
pub fn draw_solid_rounded_rect(&self, device: &D, rect: RectI, color: ColorU) { pub fn draw_solid_rounded_rect(&self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
rect: RectI,
color: ColorU) {
let corner_texture = self.corner_texture(true); let corner_texture = self.corner_texture(true);
let corner_rects = CornerRects::new(device, rect, corner_texture); let corner_rects = CornerRects::new(device, rect, corner_texture);
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects); self.draw_rounded_rect_corners(device, allocator, color, corner_texture, &corner_rects);
let solid_rect_mid = RectI::from_points(corner_rects.upper_left.upper_right(), let solid_rect_mid = RectI::from_points(corner_rects.upper_left.upper_right(),
corner_rects.lower_right.lower_left()); corner_rects.lower_right.lower_left());
@ -302,16 +340,21 @@ impl<D> UIPresenter<D> where D: Device {
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8)); index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
self.draw_solid_rects_with_vertex_data(device, self.draw_solid_rects_with_vertex_data(device,
allocator,
&vertex_data, &vertex_data,
&index_data[0..18], &index_data[0..18],
color, color,
true); true);
} }
pub fn draw_rounded_rect_outline(&self, device: &D, rect: RectI, color: ColorU) { pub fn draw_rounded_rect_outline(&self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
rect: RectI,
color: ColorU) {
let corner_texture = self.corner_texture(false); let corner_texture = self.corner_texture(false);
let corner_rects = CornerRects::new(device, rect, corner_texture); let corner_rects = CornerRects::new(device, rect, corner_texture);
self.draw_rounded_rect_corners(device, color, corner_texture, &corner_rects); self.draw_rounded_rect_corners(device, allocator, color, corner_texture, &corner_rects);
let vertex_data = vec![ let vertex_data = vec![
DebugSolidVertex::new(corner_rects.upper_left.upper_right()), DebugSolidVertex::new(corner_rects.upper_left.upper_right()),
@ -325,18 +368,34 @@ impl<D> UIPresenter<D> where D: Device {
]; ];
let index_data = &OUTLINE_RECT_LINE_INDICES; let index_data = &OUTLINE_RECT_LINE_INDICES;
self.draw_solid_rects_with_vertex_data(device, &vertex_data, index_data, color, false); self.draw_solid_rects_with_vertex_data(device,
allocator,
&vertex_data,
index_data,
color,
false);
} }
// TODO(pcwalton): `LineSegment2I`. // TODO(pcwalton): `LineSegment2I`.
fn draw_line(&self, device: &D, from: Vector2I, to: Vector2I, color: ColorU) { fn draw_line(&self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
from: Vector2I,
to: Vector2I,
color: ColorU) {
let vertex_data = vec![DebugSolidVertex::new(from), DebugSolidVertex::new(to)]; let vertex_data = vec![DebugSolidVertex::new(from), DebugSolidVertex::new(to)];
self.draw_solid_rects_with_vertex_data(device, &vertex_data, &[0, 1], color, false); self.draw_solid_rects_with_vertex_data(device,
allocator,
&vertex_data,
&[0, 1],
color,
false);
} }
fn draw_rounded_rect_corners(&self, fn draw_rounded_rect_corners(&self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
color: ColorU, color: ColorU,
texture: &D::Texture, texture: &D::Texture,
corner_rects: &CornerRects) { corner_rects: &CornerRects) {
@ -387,7 +446,12 @@ impl<D> UIPresenter<D> where D: Device {
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8)); index_data.extend(QUAD_INDICES.iter().map(|&index| index + 8));
index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12)); index_data.extend(QUAD_INDICES.iter().map(|&index| index + 12));
self.draw_texture_with_vertex_data(device, &vertex_data, &index_data, texture, color); self.draw_texture_with_vertex_data(device,
allocator,
&vertex_data,
&index_data,
texture,
color);
} }
fn corner_texture(&self, filled: bool) -> &D::Texture { fn corner_texture(&self, filled: bool) -> &D::Texture {
@ -396,24 +460,37 @@ impl<D> UIPresenter<D> where D: Device {
fn draw_texture_with_vertex_data(&self, fn draw_texture_with_vertex_data(&self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
vertex_data: &[DebugTextureVertex], vertex_data: &[DebugTextureVertex],
index_data: &[u32], index_data: &[u32],
texture: &D::Texture, texture: &D::Texture,
color: ColorU) { color: ColorU) {
device.allocate_buffer(&self.texture_vertex_array.vertex_buffer, let vertex_buffer_id =
BufferData::Memory(vertex_data), allocator.allocate_buffer::<DebugTextureVertex>(device,
BufferTarget::Vertex); vertex_data.len() as u64,
device.allocate_buffer(&self.texture_vertex_array.index_buffer, BufferTag("TextureVertexDebug"));
BufferData::Memory(index_data), let index_buffer_id = allocator.allocate_buffer::<u32>(device,
BufferTarget::Index); index_data.len() as u64,
BufferTag("TextureIndexDebug"));
{
let vertex_buffer = allocator.get_buffer(vertex_buffer_id);
let index_buffer = allocator.get_buffer(index_buffer_id);
device.upload_to_buffer(&vertex_buffer, 0, vertex_data, BufferTarget::Vertex);
device.upload_to_buffer(&index_buffer, 0, index_data, BufferTarget::Index);
let texture_vertex_array = DebugTextureVertexArray::new(device,
&self.texture_program,
vertex_buffer,
index_buffer);
device.draw_elements(index_data.len() as u32, &RenderState { device.draw_elements(index_data.len() as u32, &RenderState {
target: &RenderTarget::Default, target: &RenderTarget::Default,
program: &self.texture_program.program, program: &self.texture_program.program,
vertex_array: &self.texture_vertex_array.vertex_array, vertex_array: &texture_vertex_array.vertex_array,
primitive: Primitive::Triangles, primitive: Primitive::Triangles,
textures: &[(&self.texture_program.texture, &texture)], textures: &[(&self.texture_program.texture, &texture)],
images: &[], images: &[],
storage_buffers: &[],
uniforms: &[ uniforms: &[
(&self.texture_program.framebuffer_size_uniform, (&self.texture_program.framebuffer_size_uniform,
UniformData::Vec2(self.framebuffer_size.0.to_f32x2())), UniformData::Vec2(self.framebuffer_size.0.to_f32x2())),
@ -429,11 +506,20 @@ impl<D> UIPresenter<D> where D: Device {
}); });
} }
pub fn draw_button(&mut self, device: &D, origin: Vector2I, texture: &D::Texture) -> bool { allocator.free_buffer(index_buffer_id);
allocator.free_buffer(vertex_buffer_id);
}
pub fn draw_button(&mut self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
origin: Vector2I,
texture: &D::Texture) -> bool {
let button_rect = RectI::new(origin, vec2i(BUTTON_WIDTH, BUTTON_HEIGHT)); let button_rect = RectI::new(origin, vec2i(BUTTON_WIDTH, BUTTON_HEIGHT));
self.draw_solid_rounded_rect(device, button_rect, WINDOW_COLOR); self.draw_solid_rounded_rect(device, allocator, button_rect, WINDOW_COLOR);
self.draw_rounded_rect_outline(device, button_rect, OUTLINE_COLOR); self.draw_rounded_rect_outline(device, allocator, button_rect, OUTLINE_COLOR);
self.draw_texture(device, self.draw_texture(device,
allocator,
origin + vec2i(PADDING, PADDING), origin + vec2i(PADDING, PADDING),
texture, texture,
BUTTON_ICON_COLOR); BUTTON_ICON_COLOR);
@ -442,11 +528,13 @@ impl<D> UIPresenter<D> where D: Device {
pub fn draw_text_switch(&mut self, pub fn draw_text_switch(&mut self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
mut origin: Vector2I, mut origin: Vector2I,
segment_labels: &[&str], segment_labels: &[&str],
mut value: u8) mut value: u8)
-> u8 { -> u8 {
if let Some(new_value) = self.draw_segmented_control(device, if let Some(new_value) = self.draw_segmented_control(device,
allocator,
origin, origin,
Some(value), Some(value),
segment_labels.len() as u8) { segment_labels.len() as u8) {
@ -458,6 +546,7 @@ impl<D> UIPresenter<D> where D: Device {
let label_width = self.measure_text(segment_label); let label_width = self.measure_text(segment_label);
let offset = SEGMENT_SIZE / 2 - label_width / 2; let offset = SEGMENT_SIZE / 2 - label_width / 2;
self.draw_text(device, self.draw_text(device,
allocator,
segment_label, segment_label,
origin + vec2i(offset, 0), origin + vec2i(offset, 0),
segment_index as u8 == value); segment_index as u8 == value);
@ -469,12 +558,14 @@ impl<D> UIPresenter<D> where D: Device {
pub fn draw_image_segmented_control(&mut self, pub fn draw_image_segmented_control(&mut self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
mut origin: Vector2I, mut origin: Vector2I,
segment_textures: &[&D::Texture], segment_textures: &[&D::Texture],
mut value: Option<u8>) mut value: Option<u8>)
-> Option<u8> { -> Option<u8> {
let mut clicked_segment = None; let mut clicked_segment = None;
if let Some(segment_index) = self.draw_segmented_control(device, if let Some(segment_index) = self.draw_segmented_control(device,
allocator,
origin, origin,
value, value,
segment_textures.len() as u8) { segment_textures.len() as u8) {
@ -493,7 +584,7 @@ impl<D> UIPresenter<D> where D: Device {
TEXT_COLOR TEXT_COLOR
}; };
self.draw_texture(device, origin + offset, segment_texture, color); self.draw_texture(device, allocator, origin + offset, segment_texture, color);
origin += vec2i(SEGMENT_SIZE + 1, 0); origin += vec2i(SEGMENT_SIZE + 1, 0);
} }
@ -502,6 +593,7 @@ impl<D> UIPresenter<D> where D: Device {
fn draw_segmented_control(&mut self, fn draw_segmented_control(&mut self,
device: &D, device: &D,
allocator: &mut GPUMemoryAllocator<D>,
origin: Vector2I, origin: Vector2I,
mut value: Option<u8>, mut value: Option<u8>,
segment_count: u8) segment_count: u8)
@ -518,13 +610,14 @@ impl<D> UIPresenter<D> where D: Device {
clicked_segment = Some(segment); clicked_segment = Some(segment);
} }
self.draw_solid_rounded_rect(device, widget_rect, WINDOW_COLOR); self.draw_solid_rounded_rect(device, allocator, widget_rect, WINDOW_COLOR);
self.draw_rounded_rect_outline(device, widget_rect, OUTLINE_COLOR); self.draw_rounded_rect_outline(device, allocator, widget_rect, OUTLINE_COLOR);
if let Some(value) = value { if let Some(value) = value {
let highlight_size = vec2i(SEGMENT_SIZE, BUTTON_HEIGHT); let highlight_size = vec2i(SEGMENT_SIZE, BUTTON_HEIGHT);
let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1); let x_offset = value as i32 * SEGMENT_SIZE + (value as i32 - 1);
self.draw_solid_rounded_rect(device, self.draw_solid_rounded_rect(device,
allocator,
RectI::new(origin + vec2i(x_offset, 0), highlight_size), RectI::new(origin + vec2i(x_offset, 0), highlight_size),
TEXT_COLOR); TEXT_COLOR);
} }
@ -536,6 +629,7 @@ impl<D> UIPresenter<D> where D: Device {
Some(value) if value == prev_segment_index || value == next_segment_index => {} Some(value) if value == prev_segment_index || value == next_segment_index => {}
_ => { _ => {
self.draw_line(device, self.draw_line(device,
allocator,
segment_origin, segment_origin,
segment_origin + vec2i(0, BUTTON_HEIGHT), segment_origin + vec2i(0, BUTTON_HEIGHT),
TEXT_COLOR); TEXT_COLOR);
@ -547,7 +641,11 @@ impl<D> UIPresenter<D> where D: Device {
clicked_segment clicked_segment
} }
pub fn draw_tooltip(&self, device: &D, string: &str, rect: RectI) { pub fn draw_tooltip(&self,
device: &D,
allocator: &mut GPUMemoryAllocator<D>,
string: &str,
rect: RectI) {
if !rect.to_f32().contains_point(self.mouse_position) { if !rect.to_f32().contains_point(self.mouse_position) {
return; return;
} }
@ -556,8 +654,15 @@ impl<D> UIPresenter<D> where D: Device {
let window_size = vec2i(text_size + PADDING * 2, TOOLTIP_HEIGHT); let window_size = vec2i(text_size + PADDING * 2, TOOLTIP_HEIGHT);
let origin = rect.origin() - vec2i(0, window_size.y() + PADDING); let origin = rect.origin() - vec2i(0, window_size.y() + PADDING);
self.draw_solid_rounded_rect(device, RectI::new(origin, window_size), WINDOW_COLOR); self.draw_solid_rounded_rect(device,
self.draw_text(device, string, origin + vec2i(PADDING, PADDING + FONT_ASCENT), false); allocator,
RectI::new(origin, window_size),
WINDOW_COLOR);
self.draw_text(device,
allocator,
string,
origin + vec2i(PADDING, PADDING + FONT_ASCENT),
false);
} }
} }
@ -571,7 +676,7 @@ struct DebugTextureProgram<D> where D: Device {
impl<D> DebugTextureProgram<D> where D: Device { impl<D> DebugTextureProgram<D> where D: Device {
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugTextureProgram<D> { fn new(device: &D, resources: &dyn ResourceLoader) -> DebugTextureProgram<D> {
let program = device.create_raster_program(resources, "debug_texture"); let program = device.create_raster_program(resources, "debug/texture");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
let texture_size_uniform = device.get_uniform(&program, "TextureSize"); let texture_size_uniform = device.get_uniform(&program, "TextureSize");
let color_uniform = device.get_uniform(&program, "Color"); let color_uniform = device.get_uniform(&program, "Color");
@ -588,15 +693,14 @@ impl<D> DebugTextureProgram<D> where D: Device {
struct DebugTextureVertexArray<D> where D: Device { struct DebugTextureVertexArray<D> where D: Device {
vertex_array: D::VertexArray, vertex_array: D::VertexArray,
vertex_buffer: D::Buffer,
index_buffer: D::Buffer,
} }
impl<D> DebugTextureVertexArray<D> where D: Device { impl<D> DebugTextureVertexArray<D> where D: Device {
fn new(device: &D, debug_texture_program: &DebugTextureProgram<D>) fn new(device: &D,
debug_texture_program: &DebugTextureProgram<D>,
vertex_buffer: &D::Buffer,
index_buffer: &D::Buffer)
-> DebugTextureVertexArray<D> { -> DebugTextureVertexArray<D> {
let vertex_buffer = device.create_buffer(BufferUploadMode::Dynamic);
let index_buffer = device.create_buffer(BufferUploadMode::Dynamic);
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position") let position_attr = device.get_vertex_attr(&debug_texture_program.program, "Position")
@ -604,8 +708,8 @@ impl<D> DebugTextureVertexArray<D> where D: Device {
let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord") let tex_coord_attr = device.get_vertex_attr(&debug_texture_program.program, "TexCoord")
.unwrap(); .unwrap();
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); device.bind_buffer(&vertex_array, vertex_buffer, BufferTarget::Vertex);
device.bind_buffer(&vertex_array, &index_buffer, BufferTarget::Index); device.bind_buffer(&vertex_array, index_buffer, BufferTarget::Index);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor { device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
@ -625,20 +729,20 @@ impl<D> DebugTextureVertexArray<D> where D: Device {
buffer_index: 0, buffer_index: 0,
}); });
DebugTextureVertexArray { vertex_array, vertex_buffer, index_buffer } DebugTextureVertexArray { vertex_array }
} }
} }
struct DebugSolidVertexArray<D> where D: Device { struct DebugSolidVertexArray<D> where D: Device {
vertex_array: D::VertexArray, vertex_array: D::VertexArray,
vertex_buffer: D::Buffer,
index_buffer: D::Buffer,
} }
impl<D> DebugSolidVertexArray<D> where D: Device { impl<D> DebugSolidVertexArray<D> where D: Device {
fn new(device: &D, debug_solid_program: &DebugSolidProgram<D>) -> DebugSolidVertexArray<D> { fn new(device: &D,
let vertex_buffer = device.create_buffer(BufferUploadMode::Dynamic); debug_solid_program: &DebugSolidProgram<D>,
let index_buffer = device.create_buffer(BufferUploadMode::Dynamic); vertex_buffer: &D::Buffer,
index_buffer: &D::Buffer)
-> DebugSolidVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let position_attr = let position_attr =
@ -655,7 +759,7 @@ impl<D> DebugSolidVertexArray<D> where D: Device {
buffer_index: 0, buffer_index: 0,
}); });
DebugSolidVertexArray { vertex_array, vertex_buffer, index_buffer } DebugSolidVertexArray { vertex_array }
} }
} }
@ -667,7 +771,7 @@ struct DebugSolidProgram<D> where D: Device {
impl<D> DebugSolidProgram<D> where D: Device { impl<D> DebugSolidProgram<D> where D: Device {
fn new(device: &D, resources: &dyn ResourceLoader) -> DebugSolidProgram<D> { fn new(device: &D, resources: &dyn ResourceLoader) -> DebugSolidProgram<D> {
let program = device.create_raster_program(resources, "debug_solid"); let program = device.create_raster_program(resources, "debug/solid");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
let color_uniform = device.get_uniform(&program, "Color"); let color_uniform = device.get_uniform(&program, "Color");
DebugSolidProgram { program, framebuffer_size_uniform, color_uniform } DebugSolidProgram { program, framebuffer_size_uniform, color_uniform }