mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Reimplement checkered background rendering (#4034)
* Reimplement background checkerboard rendering
This commit is contained in:
@@ -6,7 +6,7 @@ use core_types::{CloneVarArgs, Context, Ctx, ExtractAll, ExtractAnimationTime, E
|
||||
use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use graph_craft::application_io::PlatformEditorApi;
|
||||
use graph_craft::document::value::RenderOutput;
|
||||
use graphene_application_io::ApplicationIo;
|
||||
use graphene_application_io::{ApplicationIo, ImageTexture};
|
||||
use rendering::{RenderOutputType as RenderOutputTypeRequest, RenderParams};
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
@@ -26,7 +26,7 @@ pub struct TileCoord {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CachedRegion {
|
||||
pub texture: wgpu::Texture,
|
||||
pub texture: ImageTexture,
|
||||
pub texture_size: UVec2,
|
||||
pub tiles: Vec<TileCoord>,
|
||||
pub metadata: rendering::RenderMetadata,
|
||||
@@ -41,7 +41,6 @@ pub struct CacheKey {
|
||||
pub device_scale: u64,
|
||||
pub zoom: u64,
|
||||
pub rotation: u64,
|
||||
pub hide_artboards: bool,
|
||||
pub for_export: bool,
|
||||
pub for_mask: bool,
|
||||
pub thumbnail: bool,
|
||||
@@ -60,7 +59,6 @@ impl CacheKey {
|
||||
device_scale: f64,
|
||||
zoom: f64,
|
||||
rotation: f64,
|
||||
hide_artboards: bool,
|
||||
for_export: bool,
|
||||
for_mask: bool,
|
||||
thumbnail: bool,
|
||||
@@ -87,7 +85,6 @@ impl CacheKey {
|
||||
device_scale: device_scale.to_bits(),
|
||||
zoom: zoom.to_bits(),
|
||||
rotation: quantized_rotation.to_bits(),
|
||||
hide_artboards,
|
||||
for_export,
|
||||
for_mask,
|
||||
thumbnail,
|
||||
@@ -100,23 +97,27 @@ impl CacheKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, dyn_any::DynAny, Debug)]
|
||||
pub struct TileCache(Arc<Mutex<TileCacheImpl>>);
|
||||
|
||||
impl TileCache {
|
||||
pub fn query(&self, viewport_bounds: &AxisAlignedBbox, cache_key: &CacheKey, max_region_area: u32) -> CacheQuery {
|
||||
self.0.lock().unwrap().query(viewport_bounds, cache_key, max_region_area)
|
||||
}
|
||||
|
||||
pub fn store_regions(&self, regions: Vec<CachedRegion>) {
|
||||
self.0.lock().unwrap().store_regions(regions);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct TileCacheImpl {
|
||||
regions: Vec<CachedRegion>,
|
||||
timestamp: u64,
|
||||
total_memory: usize,
|
||||
cache_key: CacheKey,
|
||||
texture_cache_resolution: UVec2,
|
||||
/// Pool of textures of the same size: `texture_cache_resolution`.
|
||||
/// Reusing textures reduces the wgpu allocation pressure,
|
||||
/// which is a problem on web since we have to wait for
|
||||
/// the browser to garbage collect unused textures, eating up memory.
|
||||
texture_cache: Vec<Arc<wgpu::Texture>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, dyn_any::DynAny, Debug)]
|
||||
pub struct TileCache(Arc<Mutex<TileCacheImpl>>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RenderRegion {
|
||||
pub tiles: Vec<TileCoord>,
|
||||
@@ -205,7 +206,6 @@ impl TileCacheImpl {
|
||||
while self.total_memory > MAX_CACHE_MEMORY_BYTES && !self.regions.is_empty() {
|
||||
if let Some((oldest_idx, _)) = self.regions.iter().enumerate().min_by_key(|(_, r)| r.last_access) {
|
||||
let removed = self.regions.remove(oldest_idx);
|
||||
removed.texture.destroy();
|
||||
self.total_memory = self.total_memory.saturating_sub(removed.memory_size);
|
||||
} else {
|
||||
break;
|
||||
@@ -214,56 +214,9 @@ impl TileCacheImpl {
|
||||
}
|
||||
|
||||
fn invalidate_all(&mut self) {
|
||||
for region in &self.regions {
|
||||
region.texture.destroy();
|
||||
}
|
||||
self.regions.clear();
|
||||
self.total_memory = 0;
|
||||
}
|
||||
|
||||
pub fn request_texture(&mut self, size: UVec2, device: &wgpu::Device) -> Arc<wgpu::Texture> {
|
||||
if self.texture_cache_resolution != size {
|
||||
self.texture_cache_resolution = size;
|
||||
self.texture_cache.clear();
|
||||
}
|
||||
self.texture_cache.truncate(5);
|
||||
for texture in &self.texture_cache {
|
||||
if Arc::strong_count(texture) == 1 {
|
||||
return Arc::clone(texture);
|
||||
}
|
||||
}
|
||||
let texture = Arc::new(device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("viewport_output"),
|
||||
size: wgpu::Extent3d {
|
||||
width: size.x,
|
||||
height: size.y,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
}));
|
||||
self.texture_cache.push(texture.clone());
|
||||
|
||||
texture
|
||||
}
|
||||
}
|
||||
|
||||
impl TileCache {
|
||||
pub fn query(&self, viewport_bounds: &AxisAlignedBbox, cache_key: &CacheKey, max_region_area: u32) -> CacheQuery {
|
||||
self.0.lock().unwrap().query(viewport_bounds, cache_key, max_region_area)
|
||||
}
|
||||
|
||||
pub fn store_regions(&self, regions: Vec<CachedRegion>) {
|
||||
self.0.lock().unwrap().store_regions(regions);
|
||||
}
|
||||
|
||||
pub fn request_texture(&self, size: UVec2, device: &wgpu::Device) -> Arc<wgpu::Texture> {
|
||||
self.0.lock().unwrap().request_texture(size, device)
|
||||
}
|
||||
}
|
||||
|
||||
fn group_into_regions(tiles: &[TileCoord], max_region_area: u32) -> Vec<RenderRegion> {
|
||||
@@ -411,7 +364,6 @@ pub async fn render_output_cache<'a: 'n>(
|
||||
device_scale,
|
||||
zoom,
|
||||
rotation,
|
||||
render_params.hide_artboards,
|
||||
render_params.for_export,
|
||||
render_params.for_mask,
|
||||
render_params.thumbnail,
|
||||
@@ -454,10 +406,9 @@ pub async fn render_output_cache<'a: 'n>(
|
||||
|
||||
let exec = editor_api.application_io.as_ref().unwrap().gpu_executor().unwrap();
|
||||
|
||||
let device = &exec.context.device;
|
||||
let output_texture = tile_cache.request_texture(physical_resolution, device);
|
||||
let output_texture = exec.request_texture(physical_resolution).await;
|
||||
|
||||
let combined_metadata = composite_cached_regions(&all_regions, output_texture.as_ref(), &device_origin_offset, &footprint.transform, exec);
|
||||
let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, exec);
|
||||
|
||||
RenderOutput {
|
||||
data: RenderOutputType::Texture(output_texture.into()),
|
||||
@@ -496,7 +447,7 @@ where
|
||||
let region_ctx = OwnedContextImpl::from(ctx).with_footprint(region_footprint).with_vararg(Box::new(region_params)).into_context();
|
||||
let mut result = render_fn(region_ctx).await;
|
||||
|
||||
let RenderOutputType::Texture(rendered_texture) = result.data else {
|
||||
let RenderOutputType::Texture(texture) = result.data else {
|
||||
unreachable!("render_missing_region: expected texture output from Vello render");
|
||||
};
|
||||
|
||||
@@ -506,7 +457,7 @@ where
|
||||
let memory_size = (region_pixel_size.x * region_pixel_size.y) as usize * BYTES_PER_PIXEL;
|
||||
|
||||
CachedRegion {
|
||||
texture: rendered_texture.as_ref().clone(),
|
||||
texture,
|
||||
texture_size: region_pixel_size,
|
||||
tiles: region.tiles.clone(),
|
||||
metadata: result.metadata,
|
||||
@@ -552,7 +503,7 @@ fn composite_cached_regions(
|
||||
if width > 0 && height > 0 {
|
||||
encoder.copy_texture_to_texture(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: ®ion.texture,
|
||||
texture: region.texture.as_ref(),
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d { x: src_x, y: src_y, z: 0 },
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
|
||||
Reference in New Issue
Block a user