mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
make gradient ramps late bound
Removes ResourceContext type. This makes scenes and fragments nearly identical. Should they be merged?
This commit is contained in:
parent
2e8781fbb6
commit
cd25528abd
|
@ -18,7 +18,7 @@ use piet_gpu::{PixelFormat, RenderConfig};
|
||||||
use piet_gpu_hal::{QueryPool, Session};
|
use piet_gpu_hal::{QueryPool, Session};
|
||||||
use piet_scene::glyph::pinot::{types::Tag, FontDataRef};
|
use piet_scene::glyph::pinot::{types::Tag, FontDataRef};
|
||||||
use piet_scene::glyph::{GlyphContext, GlyphProvider};
|
use piet_scene::glyph::{GlyphContext, GlyphProvider};
|
||||||
use piet_scene::{Affine, Rect, ResourceContext, Scene, SceneFragment};
|
use piet_scene::{Affine, Rect, Scene, SceneFragment};
|
||||||
|
|
||||||
/// State and resources for rendering a scene.
|
/// State and resources for rendering a scene.
|
||||||
pub struct PgpuRenderer {
|
pub struct PgpuRenderer {
|
||||||
|
@ -105,23 +105,17 @@ impl PgpuRenderer {
|
||||||
/// Encoded streams and resources describing a vector graphics scene.
|
/// Encoded streams and resources describing a vector graphics scene.
|
||||||
pub struct PgpuScene {
|
pub struct PgpuScene {
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
rcx: ResourceContext,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PgpuScene {
|
impl PgpuScene {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
scene: Scene::default(),
|
scene: Scene::default(),
|
||||||
rcx: ResourceContext::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builder(&mut self) -> PgpuSceneBuilder {
|
pub fn builder(&mut self) -> PgpuSceneBuilder {
|
||||||
self.rcx.advance();
|
PgpuSceneBuilder(piet_scene::SceneBuilder::for_scene(&mut self.scene))
|
||||||
PgpuSceneBuilder(piet_scene::SceneBuilder::for_scene(
|
|
||||||
&mut self.scene,
|
|
||||||
&mut self.rcx,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use piet_gpu_hal::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use piet_gpu::{samples, RenderDriver, Renderer, SimpleText};
|
use piet_gpu::{samples, RenderDriver, Renderer, SimpleText};
|
||||||
use piet_scene::{ResourceContext, Scene, SceneBuilder};
|
use piet_scene::{Scene, SceneBuilder};
|
||||||
|
|
||||||
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
|
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -134,13 +134,12 @@ impl GfxState {
|
||||||
}
|
}
|
||||||
let mut text = SimpleText::new();
|
let mut text = SimpleText::new();
|
||||||
let mut scene = Scene::default();
|
let mut scene = Scene::default();
|
||||||
let mut rcx = ResourceContext::default();
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||||
let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx);
|
|
||||||
samples::render_anim_frame(&mut builder, self.current_frame);
|
samples::render_anim_frame(&mut builder, self.current_frame);
|
||||||
//samples::render_tiger(&mut builder, false);
|
//samples::render_tiger(&mut builder, false);
|
||||||
render_info(&mut text, &mut builder, &info_string);
|
render_info(&mut text, &mut builder, &info_string);
|
||||||
builder.finish();
|
builder.finish();
|
||||||
if let Err(e) = self.render_driver.upload_scene(&self.session, &scene, &rcx) {
|
if let Err(e) = self.render_driver.upload_scene(&self.session, &scene) {
|
||||||
println!("error in uploading: {}", e);
|
println!("error in uploading: {}", e);
|
||||||
}
|
}
|
||||||
let (image_idx, acquisition_semaphore) = self.swapchain.next().unwrap();
|
let (image_idx, acquisition_semaphore) = self.swapchain.next().unwrap();
|
||||||
|
|
|
@ -7,7 +7,7 @@ use clap::{App, Arg};
|
||||||
use piet_gpu_hal::{BufferUsage, Error, Instance, InstanceFlags, Session};
|
use piet_gpu_hal::{BufferUsage, Error, Instance, InstanceFlags, Session};
|
||||||
|
|
||||||
use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer};
|
use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer};
|
||||||
use piet_scene::{ResourceContext, Scene, SceneBuilder};
|
use piet_scene::{Scene, SceneBuilder};
|
||||||
|
|
||||||
const WIDTH: usize = 2048;
|
const WIDTH: usize = 2048;
|
||||||
const HEIGHT: usize = 1536;
|
const HEIGHT: usize = 1536;
|
||||||
|
@ -229,12 +229,10 @@ fn main() -> Result<(), Error> {
|
||||||
.get_matches();
|
.get_matches();
|
||||||
let instance = Instance::new(InstanceFlags::default())?;
|
let instance = Instance::new(InstanceFlags::default())?;
|
||||||
let mut scene = Scene::default();
|
let mut scene = Scene::default();
|
||||||
let mut rcx = ResourceContext::default();
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = instance.device()?;
|
let device = instance.device()?;
|
||||||
let session = Session::new(device);
|
let session = Session::new(device);
|
||||||
rcx.advance();
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||||
let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx);
|
|
||||||
if let Some(input) = matches.value_of("INPUT") {
|
if let Some(input) = matches.value_of("INPUT") {
|
||||||
let mut scale = matches
|
let mut scale = matches
|
||||||
.value_of("scale")
|
.value_of("scale")
|
||||||
|
@ -257,7 +255,7 @@ fn main() -> Result<(), Error> {
|
||||||
let renderer = Renderer::new(&session, WIDTH, HEIGHT, 1)?;
|
let renderer = Renderer::new(&session, WIDTH, HEIGHT, 1)?;
|
||||||
let mut render_driver = RenderDriver::new(&session, 1, renderer);
|
let mut render_driver = RenderDriver::new(&session, 1, renderer);
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
render_driver.upload_scene(&session, &scene, &rcx)?;
|
render_driver.upload_scene(&session, &scene)?;
|
||||||
let image_usage = BufferUsage::MAP_READ | BufferUsage::COPY_DST;
|
let image_usage = BufferUsage::MAP_READ | BufferUsage::COPY_DST;
|
||||||
let image_buf = session.create_buffer((WIDTH * HEIGHT * 4) as u64, image_usage)?;
|
let image_buf = session.create_buffer((WIDTH * HEIGHT * 4) as u64, image_usage)?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer, SimpleText};
|
use piet_gpu::{samples, PicoSvg, RenderDriver, Renderer, SimpleText};
|
||||||
use piet_gpu_hal::{Error, ImageLayout, Instance, InstanceFlags, Session};
|
use piet_gpu_hal::{Error, ImageLayout, Instance, InstanceFlags, Session};
|
||||||
use piet_scene::{ResourceContext, Scene, SceneBuilder};
|
use piet_scene::{Scene, SceneBuilder};
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ fn main() -> Result<(), Error> {
|
||||||
let instance = Instance::new(InstanceFlags::default())?;
|
let instance = Instance::new(InstanceFlags::default())?;
|
||||||
let mut info_string = "info".to_string();
|
let mut info_string = "info".to_string();
|
||||||
let mut scene = Scene::default();
|
let mut scene = Scene::default();
|
||||||
let mut rcx = ResourceContext::default();
|
|
||||||
let mut simple_text = piet_gpu::SimpleText::new();
|
let mut simple_text = piet_gpu::SimpleText::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
let surface = instance.surface(&window)?;
|
let surface = instance.surface(&window)?;
|
||||||
|
@ -113,17 +112,15 @@ fn main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(svg) = &svg {
|
if let Some(svg) = &svg {
|
||||||
rcx.advance();
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||||
let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx);
|
|
||||||
samples::render_svg(&mut builder, svg, false);
|
samples::render_svg(&mut builder, svg, false);
|
||||||
render_info(&mut simple_text, &mut builder, &info_string);
|
render_info(&mut simple_text, &mut builder, &info_string);
|
||||||
builder.finish();
|
builder.finish();
|
||||||
if let Err(e) = render_driver.upload_scene(&session, &scene, &rcx) {
|
if let Err(e) = render_driver.upload_scene(&session, &scene) {
|
||||||
println!("error in uploading: {}", e);
|
println!("error in uploading: {}", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rcx.advance();
|
let mut builder = SceneBuilder::for_scene(&mut scene);
|
||||||
let mut builder = SceneBuilder::for_scene(&mut scene, &mut rcx);
|
|
||||||
|
|
||||||
const N_SAMPLES: usize = 4;
|
const N_SAMPLES: usize = 4;
|
||||||
match sample_index % N_SAMPLES {
|
match sample_index % N_SAMPLES {
|
||||||
|
@ -138,7 +135,7 @@ fn main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
render_info(&mut simple_text, &mut builder, &info_string);
|
render_info(&mut simple_text, &mut builder, &info_string);
|
||||||
builder.finish();
|
builder.finish();
|
||||||
if let Err(e) = render_driver.upload_scene(&session, &scene, &rcx) {
|
if let Err(e) = render_driver.upload_scene(&session, &scene) {
|
||||||
println!("error in uploading: {}", e);
|
println!("error in uploading: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
mod pico_svg;
|
mod pico_svg;
|
||||||
|
mod ramp;
|
||||||
mod render_driver;
|
mod render_driver;
|
||||||
pub mod samples;
|
pub mod samples;
|
||||||
mod simple_text;
|
mod simple_text;
|
||||||
|
@ -7,6 +8,7 @@ pub mod stages;
|
||||||
pub use piet_scene as scene;
|
pub use piet_scene as scene;
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use scene::ResourcePatch;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
pub use render_driver::RenderDriver;
|
pub use render_driver::RenderDriver;
|
||||||
|
@ -17,7 +19,7 @@ use piet_gpu_hal::{
|
||||||
DescriptorSet, Error, Image, ImageLayout, Pipeline, QueryPool, Session,
|
DescriptorSet, Error, Image, ImageLayout, Pipeline, QueryPool, Session,
|
||||||
};
|
};
|
||||||
|
|
||||||
use piet_scene::{ResourceContext, Scene};
|
use piet_scene::Scene;
|
||||||
|
|
||||||
pub use pico_svg::PicoSvg;
|
pub use pico_svg::PicoSvg;
|
||||||
use stages::{ClipBinding, ElementBinding, ElementCode, DRAW_PART_SIZE, PATHSEG_PART_SIZE};
|
use stages::{ClipBinding, ElementBinding, ElementCode, DRAW_PART_SIZE, PATHSEG_PART_SIZE};
|
||||||
|
@ -154,6 +156,9 @@ pub struct Renderer {
|
||||||
|
|
||||||
gradient_bufs: Vec<Buffer>,
|
gradient_bufs: Vec<Buffer>,
|
||||||
gradients: Image,
|
gradients: Image,
|
||||||
|
|
||||||
|
ramps: ramp::RampCache,
|
||||||
|
drawdata_patches: Vec<(usize, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderConfig {
|
impl RenderConfig {
|
||||||
|
@ -364,6 +369,9 @@ impl Renderer {
|
||||||
.build(&session, &k4_pipeline)?;
|
.build(&session, &k4_pipeline)?;
|
||||||
|
|
||||||
let scene_stats = Default::default();
|
let scene_stats = Default::default();
|
||||||
|
let ramps = ramp::RampCache::default();
|
||||||
|
let drawdata_patches = vec![];
|
||||||
|
|
||||||
Ok(Renderer {
|
Ok(Renderer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
@ -403,26 +411,34 @@ impl Renderer {
|
||||||
_bg_image: bg_image,
|
_bg_image: bg_image,
|
||||||
gradient_bufs,
|
gradient_bufs,
|
||||||
gradients,
|
gradients,
|
||||||
|
ramps,
|
||||||
|
drawdata_patches,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_scene(
|
pub fn upload_scene(&mut self, scene: &Scene, buf_ix: usize) -> Result<(), Error> {
|
||||||
&mut self,
|
self.drawdata_patches.clear();
|
||||||
scene: &Scene,
|
|
||||||
rcx: &ResourceContext,
|
|
||||||
buf_ix: usize,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.scene_stats = SceneStats::from_scene(scene);
|
self.scene_stats = SceneStats::from_scene(scene);
|
||||||
|
self.ramps.advance();
|
||||||
|
let data = scene.data();
|
||||||
|
let stop_data = &data.resources.stops;
|
||||||
|
for patch in &data.resources.patches {
|
||||||
|
match patch {
|
||||||
|
ResourcePatch::Ramp { offset, stops } => {
|
||||||
|
let ramp_id = self.ramps.add(&stop_data[stops.clone()]);
|
||||||
|
self.drawdata_patches.push((*offset, ramp_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
self.upload_config(buf_ix)?;
|
self.upload_config(buf_ix)?;
|
||||||
{
|
{
|
||||||
let mut mapped_scene = self.scene_bufs[buf_ix].map_write(..)?;
|
let mut mapped_scene = self.scene_bufs[buf_ix].map_write(..)?;
|
||||||
write_scene(scene, &mut mapped_scene);
|
write_scene(scene, &self.drawdata_patches, &mut mapped_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload gradient data.
|
// Upload gradient data.
|
||||||
let ramp_data = rcx.ramp_data();
|
let ramp_data = self.ramps.data();
|
||||||
if !ramp_data.is_empty() {
|
if !ramp_data.is_empty() {
|
||||||
assert!(
|
assert!(
|
||||||
self.gradient_bufs[buf_ix].size() as usize
|
self.gradient_bufs[buf_ix].size() as usize
|
||||||
|
@ -870,12 +886,28 @@ impl SceneStats {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_scene(scene: &Scene, buf: &mut BufWrite) {
|
fn write_scene(scene: &Scene, drawdata_patches: &[(usize, u32)], buf: &mut BufWrite) {
|
||||||
let data = scene.data();
|
let data = scene.data();
|
||||||
buf.extend_slice(&data.drawtag_stream);
|
buf.extend_slice(&data.drawtag_stream);
|
||||||
let n_drawobj = data.drawtag_stream.len();
|
let n_drawobj = data.drawtag_stream.len();
|
||||||
buf.fill_zero(padding(n_drawobj, DRAW_PART_SIZE as usize) * DRAWTAG_SIZE);
|
buf.fill_zero(padding(n_drawobj, DRAW_PART_SIZE as usize) * DRAWTAG_SIZE);
|
||||||
|
if !drawdata_patches.is_empty() {
|
||||||
|
let mut pos = 0;
|
||||||
|
for patch in drawdata_patches {
|
||||||
|
let offset = patch.0;
|
||||||
|
let value = patch.1;
|
||||||
|
if pos < offset {
|
||||||
|
buf.extend_slice(&data.drawdata_stream[pos..offset]);
|
||||||
|
}
|
||||||
|
buf.push(value);
|
||||||
|
pos = offset + 4;
|
||||||
|
}
|
||||||
|
if pos < data.drawdata_stream.len() {
|
||||||
|
buf.extend_slice(&data.drawdata_stream[pos..])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
buf.extend_slice(&data.drawdata_stream);
|
buf.extend_slice(&data.drawdata_stream);
|
||||||
|
}
|
||||||
buf.extend_slice(&data.transform_stream);
|
buf.extend_slice(&data.transform_stream);
|
||||||
buf.extend_slice(&data.linewidth_stream);
|
buf.extend_slice(&data.linewidth_stream);
|
||||||
buf.extend_slice(&data.tag_stream);
|
buf.extend_slice(&data.tag_stream);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::brush::{Color, GradientStop, GradientStops};
|
use piet_scene::{Color, GradientStop, GradientStops};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
const N_SAMPLES: usize = 512;
|
const N_SAMPLES: usize = 512;
|
||||||
|
@ -21,12 +22,6 @@ impl RampCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.epoch = 0;
|
|
||||||
self.map.clear();
|
|
||||||
self.data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, stops: &[GradientStop]) -> u32 {
|
pub fn add(&mut self, stops: &[GradientStop]) -> u32 {
|
||||||
if let Some(entry) = self.map.get_mut(stops) {
|
if let Some(entry) = self.map.get_mut(stops) {
|
||||||
entry.1 = self.epoch;
|
entry.1 = self.epoch;
|
|
@ -15,7 +15,7 @@
|
||||||
// Also licensed under MIT license, at your choice.
|
// Also licensed under MIT license, at your choice.
|
||||||
|
|
||||||
use piet_gpu_hal::{CmdBuf, Error, Image, QueryPool, Semaphore, Session, SubmittedCmdBuf};
|
use piet_gpu_hal::{CmdBuf, Error, Image, QueryPool, Semaphore, Session, SubmittedCmdBuf};
|
||||||
use piet_scene::{ResourceContext, Scene};
|
use piet_scene::Scene;
|
||||||
|
|
||||||
use crate::{MemoryHeader, Renderer, SceneStats};
|
use crate::{MemoryHeader, Renderer, SceneStats};
|
||||||
|
|
||||||
|
@ -86,15 +86,10 @@ impl RenderDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_scene(
|
pub fn upload_scene(&mut self, session: &Session, scene: &Scene) -> Result<(), Error> {
|
||||||
&mut self,
|
|
||||||
session: &Session,
|
|
||||||
scene: &Scene,
|
|
||||||
rcx: &ResourceContext,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let stats = SceneStats::from_scene(scene);
|
let stats = SceneStats::from_scene(scene);
|
||||||
self.ensure_scene_buffers(session, &stats)?;
|
self.ensure_scene_buffers(session, &stats)?;
|
||||||
self.renderer.upload_scene(scene, rcx, self.buf_ix)
|
self.renderer.upload_scene(scene, self.buf_ix)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_scene_buffers(&mut self, session: &Session, stats: &SceneStats) -> Result<(), Error> {
|
fn ensure_scene_buffers(&mut self, session: &Session, stats: &SceneStats) -> Result<(), Error> {
|
||||||
|
|
|
@ -168,7 +168,10 @@ pub fn render_blend_grid(sb: &mut SceneBuilder) {
|
||||||
let i = ix % 4;
|
let i = ix % 4;
|
||||||
let j = ix / 4;
|
let j = ix / 4;
|
||||||
let transform = Affine::translate(i as f32 * 225., j as f32 * 225.);
|
let transform = Affine::translate(i as f32 * 225., j as f32 * 225.);
|
||||||
render_blend_square(sb, blend.into(), transform);
|
let square = blend_square(blend.into());
|
||||||
|
sb.append(&square, Some(transform));
|
||||||
|
// sb.append(&square, Some(transform));
|
||||||
|
// render_blend_square(sb, blend.into(), transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,6 +268,101 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin
|
||||||
sb.pop_layer();
|
sb.pop_layer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn blend_square(blend: BlendMode) -> SceneFragment {
|
||||||
|
let mut fragment = SceneFragment::default();
|
||||||
|
let mut sb = SceneBuilder::for_fragment(&mut fragment);
|
||||||
|
// Inspired by https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
|
||||||
|
let rect = Rect::from_origin_size(Point::new(0., 0.), 200., 200.);
|
||||||
|
let stops = &[
|
||||||
|
GradientStop {
|
||||||
|
color: Color::rgb8(0, 0, 0),
|
||||||
|
offset: 0.0,
|
||||||
|
},
|
||||||
|
GradientStop {
|
||||||
|
color: Color::rgb8(255, 255, 255),
|
||||||
|
offset: 1.0,
|
||||||
|
},
|
||||||
|
][..];
|
||||||
|
let linear = Brush::LinearGradient(LinearGradient {
|
||||||
|
start: Point::new(0.0, 0.0),
|
||||||
|
end: Point::new(200.0, 0.0),
|
||||||
|
stops: stops.into(),
|
||||||
|
extend: ExtendMode::Pad,
|
||||||
|
});
|
||||||
|
sb.fill(Fill::NonZero, &linear, None, rect.elements());
|
||||||
|
const GRADIENTS: &[(f32, f32, Color)] = &[
|
||||||
|
(150., 0., Color::rgb8(64, 240, 255)),
|
||||||
|
(175., 100., Color::rgb8(240, 96, 255)),
|
||||||
|
(125., 200., Color::rgb8(255, 192, 64)),
|
||||||
|
];
|
||||||
|
for (x, y, c) in GRADIENTS {
|
||||||
|
let mut color2 = c.clone();
|
||||||
|
color2.a = 0;
|
||||||
|
let stops = &[
|
||||||
|
GradientStop {
|
||||||
|
color: c.clone(),
|
||||||
|
offset: 0.0,
|
||||||
|
},
|
||||||
|
GradientStop {
|
||||||
|
color: color2,
|
||||||
|
offset: 1.0,
|
||||||
|
},
|
||||||
|
][..];
|
||||||
|
let rad = Brush::RadialGradient(RadialGradient {
|
||||||
|
center0: Point::new(*x, *y),
|
||||||
|
center1: Point::new(*x, *y),
|
||||||
|
radius0: 0.0,
|
||||||
|
radius1: 100.0,
|
||||||
|
stops: stops.into(),
|
||||||
|
extend: ExtendMode::Pad,
|
||||||
|
});
|
||||||
|
sb.fill(Fill::NonZero, &rad, None, rect.elements());
|
||||||
|
}
|
||||||
|
const COLORS: &[Color] = &[
|
||||||
|
Color::rgb8(0, 0, 255),
|
||||||
|
Color::rgb8(0, 255, 0),
|
||||||
|
Color::rgb8(255, 0, 0),
|
||||||
|
];
|
||||||
|
sb.push_layer(Mix::Normal.into(), rect.elements());
|
||||||
|
for (i, c) in COLORS.iter().enumerate() {
|
||||||
|
let stops = &[
|
||||||
|
GradientStop {
|
||||||
|
color: Color::rgb8(255, 255, 255),
|
||||||
|
offset: 0.0,
|
||||||
|
},
|
||||||
|
GradientStop {
|
||||||
|
color: c.clone(),
|
||||||
|
offset: 1.0,
|
||||||
|
},
|
||||||
|
][..];
|
||||||
|
let linear = Brush::LinearGradient(LinearGradient {
|
||||||
|
start: Point::new(0.0, 0.0),
|
||||||
|
end: Point::new(0.0, 200.0),
|
||||||
|
stops: stops.into(),
|
||||||
|
extend: ExtendMode::Pad,
|
||||||
|
});
|
||||||
|
sb.transform(Affine::IDENTITY);
|
||||||
|
sb.push_layer(blend, rect.elements());
|
||||||
|
// squash the ellipse
|
||||||
|
let a = Affine::translate(100., 100.)
|
||||||
|
* Affine::rotate(std::f32::consts::FRAC_PI_3 * (i * 2 + 1) as f32)
|
||||||
|
* Affine::scale(1.0, 0.357)
|
||||||
|
* Affine::translate(-100., -100.);
|
||||||
|
sb.transform(a);
|
||||||
|
sb.fill(
|
||||||
|
Fill::NonZero,
|
||||||
|
&linear,
|
||||||
|
None,
|
||||||
|
make_ellipse(100., 100., 90., 90.),
|
||||||
|
);
|
||||||
|
sb.pop_layer();
|
||||||
|
}
|
||||||
|
sb.pop_layer();
|
||||||
|
sb.finish();
|
||||||
|
fragment
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
pub fn render_anim_frame(sb: &mut SceneBuilder, text: &mut SimpleText, i: usize) {
|
||||||
sb.fill(
|
sb.fill(
|
||||||
|
|
31
piet-scene/src/resource.rs
Normal file
31
piet-scene/src/resource.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use crate::brush::GradientStop;
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
/// Collection of late bound resources for a scene or scene fragment.
|
||||||
|
pub struct ResourceBundle {
|
||||||
|
/// Sequence of resource patches.
|
||||||
|
pub patches: Vec<ResourcePatch>,
|
||||||
|
/// Cache of gradient stops, referenced by range from the patches.
|
||||||
|
pub stops: Vec<GradientStop>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceBundle {
|
||||||
|
/// Clears the resource set.
|
||||||
|
pub(crate) fn clear(&mut self) {
|
||||||
|
self.patches.clear();
|
||||||
|
self.stops.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
/// Description of a late bound resource.
|
||||||
|
pub enum ResourcePatch {
|
||||||
|
/// Gradient ramp resource.
|
||||||
|
Ramp {
|
||||||
|
/// Byte offset to the ramp id in the draw data stream.
|
||||||
|
offset: usize,
|
||||||
|
/// Range of the gradient stops in the resource set.
|
||||||
|
stops: Range<usize>,
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
mod gradient;
|
|
||||||
|
|
||||||
use crate::brush::GradientStop;
|
|
||||||
use gradient::RampCache;
|
|
||||||
|
|
||||||
/// Context for caching resources across rendering operations.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ResourceContext {
|
|
||||||
ramps: RampCache,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResourceContext {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn advance(&mut self) {
|
|
||||||
self.ramps.advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.ramps.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_ramp(&mut self, stops: &[GradientStop]) -> u32 {
|
|
||||||
self.ramps.add(stops)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ramp_data(&self) -> &[u32] {
|
|
||||||
&self.ramps.data()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,12 +15,8 @@
|
||||||
// Also licensed under MIT license, at your choice.
|
// Also licensed under MIT license, at your choice.
|
||||||
|
|
||||||
use super::style::{Fill, Stroke};
|
use super::style::{Fill, Stroke};
|
||||||
use super::{
|
use super::{Affine, BlendMode, PathElement, Scene, SceneData, SceneFragment};
|
||||||
Affine, BlendMode, FragmentResources, PathElement, ResourcePatch, Scene, SceneData,
|
use crate::{brush::*, ResourcePatch};
|
||||||
SceneFragment,
|
|
||||||
};
|
|
||||||
use crate::brush::*;
|
|
||||||
use crate::resource::ResourceContext;
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -28,37 +24,27 @@ use smallvec::SmallVec;
|
||||||
/// Builder for constructing a scene or scene fragment.
|
/// Builder for constructing a scene or scene fragment.
|
||||||
pub struct SceneBuilder<'a> {
|
pub struct SceneBuilder<'a> {
|
||||||
scene: &'a mut SceneData,
|
scene: &'a mut SceneData,
|
||||||
resources: ResourceData<'a>,
|
|
||||||
layers: SmallVec<[BlendMode; 8]>,
|
layers: SmallVec<[BlendMode; 8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SceneBuilder<'a> {
|
impl<'a> SceneBuilder<'a> {
|
||||||
/// Creates a new builder for filling a scene. Any current content in the scene
|
/// Creates a new builder for filling a scene. Any current content in the scene
|
||||||
/// will be cleared.
|
/// will be cleared.
|
||||||
pub fn for_scene(scene: &'a mut Scene, rcx: &'a mut ResourceContext) -> Self {
|
pub fn for_scene(scene: &'a mut Scene) -> Self {
|
||||||
Self::new(&mut scene.data, ResourceData::Scene(rcx))
|
Self::new(&mut scene.data, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new builder for filling a scene fragment. Any current content in
|
/// Creates a new builder for filling a scene fragment. Any current content in
|
||||||
/// the fragment will be cleared.
|
/// the fragment will be cleared.
|
||||||
pub fn for_fragment(fragment: &'a mut SceneFragment) -> Self {
|
pub fn for_fragment(fragment: &'a mut SceneFragment) -> Self {
|
||||||
Self::new(
|
Self::new(&mut fragment.data, true)
|
||||||
&mut fragment.data,
|
|
||||||
ResourceData::Fragment(&mut fragment.resources),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new builder for constructing a scene.
|
/// Creates a new builder for constructing a scene.
|
||||||
fn new(scene: &'a mut SceneData, mut resources: ResourceData<'a>) -> Self {
|
fn new(scene: &'a mut SceneData, is_fragment: bool) -> Self {
|
||||||
let is_fragment = match resources {
|
|
||||||
ResourceData::Fragment(_) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
scene.reset(is_fragment);
|
scene.reset(is_fragment);
|
||||||
resources.clear();
|
|
||||||
Self {
|
Self {
|
||||||
scene,
|
scene,
|
||||||
resources,
|
|
||||||
layers: Default::default(),
|
layers: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +147,6 @@ impl<'a> SceneBuilder<'a> {
|
||||||
|
|
||||||
/// Appends a fragment to the scene.
|
/// Appends a fragment to the scene.
|
||||||
pub fn append(&mut self, fragment: &SceneFragment, transform: Option<Affine>) {
|
pub fn append(&mut self, fragment: &SceneFragment, transform: Option<Affine>) {
|
||||||
let drawdata_base = self.scene.drawdata_stream.len();
|
|
||||||
let mut cur_transform = self.scene.transform_stream.last().copied();
|
let mut cur_transform = self.scene.transform_stream.last().copied();
|
||||||
if let Some(transform) = transform {
|
if let Some(transform) = transform {
|
||||||
if cur_transform.is_none() {
|
if cur_transform.is_none() {
|
||||||
|
@ -172,39 +157,6 @@ impl<'a> SceneBuilder<'a> {
|
||||||
self.encode_transform(Affine::IDENTITY);
|
self.encode_transform(Affine::IDENTITY);
|
||||||
}
|
}
|
||||||
self.scene.append(&fragment.data, &transform);
|
self.scene.append(&fragment.data, &transform);
|
||||||
match &mut self.resources {
|
|
||||||
ResourceData::Scene(res) => {
|
|
||||||
for patch in &fragment.resources.patches {
|
|
||||||
match patch {
|
|
||||||
ResourcePatch::Ramp {
|
|
||||||
drawdata_offset,
|
|
||||||
stops,
|
|
||||||
} => {
|
|
||||||
let stops = &fragment.resources.stops[stops.clone()];
|
|
||||||
let ramp_id = res.add_ramp(stops);
|
|
||||||
let patch_base = *drawdata_offset + drawdata_base;
|
|
||||||
(&mut self.scene.drawdata_stream[patch_base..patch_base + 4])
|
|
||||||
.copy_from_slice(bytemuck::bytes_of(&ramp_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ResourceData::Fragment(res) => {
|
|
||||||
let stops_base = res.stops.len();
|
|
||||||
res.stops.extend_from_slice(&fragment.resources.stops);
|
|
||||||
res.patches.extend(fragment.resources.patches.iter().map(
|
|
||||||
|pending| match pending {
|
|
||||||
ResourcePatch::Ramp {
|
|
||||||
drawdata_offset,
|
|
||||||
stops,
|
|
||||||
} => ResourcePatch::Ramp {
|
|
||||||
drawdata_offset: drawdata_offset + drawdata_base,
|
|
||||||
stops: stops.start + stops_base..stops.end + stops_base,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Prevent fragments from affecting transform state. Should we allow this?
|
// Prevent fragments from affecting transform state. Should we allow this?
|
||||||
if let Some(transform) = cur_transform {
|
if let Some(transform) = cur_transform {
|
||||||
self.transform(transform);
|
self.transform(transform);
|
||||||
|
@ -325,19 +277,15 @@ impl<'a> SceneBuilder<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_ramp(&mut self, stops: &[GradientStop]) -> u32 {
|
fn add_ramp(&mut self, stops: &[GradientStop]) -> u32 {
|
||||||
match &mut self.resources {
|
let offset = self.scene.drawdata_stream.len();
|
||||||
ResourceData::Scene(res) => res.add_ramp(stops),
|
let resources = &mut self.scene.resources;
|
||||||
ResourceData::Fragment(res) => {
|
let stops_start = resources.stops.len();
|
||||||
let stops_start = res.stops.len();
|
resources.stops.extend_from_slice(stops);
|
||||||
res.stops.extend_from_slice(stops);
|
resources.patches.push(ResourcePatch::Ramp {
|
||||||
let id = res.patches.len() as u32;
|
offset,
|
||||||
res.patches.push(ResourcePatch::Ramp {
|
|
||||||
drawdata_offset: self.scene.drawdata_stream.len(),
|
|
||||||
stops: stops_start..stops_start + stops.len(),
|
stops: stops_start..stops_start + stops.len(),
|
||||||
});
|
});
|
||||||
id
|
0
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a clip.
|
/// Start a clip.
|
||||||
|
@ -366,22 +314,6 @@ impl<'a> SceneBuilder<'a> {
|
||||||
self.scene.n_clip += 1;
|
self.scene.n_clip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enum ResourceData<'a> {
|
|
||||||
Fragment(&'a mut FragmentResources),
|
|
||||||
Scene(&'a mut ResourceContext),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResourceData<'_> {
|
|
||||||
fn clear(&mut self) {
|
|
||||||
match self {
|
|
||||||
Self::Fragment(res) => {
|
|
||||||
res.patches.clear();
|
|
||||||
res.stops.clear();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tags for draw objects. See shader/drawtag.h for the authoritative source.
|
// Tags for draw objects. See shader/drawtag.h for the authoritative source.
|
||||||
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
const DRAWTAG_FILLCOLOR: u32 = 0x44;
|
||||||
|
|
|
@ -22,11 +22,9 @@ pub use blend::{BlendMode, Compose, Mix};
|
||||||
pub use builder::SceneBuilder;
|
pub use builder::SceneBuilder;
|
||||||
pub use style::*;
|
pub use style::*;
|
||||||
|
|
||||||
use super::brush::*;
|
|
||||||
use super::geometry::{Affine, Point};
|
use super::geometry::{Affine, Point};
|
||||||
use super::path::PathElement;
|
use super::path::PathElement;
|
||||||
|
use super::resource::{ResourceBundle, ResourcePatch};
|
||||||
use core::ops::Range;
|
|
||||||
|
|
||||||
/// Raw data streams describing an encoded scene.
|
/// Raw data streams describing an encoded scene.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -40,6 +38,7 @@ pub struct SceneData {
|
||||||
pub n_path: u32,
|
pub n_path: u32,
|
||||||
pub n_pathseg: u32,
|
pub n_pathseg: u32,
|
||||||
pub n_clip: u32,
|
pub n_clip: u32,
|
||||||
|
pub resources: ResourceBundle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneData {
|
impl SceneData {
|
||||||
|
@ -57,6 +56,7 @@ impl SceneData {
|
||||||
self.n_path = 0;
|
self.n_path = 0;
|
||||||
self.n_pathseg = 0;
|
self.n_pathseg = 0;
|
||||||
self.n_clip = 0;
|
self.n_clip = 0;
|
||||||
|
self.resources.clear();
|
||||||
if !is_fragment {
|
if !is_fragment {
|
||||||
self.transform_stream
|
self.transform_stream
|
||||||
.push(Affine::new(&[1.0, 0.0, 0.0, 1.0, 0.0, 0.0]));
|
.push(Affine::new(&[1.0, 0.0, 0.0, 1.0, 0.0, 0.0]));
|
||||||
|
@ -65,9 +65,11 @@ impl SceneData {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append(&mut self, other: &SceneData, transform: &Option<Affine>) {
|
fn append(&mut self, other: &SceneData, transform: &Option<Affine>) {
|
||||||
|
let stops_base = self.resources.stops.len();
|
||||||
|
let drawdata_base = self.drawdata_stream.len();
|
||||||
if let Some(transform) = *transform {
|
if let Some(transform) = *transform {
|
||||||
self.transform_stream
|
self.transform_stream
|
||||||
.extend(other.transform_stream.iter().map(|x| *x * transform));
|
.extend(other.transform_stream.iter().map(|x| transform * *x));
|
||||||
} else {
|
} else {
|
||||||
self.transform_stream
|
self.transform_stream
|
||||||
.extend_from_slice(&other.transform_stream);
|
.extend_from_slice(&other.transform_stream);
|
||||||
|
@ -82,6 +84,20 @@ impl SceneData {
|
||||||
self.n_path += other.n_path;
|
self.n_path += other.n_path;
|
||||||
self.n_pathseg += other.n_pathseg;
|
self.n_pathseg += other.n_pathseg;
|
||||||
self.n_clip += other.n_clip;
|
self.n_clip += other.n_clip;
|
||||||
|
self.resources
|
||||||
|
.stops
|
||||||
|
.extend_from_slice(&other.resources.stops);
|
||||||
|
self.resources
|
||||||
|
.patches
|
||||||
|
.extend(other.resources.patches.iter().map(|patch| match patch {
|
||||||
|
ResourcePatch::Ramp { offset, stops } => {
|
||||||
|
let stops = stops.start + stops_base..stops.end + stops_base;
|
||||||
|
ResourcePatch::Ramp {
|
||||||
|
offset: drawdata_base + offset,
|
||||||
|
stops,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +119,6 @@ impl Scene {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SceneFragment {
|
pub struct SceneFragment {
|
||||||
data: SceneData,
|
data: SceneData,
|
||||||
resources: FragmentResources,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneFragment {
|
impl SceneFragment {
|
||||||
|
@ -122,16 +137,3 @@ impl SceneFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct FragmentResources {
|
|
||||||
patches: Vec<ResourcePatch>,
|
|
||||||
stops: Vec<GradientStop>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ResourcePatch {
|
|
||||||
Ramp {
|
|
||||||
drawdata_offset: usize,
|
|
||||||
stops: Range<usize>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue