mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
Animating scene
Make the scene dependent on timing. This commit patches the HAL to reuse command buffers; this works well on Vulkan and prevents a leak, but breaks the other back-ends. That will require a solution, possibly including plumbing up the resource lifetime responsibilities to the client. Other things might be hacky as well.
This commit is contained in:
parent
ef5ef2745c
commit
4b2a720289
|
@ -173,7 +173,7 @@ impl Session {
|
||||||
// Reuse of command buffers works on Vulkan, but not at all on
|
// Reuse of command buffers works on Vulkan, but not at all on
|
||||||
// Metal and is problematic on DX12 (the allocator is returned)
|
// Metal and is problematic on DX12 (the allocator is returned)
|
||||||
// to the pool. Punt for now.
|
// to the pool. Punt for now.
|
||||||
/*
|
|
||||||
let mut pool = self.0.cmd_buf_pool.lock().unwrap();
|
let mut pool = self.0.cmd_buf_pool.lock().unwrap();
|
||||||
pool.push((item.cmd_buf, item.fence));
|
pool.push((item.cmd_buf, item.fence));
|
||||||
std::mem::drop(item.resources);
|
std::mem::drop(item.resources);
|
||||||
|
@ -181,7 +181,7 @@ impl Session {
|
||||||
pool.push((staging_cmd_buf.cmd_buf, staging_cmd_buf.fence));
|
pool.push((staging_cmd_buf.cmd_buf, staging_cmd_buf.fence));
|
||||||
std::mem::drop(staging_cmd_buf.resources);
|
std::mem::drop(staging_cmd_buf.resources);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
@ -569,13 +569,11 @@ impl SubmittedCmdBuf {
|
||||||
session.device.wait_and_reset(vec![&mut item.fence])?;
|
session.device.wait_and_reset(vec![&mut item.fence])?;
|
||||||
}
|
}
|
||||||
// See discussion in `poll_cleanup`
|
// See discussion in `poll_cleanup`
|
||||||
/*
|
|
||||||
session
|
session
|
||||||
.cmd_buf_pool
|
.cmd_buf_pool
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push((item.cmd_buf, item.fence));
|
.push((item.cmd_buf, item.fence));
|
||||||
*/
|
|
||||||
std::mem::drop(item.resources);
|
std::mem::drop(item.resources);
|
||||||
}
|
}
|
||||||
// else session dropped error?
|
// else session dropped error?
|
||||||
|
|
|
@ -16,7 +16,7 @@ use piet_gpu_hal::{
|
||||||
Swapchain,
|
Swapchain,
|
||||||
};
|
};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer};
|
use piet_gpu::{test_scenes, PietGpuRenderContext, Renderer};
|
||||||
|
|
||||||
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
|
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -62,7 +62,7 @@ fn my_main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
Event::WindowRedrawNeeded => {
|
Event::WindowRedrawNeeded => {
|
||||||
if let Some(gfx_state) = gfx_state.as_mut() {
|
if let Some(gfx_state) = gfx_state.as_mut() {
|
||||||
for _ in 0..10 {
|
for _ in 0..1000 {
|
||||||
gfx_state.redraw();
|
gfx_state.redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ impl GfxState {
|
||||||
.collect::<Result<Vec<_>, Error>>()?;
|
.collect::<Result<Vec<_>, Error>>()?;
|
||||||
|
|
||||||
let mut ctx = PietGpuRenderContext::new();
|
let mut ctx = PietGpuRenderContext::new();
|
||||||
render_scene(&mut ctx);
|
test_scenes::render_anim_frame(&mut ctx, 0);
|
||||||
|
|
||||||
let mut renderer = Renderer::new(&session, width, height)?;
|
let mut renderer = Renderer::new(&session, width, height)?;
|
||||||
renderer.upload_render_ctx(&mut ctx)?;
|
renderer.upload_render_ctx(&mut ctx)?;
|
||||||
|
@ -138,6 +138,12 @@ impl GfxState {
|
||||||
if let Some(submitted) = self.submitted.take() {
|
if let Some(submitted) = self.submitted.take() {
|
||||||
submitted.wait().unwrap();
|
submitted.wait().unwrap();
|
||||||
|
|
||||||
|
let mut ctx = PietGpuRenderContext::new();
|
||||||
|
test_scenes::render_anim_frame(&mut ctx, self.current_frame);
|
||||||
|
if let Err(e) = self.renderer.upload_render_ctx(&mut ctx) {
|
||||||
|
println!("error in uploading: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
let ts = self
|
let ts = self
|
||||||
.session
|
.session
|
||||||
.fetch_query_pool(&self.query_pools[self.last_frame_idx])
|
.fetch_query_pool(&self.query_pools[self.last_frame_idx])
|
||||||
|
|
|
@ -6,7 +6,7 @@ use clap::{App, Arg};
|
||||||
|
|
||||||
use piet_gpu_hal::{BufferUsage, Error, Instance, Session};
|
use piet_gpu_hal::{BufferUsage, Error, Instance, Session};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer};
|
use piet_gpu::{test_scenes, PietGpuRenderContext, Renderer};
|
||||||
|
|
||||||
const WIDTH: usize = 2048;
|
const WIDTH: usize = 2048;
|
||||||
const HEIGHT: usize = 1536;
|
const HEIGHT: usize = 1536;
|
||||||
|
@ -243,9 +243,9 @@ fn main() -> Result<(), Error> {
|
||||||
if matches.is_present("flip") {
|
if matches.is_present("flip") {
|
||||||
scale = -scale;
|
scale = -scale;
|
||||||
}
|
}
|
||||||
render_svg(&mut ctx, input, scale);
|
test_scenes::render_svg(&mut ctx, input, scale);
|
||||||
} else {
|
} else {
|
||||||
render_scene(&mut ctx);
|
test_scenes::render_scene(&mut ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut renderer = Renderer::new(&session, WIDTH, HEIGHT)?;
|
let mut renderer = Renderer::new(&session, WIDTH, HEIGHT)?;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
use piet::RenderContext;
|
||||||
use piet_gpu_hal::{Error, ImageLayout, Instance, Session, SubmittedCmdBuf};
|
use piet_gpu_hal::{Error, ImageLayout, Instance, Session, SubmittedCmdBuf};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer};
|
use piet_gpu::{test_scenes, PietGpuRenderContext, Renderer};
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
|
@ -60,9 +61,10 @@ fn main() -> Result<(), Error> {
|
||||||
if matches.is_present("flip") {
|
if matches.is_present("flip") {
|
||||||
scale = -scale;
|
scale = -scale;
|
||||||
}
|
}
|
||||||
render_svg(&mut ctx, input, scale);
|
test_scenes::render_svg(&mut ctx, input, scale);
|
||||||
} else {
|
} else {
|
||||||
render_scene(&mut ctx);
|
test_scenes::render_scene(&mut ctx);
|
||||||
|
//test_scenes::render_anim_frame(&mut ctx, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut renderer = Renderer::new(&session, WIDTH, HEIGHT)?;
|
let mut renderer = Renderer::new(&session, WIDTH, HEIGHT)?;
|
||||||
|
@ -96,6 +98,13 @@ fn main() -> Result<(), Error> {
|
||||||
// Getting this right will take some thought.
|
// Getting this right will take some thought.
|
||||||
if let Some(submitted) = submitted.take() {
|
if let Some(submitted) = submitted.take() {
|
||||||
submitted.wait().unwrap();
|
submitted.wait().unwrap();
|
||||||
|
if matches.value_of("INPUT").is_none() {
|
||||||
|
let mut ctx = PietGpuRenderContext::new();
|
||||||
|
test_scenes::render_anim_frame(&mut ctx, current_frame);
|
||||||
|
if let Err(e) = renderer.upload_render_ctx(&mut ctx) {
|
||||||
|
println!("error in uploading: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ts = session.fetch_query_pool(&query_pools[last_frame_idx]).unwrap();
|
let ts = session.fetch_query_pool(&query_pools[last_frame_idx]).unwrap();
|
||||||
window.set_title(&format!(
|
window.set_title(&format!(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod gradient;
|
mod gradient;
|
||||||
mod pico_svg;
|
mod pico_svg;
|
||||||
mod render_ctx;
|
mod render_ctx;
|
||||||
|
pub mod test_scenes;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
@ -31,188 +32,6 @@ const PTCL_INITIAL_ALLOC: usize = 1024;
|
||||||
|
|
||||||
const MAX_BLEND_STACK: usize = 128;
|
const MAX_BLEND_STACK: usize = 128;
|
||||||
|
|
||||||
const N_CIRCLES: usize = 0;
|
|
||||||
|
|
||||||
pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) {
|
|
||||||
let xml_str = std::fs::read_to_string(filename).unwrap();
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
let svg = PicoSvg::load(&xml_str, scale).unwrap();
|
|
||||||
println!("parsing time: {:?}", start.elapsed());
|
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
svg.render(rc);
|
|
||||||
println!("flattening and encoding time: {:?}", start.elapsed());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_scene(rc: &mut impl RenderContext) {
|
|
||||||
const WIDTH: usize = 2048;
|
|
||||||
const HEIGHT: usize = 1536;
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
for _ in 0..N_CIRCLES {
|
|
||||||
let color = Color::from_rgba32_u32(rng.next_u32());
|
|
||||||
let center = Point::new(
|
|
||||||
rng.gen_range(0.0, WIDTH as f64),
|
|
||||||
rng.gen_range(0.0, HEIGHT as f64),
|
|
||||||
);
|
|
||||||
let radius = rng.gen_range(0.0, 50.0);
|
|
||||||
let circle = Circle::new(center, radius);
|
|
||||||
rc.fill(circle, &color);
|
|
||||||
}
|
|
||||||
let _ = rc.save();
|
|
||||||
let mut path = BezPath::new();
|
|
||||||
path.move_to((200.0, 150.0));
|
|
||||||
path.line_to((100.0, 200.0));
|
|
||||||
path.line_to((150.0, 250.0));
|
|
||||||
path.close_path();
|
|
||||||
rc.clip(path);
|
|
||||||
|
|
||||||
let mut path = BezPath::new();
|
|
||||||
path.move_to((100.0, 150.0));
|
|
||||||
path.line_to((200.0, 200.0));
|
|
||||||
path.line_to((150.0, 250.0));
|
|
||||||
path.close_path();
|
|
||||||
rc.fill(path, &Color::rgb8(128, 0, 128));
|
|
||||||
let _ = rc.restore();
|
|
||||||
rc.stroke(
|
|
||||||
piet::kurbo::Line::new((100.0, 100.0), (200.0, 150.0)),
|
|
||||||
&Color::WHITE,
|
|
||||||
5.0,
|
|
||||||
);
|
|
||||||
//render_cardioid(rc);
|
|
||||||
render_clip_test(rc);
|
|
||||||
render_alpha_test(rc);
|
|
||||||
render_gradient_test(rc);
|
|
||||||
render_text_test(rc);
|
|
||||||
//render_tiger(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_cardioid(rc: &mut impl RenderContext) {
|
|
||||||
let n = 601;
|
|
||||||
let dth = std::f64::consts::PI * 2.0 / (n as f64);
|
|
||||||
let center = Point::new(1024.0, 768.0);
|
|
||||||
let r = 750.0;
|
|
||||||
let mut path = BezPath::new();
|
|
||||||
for i in 1..n {
|
|
||||||
let p0 = center + Vec2::from_angle(i as f64 * dth) * r;
|
|
||||||
let p1 = center + Vec2::from_angle(((i * 2) % n) as f64 * dth) * r;
|
|
||||||
//rc.fill(&Circle::new(p0, 8.0), &Color::WHITE);
|
|
||||||
path.move_to(p0);
|
|
||||||
path.line_to(p1);
|
|
||||||
//rc.stroke(Line::new(p0, p1), &Color::BLACK, 2.0);
|
|
||||||
}
|
|
||||||
rc.stroke(&path, &Color::BLACK, 2.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_clip_test(rc: &mut impl RenderContext) {
|
|
||||||
const N: usize = 16;
|
|
||||||
const X0: f64 = 50.0;
|
|
||||||
const Y0: f64 = 450.0;
|
|
||||||
// Note: if it gets much larger, it will exceed the 1MB scratch buffer.
|
|
||||||
// But this is a pretty demanding test.
|
|
||||||
const X1: f64 = 550.0;
|
|
||||||
const Y1: f64 = 950.0;
|
|
||||||
let step = 1.0 / ((N + 1) as f64);
|
|
||||||
for i in 0..N {
|
|
||||||
let t = ((i + 1) as f64) * step;
|
|
||||||
rc.save();
|
|
||||||
let mut path = BezPath::new();
|
|
||||||
path.move_to((X0, Y0));
|
|
||||||
path.line_to((X1, Y0));
|
|
||||||
path.line_to((X1, Y0 + t * (Y1 - Y0)));
|
|
||||||
path.line_to((X1 + t * (X0 - X1), Y1));
|
|
||||||
path.line_to((X0, Y1));
|
|
||||||
path.close_path();
|
|
||||||
rc.clip(path);
|
|
||||||
}
|
|
||||||
let rect = piet::kurbo::Rect::new(X0, Y0, X1, Y1);
|
|
||||||
rc.fill(rect, &Color::BLACK);
|
|
||||||
for _ in 0..N {
|
|
||||||
rc.restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_alpha_test(rc: &mut impl RenderContext) {
|
|
||||||
// Alpha compositing tests.
|
|
||||||
rc.fill(
|
|
||||||
diamond(Point::new(1024.0, 100.0)),
|
|
||||||
&Color::Rgba32(0xff0000ff),
|
|
||||||
);
|
|
||||||
rc.fill(
|
|
||||||
diamond(Point::new(1024.0, 125.0)),
|
|
||||||
&Color::Rgba32(0x00ff0080),
|
|
||||||
);
|
|
||||||
rc.save();
|
|
||||||
rc.clip(diamond(Point::new(1024.0, 150.0)));
|
|
||||||
rc.fill(
|
|
||||||
diamond(Point::new(1024.0, 175.0)),
|
|
||||||
&Color::Rgba32(0x0000ff80),
|
|
||||||
);
|
|
||||||
rc.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_gradient_test(rc: &mut impl RenderContext) {
|
|
||||||
let stops = vec![
|
|
||||||
GradientStop {
|
|
||||||
color: Color::rgb8(0, 255, 0),
|
|
||||||
pos: 0.0,
|
|
||||||
},
|
|
||||||
GradientStop {
|
|
||||||
color: Color::BLACK,
|
|
||||||
pos: 1.0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
let lin = FixedLinearGradient {
|
|
||||||
start: Point::new(0.0, 100.0),
|
|
||||||
end: Point::new(0.0, 300.0),
|
|
||||||
stops,
|
|
||||||
};
|
|
||||||
let brush = FixedGradient::Linear(lin);
|
|
||||||
//let brush = Color::rgb8(0, 128, 0);
|
|
||||||
rc.fill(Rect::new(100.0, 100.0, 300.0, 300.0), &brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn diamond(origin: Point) -> impl Shape {
|
|
||||||
let mut path = BezPath::new();
|
|
||||||
const SIZE: f64 = 50.0;
|
|
||||||
path.move_to((origin.x, origin.y - SIZE));
|
|
||||||
path.line_to((origin.x + SIZE, origin.y));
|
|
||||||
path.line_to((origin.x, origin.y + SIZE));
|
|
||||||
path.line_to((origin.x - SIZE, origin.y));
|
|
||||||
path.close_path();
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_text_test(rc: &mut impl RenderContext) {
|
|
||||||
rc.save();
|
|
||||||
//rc.transform(Affine::new([0.2, 0.0, 0.0, -0.2, 200.0, 800.0]));
|
|
||||||
let layout = rc
|
|
||||||
.text()
|
|
||||||
.new_text_layout("\u{1f600}hello piet-gpu text!")
|
|
||||||
.default_attribute(TextAttribute::FontSize(100.0))
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
rc.draw_text(&layout, Point::new(110.0, 600.0));
|
|
||||||
rc.draw_text(&layout, Point::new(110.0, 700.0));
|
|
||||||
rc.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn render_tiger(rc: &mut impl RenderContext) {
|
|
||||||
let xml_str = std::str::from_utf8(include_bytes!("../Ghostscript_Tiger.svg")).unwrap();
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
let svg = PicoSvg::load(xml_str, 8.0).unwrap();
|
|
||||||
println!("parsing time: {:?}", start.elapsed());
|
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
svg.render(rc);
|
|
||||||
println!("flattening and encoding time: {:?}", start.elapsed());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn dump_scene(buf: &[u8]) {
|
fn dump_scene(buf: &[u8]) {
|
||||||
for i in 0..(buf.len() / 4) {
|
for i in 0..(buf.len() / 4) {
|
||||||
|
@ -478,6 +297,10 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn record(&self, cmd_buf: &mut CmdBuf, query_pool: &QueryPool) {
|
pub unsafe fn record(&self, cmd_buf: &mut CmdBuf, query_pool: &QueryPool) {
|
||||||
|
//cmd_buf.clear_buffer(&self.memory_buf_dev, None);
|
||||||
|
//cmd_buf.memory_barrier();
|
||||||
|
// Only need to copy the first few words; need to upgrade HAL to be able to
|
||||||
|
// express sub-buffer copies.
|
||||||
cmd_buf.copy_buffer(&self.memory_buf_host, &self.memory_buf_dev);
|
cmd_buf.copy_buffer(&self.memory_buf_host, &self.memory_buf_dev);
|
||||||
cmd_buf.clear_buffer(&self.state_buf, None);
|
cmd_buf.clear_buffer(&self.state_buf, None);
|
||||||
cmd_buf.memory_barrier();
|
cmd_buf.memory_barrier();
|
||||||
|
|
|
@ -102,6 +102,9 @@ impl PietGpuRenderContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_scene_buf(&mut self) -> &[u8] {
|
pub fn get_scene_buf(&mut self) -> &[u8] {
|
||||||
|
const ALIGN: usize = 128;
|
||||||
|
let padded_size = (self.elements.len() + (ALIGN - 1)) & ALIGN.wrapping_neg();
|
||||||
|
self.elements.resize(padded_size, Element::Nop());
|
||||||
self.elements.encode(&mut self.encoder);
|
self.elements.encode(&mut self.encoder);
|
||||||
self.encoder.buf()
|
self.encoder.buf()
|
||||||
}
|
}
|
||||||
|
|
211
piet-gpu/src/test_scenes.rs
Normal file
211
piet-gpu/src/test_scenes.rs
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
//! Various synthetic scenes for exercising the renderer.
|
||||||
|
|
||||||
|
use rand::{Rng, RngCore};
|
||||||
|
|
||||||
|
use piet::{Color, FixedGradient, FixedLinearGradient, GradientStop, Text, TextAttribute, TextLayoutBuilder};
|
||||||
|
use piet::kurbo::{BezPath, Circle, Line, Point, Rect, Shape};
|
||||||
|
|
||||||
|
use crate::{RenderContext, PicoSvg, Vec2};
|
||||||
|
|
||||||
|
const N_CIRCLES: usize = 0;
|
||||||
|
|
||||||
|
pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) {
|
||||||
|
let xml_str = std::fs::read_to_string(filename).unwrap();
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
let svg = PicoSvg::load(&xml_str, scale).unwrap();
|
||||||
|
println!("parsing time: {:?}", start.elapsed());
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
svg.render(rc);
|
||||||
|
println!("flattening and encoding time: {:?}", start.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_scene(rc: &mut impl RenderContext) {
|
||||||
|
const WIDTH: usize = 2048;
|
||||||
|
const HEIGHT: usize = 1536;
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
for _ in 0..N_CIRCLES {
|
||||||
|
let color = Color::from_rgba32_u32(rng.next_u32());
|
||||||
|
let center = Point::new(
|
||||||
|
rng.gen_range(0.0, WIDTH as f64),
|
||||||
|
rng.gen_range(0.0, HEIGHT as f64),
|
||||||
|
);
|
||||||
|
let radius = rng.gen_range(0.0, 50.0);
|
||||||
|
let circle = Circle::new(center, radius);
|
||||||
|
rc.fill(circle, &color);
|
||||||
|
}
|
||||||
|
let _ = rc.save();
|
||||||
|
let mut path = BezPath::new();
|
||||||
|
path.move_to((200.0, 150.0));
|
||||||
|
path.line_to((100.0, 200.0));
|
||||||
|
path.line_to((150.0, 250.0));
|
||||||
|
path.close_path();
|
||||||
|
rc.clip(path);
|
||||||
|
|
||||||
|
let mut path = BezPath::new();
|
||||||
|
path.move_to((100.0, 150.0));
|
||||||
|
path.line_to((200.0, 200.0));
|
||||||
|
path.line_to((150.0, 250.0));
|
||||||
|
path.close_path();
|
||||||
|
rc.fill(path, &Color::rgb8(128, 0, 128));
|
||||||
|
let _ = rc.restore();
|
||||||
|
rc.stroke(
|
||||||
|
piet::kurbo::Line::new((100.0, 100.0), (200.0, 150.0)),
|
||||||
|
&Color::WHITE,
|
||||||
|
5.0,
|
||||||
|
);
|
||||||
|
//render_cardioid(rc);
|
||||||
|
render_clip_test(rc);
|
||||||
|
render_alpha_test(rc);
|
||||||
|
render_gradient_test(rc);
|
||||||
|
render_text_test(rc);
|
||||||
|
//render_tiger(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_cardioid(rc: &mut impl RenderContext) {
|
||||||
|
let n = 601;
|
||||||
|
let dth = std::f64::consts::PI * 2.0 / (n as f64);
|
||||||
|
let center = Point::new(1024.0, 768.0);
|
||||||
|
let r = 750.0;
|
||||||
|
let mut path = BezPath::new();
|
||||||
|
for i in 1..n {
|
||||||
|
let p0 = center + Vec2::from_angle(i as f64 * dth) * r;
|
||||||
|
let p1 = center + Vec2::from_angle(((i * 2) % n) as f64 * dth) * r;
|
||||||
|
//rc.fill(&Circle::new(p0, 8.0), &Color::WHITE);
|
||||||
|
path.move_to(p0);
|
||||||
|
path.line_to(p1);
|
||||||
|
//rc.stroke(Line::new(p0, p1), &Color::BLACK, 2.0);
|
||||||
|
}
|
||||||
|
rc.stroke(&path, &Color::BLACK, 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_clip_test(rc: &mut impl RenderContext) {
|
||||||
|
const N: usize = 16;
|
||||||
|
const X0: f64 = 50.0;
|
||||||
|
const Y0: f64 = 450.0;
|
||||||
|
// Note: if it gets much larger, it will exceed the 1MB scratch buffer.
|
||||||
|
// But this is a pretty demanding test.
|
||||||
|
const X1: f64 = 550.0;
|
||||||
|
const Y1: f64 = 950.0;
|
||||||
|
let step = 1.0 / ((N + 1) as f64);
|
||||||
|
for i in 0..N {
|
||||||
|
let t = ((i + 1) as f64) * step;
|
||||||
|
rc.save();
|
||||||
|
let mut path = BezPath::new();
|
||||||
|
path.move_to((X0, Y0));
|
||||||
|
path.line_to((X1, Y0));
|
||||||
|
path.line_to((X1, Y0 + t * (Y1 - Y0)));
|
||||||
|
path.line_to((X1 + t * (X0 - X1), Y1));
|
||||||
|
path.line_to((X0, Y1));
|
||||||
|
path.close_path();
|
||||||
|
rc.clip(path);
|
||||||
|
}
|
||||||
|
let rect = piet::kurbo::Rect::new(X0, Y0, X1, Y1);
|
||||||
|
rc.fill(rect, &Color::BLACK);
|
||||||
|
for _ in 0..N {
|
||||||
|
rc.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_alpha_test(rc: &mut impl RenderContext) {
|
||||||
|
// Alpha compositing tests.
|
||||||
|
rc.fill(
|
||||||
|
diamond(Point::new(1024.0, 100.0)),
|
||||||
|
&Color::Rgba32(0xff0000ff),
|
||||||
|
);
|
||||||
|
rc.fill(
|
||||||
|
diamond(Point::new(1024.0, 125.0)),
|
||||||
|
&Color::Rgba32(0x00ff0080),
|
||||||
|
);
|
||||||
|
rc.save();
|
||||||
|
rc.clip(diamond(Point::new(1024.0, 150.0)));
|
||||||
|
rc.fill(
|
||||||
|
diamond(Point::new(1024.0, 175.0)),
|
||||||
|
&Color::Rgba32(0x0000ff80),
|
||||||
|
);
|
||||||
|
rc.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_gradient_test(rc: &mut impl RenderContext) {
|
||||||
|
let stops = vec![
|
||||||
|
GradientStop {
|
||||||
|
color: Color::rgb8(0, 255, 0),
|
||||||
|
pos: 0.0,
|
||||||
|
},
|
||||||
|
GradientStop {
|
||||||
|
color: Color::BLACK,
|
||||||
|
pos: 1.0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let lin = FixedLinearGradient {
|
||||||
|
start: Point::new(0.0, 100.0),
|
||||||
|
end: Point::new(0.0, 300.0),
|
||||||
|
stops,
|
||||||
|
};
|
||||||
|
let brush = FixedGradient::Linear(lin);
|
||||||
|
//let brush = Color::rgb8(0, 128, 0);
|
||||||
|
rc.fill(Rect::new(100.0, 100.0, 300.0, 300.0), &brush);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diamond(origin: Point) -> impl Shape {
|
||||||
|
let mut path = BezPath::new();
|
||||||
|
const SIZE: f64 = 50.0;
|
||||||
|
path.move_to((origin.x, origin.y - SIZE));
|
||||||
|
path.line_to((origin.x + SIZE, origin.y));
|
||||||
|
path.line_to((origin.x, origin.y + SIZE));
|
||||||
|
path.line_to((origin.x - SIZE, origin.y));
|
||||||
|
path.close_path();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_text_test(rc: &mut impl RenderContext) {
|
||||||
|
rc.save();
|
||||||
|
//rc.transform(Affine::new([0.2, 0.0, 0.0, -0.2, 200.0, 800.0]));
|
||||||
|
let layout = rc
|
||||||
|
.text()
|
||||||
|
.new_text_layout("\u{1f600}hello piet-gpu text!")
|
||||||
|
.default_attribute(TextAttribute::FontSize(100.0))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
rc.draw_text(&layout, Point::new(110.0, 600.0));
|
||||||
|
rc.draw_text(&layout, Point::new(110.0, 700.0));
|
||||||
|
rc.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render_tiger(rc: &mut impl RenderContext) {
|
||||||
|
let xml_str = std::str::from_utf8(include_bytes!("../Ghostscript_Tiger.svg")).unwrap();
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
let svg = PicoSvg::load(xml_str, 8.0).unwrap();
|
||||||
|
println!("parsing time: {:?}", start.elapsed());
|
||||||
|
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
svg.render(rc);
|
||||||
|
println!("flattening and encoding time: {:?}", start.elapsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_anim_frame(rc: &mut impl RenderContext, i: usize) {
|
||||||
|
rc.fill(Rect::new(0.0, 0.0, 1000.0, 1000.0), &Color::rgb8(128, 128, 128));
|
||||||
|
let text_size = 60.0 + 40.0 * (0.01 * i as f64).sin();
|
||||||
|
rc.save().unwrap();
|
||||||
|
//rc.transform(Affine::new([0.2, 0.0, 0.0, -0.2, 200.0, 800.0]));
|
||||||
|
let layout = rc
|
||||||
|
.text()
|
||||||
|
.new_text_layout("\u{1f600}hello piet-gpu text!")
|
||||||
|
.default_attribute(TextAttribute::FontSize(text_size))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
rc.draw_text(&layout, Point::new(110.0, 600.0));
|
||||||
|
rc.draw_text(&layout, Point::new(110.0, 700.0));
|
||||||
|
rc.restore().unwrap();
|
||||||
|
let th = (std::f64::consts::PI / 180.0) * (i as f64);
|
||||||
|
let center = Point::new(500.0, 500.0);
|
||||||
|
let p1 = center + 400.0 * Vec2::from_angle(th);
|
||||||
|
let line = Line::new(center, p1);
|
||||||
|
rc.stroke(line, &Color::rgb8(128, 0, 0), 5.0);
|
||||||
|
}
|
|
@ -119,12 +119,6 @@ impl TextLayout for PietGpuTextLayout {
|
||||||
impl Font {
|
impl Font {
|
||||||
pub fn new() -> Font {
|
pub fn new() -> Font {
|
||||||
let font_ref = FontRef::from_index(FONT_DATA, 0).expect("error parsing font");
|
let font_ref = FontRef::from_index(FONT_DATA, 0).expect("error parsing font");
|
||||||
for palette in font_ref.color_palettes() {
|
|
||||||
println!("palette, len={}", palette.len());
|
|
||||||
for i in 0..palette.len() {
|
|
||||||
println!("{}: {:?}", i, palette.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Font { font_ref }
|
Font { font_ref }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,14 +136,12 @@ impl Font {
|
||||||
if let Some(outline) = scaler.scale_color_outline(glyph_id) {
|
if let Some(outline) = scaler.scale_color_outline(glyph_id) {
|
||||||
// TODO: be more sophisticated choosing a palette
|
// TODO: be more sophisticated choosing a palette
|
||||||
let palette = self.font_ref.color_palettes().next().unwrap();
|
let palette = self.font_ref.color_palettes().next().unwrap();
|
||||||
println!("is_color {}", outline.is_color());
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while let Some(layer) = outline.get(i) {
|
while let Some(layer) = outline.get(i) {
|
||||||
if let Some(color_ix) = layer.color_index() {
|
if let Some(color_ix) = layer.color_index() {
|
||||||
let color = palette.get(color_ix);
|
let color = palette.get(color_ix);
|
||||||
encoder.append_outline(layer.verbs(), layer.points());
|
encoder.append_outline(layer.verbs(), layer.points());
|
||||||
encoder.append_solid_fill(color);
|
encoder.append_solid_fill(color);
|
||||||
println!("layer {} color {:?}", i, color);
|
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue