mirror of
https://github.com/penpot/penpot.git
synced 2026-07-23 06:28:14 +00:00
♻️ Refactor max texture size
This commit is contained in:
parent
0e862c4ff1
commit
137a7afd1b
@ -1871,8 +1871,6 @@
|
||||
(h/call wasm/internal-module "_set_node_batch_threshold" t))
|
||||
(when-let [t (wasm-blur-downscale-threshold-from-route-params)]
|
||||
(h/call wasm/internal-module "_set_blur_downscale_threshold" t))
|
||||
(when-let [max-tex (webgl/max-texture-size context)]
|
||||
(h/call wasm/internal-module "_set_max_texture_size" max-tex))
|
||||
|
||||
;; Set browser and canvas size only after initialization
|
||||
(h/call wasm/internal-module "_set_browser" browser)
|
||||
|
||||
@ -11,15 +11,6 @@
|
||||
[app.render-wasm.wasm :as wasm]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn max-texture-size
|
||||
"Returns `gl.MAX_TEXTURE_SIZE` (max dimension of a 2D texture), or nil if
|
||||
unavailable."
|
||||
[gl]
|
||||
(when gl
|
||||
(let [n (.getParameter ^js gl (.-MAX_TEXTURE_SIZE ^js gl))]
|
||||
(when (and (number? n) (pos? n) (js/isFinite n))
|
||||
(js/Math.floor n)))))
|
||||
|
||||
(defn get-webgl-context
|
||||
"Gets the WebGL context from the WASM module"
|
||||
[]
|
||||
|
||||
@ -90,15 +90,6 @@ pub extern "C" fn set_antialias_threshold(threshold: f32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_max_texture_size(max_px: i32) -> Result<()> {
|
||||
get_render_state()
|
||||
.surfaces
|
||||
.set_max_texture_size(max_px);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn set_canvas_background(raw_color: u32) -> Result<()> {
|
||||
|
||||
@ -412,7 +412,7 @@ pub struct InteractiveDragCrop {
|
||||
/// Chooses a window inside the full workspace-pixel crop `[0, out_w) × [0, out_h)` with each side
|
||||
/// at most `max_side_px` (**without scaling**): centered on the projection of
|
||||
/// `viewport_doc ∩ src_doc_bounds`, or on the full crop if that intersection is empty.
|
||||
/// `max_side_px` should match [`Surfaces::max_texture_dimension_px`] (same budget as the atlas).
|
||||
/// `max_side_px` should match [`GpuState::max_texture_size`] (same budget as the atlas).
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn drag_crop_snapshot_window_px(
|
||||
max_side_px: i32,
|
||||
@ -1766,7 +1766,7 @@ impl RenderState {
|
||||
let vb_left = self.viewbox.area.left;
|
||||
let vb_top = self.viewbox.area.top;
|
||||
let (bb_w, bb_h) = self.surfaces.surface_size(SurfaceId::Backbuffer);
|
||||
let max_snap_px = self.surfaces.max_texture_dimension_px();
|
||||
let max_snap_px = get_gpu_state().max_texture_size();
|
||||
|
||||
// Snapshot the atlas once for the whole pass so that all shapes sharing
|
||||
// the tile/atlas fallback path reuse the same GPU image rather than each
|
||||
@ -3578,7 +3578,9 @@ impl RenderState {
|
||||
if tree.get_modifier(&shape.id).is_some() {
|
||||
if let Some(raw_shape) = tree.get_raw(&shape.id) {
|
||||
let old_extrect = raw_shape.extrect(tree, 1.0);
|
||||
self.surfaces.atlas.clear_doc_rect_in_atlas_clipped(old_extrect);
|
||||
self.surfaces
|
||||
.atlas
|
||||
.clear_doc_rect_in_atlas_clipped(old_extrect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,9 @@ use skia_safe::gpu::{
|
||||
};
|
||||
use skia_safe::{self as skia, ISize};
|
||||
|
||||
const MIN_MAX_TEXTURE_SIZE: i32 = 512;
|
||||
const MAX_MAX_TEXTURE_SIZE: i32 = 8192 * 2;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuState {
|
||||
pub context: DirectContext,
|
||||
@ -29,8 +32,6 @@ impl GpuState {
|
||||
Error::CriticalError("Failed to create GL context".to_string()),
|
||||
)?;
|
||||
|
||||
println!("max_texture_size {}", context.max_texture_size());
|
||||
|
||||
let framebuffer_info = {
|
||||
let mut fboid: gl::types::GLint = 0;
|
||||
unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) };
|
||||
@ -50,6 +51,12 @@ impl GpuState {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn max_texture_size(&self) -> i32 {
|
||||
self.context
|
||||
.max_texture_size()
|
||||
.clamp(MIN_MAX_TEXTURE_SIZE, MAX_MAX_TEXTURE_SIZE)
|
||||
}
|
||||
|
||||
fn delete_gl_texture(&mut self, texture_id: gl::types::GLuint) -> bool {
|
||||
unsafe {
|
||||
gl::DeleteTextures(1, &texture_id);
|
||||
|
||||
@ -26,15 +26,6 @@ const TILE_DRAWABLE_RECT: IRect = IRect {
|
||||
bottom: TILE_MARGIN_SIZE + TILE_SIZE,
|
||||
};
|
||||
|
||||
/// Atlas texture size limits (px per side).
|
||||
///
|
||||
/// - `DEFAULT_ATLAS_TEXTURE_SIZE` is the startup fallback used until the
|
||||
/// frontend reads the real `gl.MAX_TEXTURE_SIZE` and sends it via
|
||||
/// [`Surfaces::atlas.set_max_texture_size`].
|
||||
/// - `atlas.max_texture_size` is a hard upper bound to clamp the runtime value
|
||||
/// (defensive cap to avoid accidentally creating oversized GPU textures).
|
||||
const MAX_ATLAS_TEXTURE_SIZE: i32 = 8192;
|
||||
|
||||
pub fn get_cache_size(viewbox: &Viewbox, interest: i32) -> skia::ISize {
|
||||
// First we retrieve the extended area of the viewport that we could render.
|
||||
let TileRect(isx, isy, iex, iey) =
|
||||
@ -90,9 +81,6 @@ pub struct DocAtlas {
|
||||
/// Optional document-space bounds (1 unit == 1 doc px @ 100% zoom) used to
|
||||
/// clamp atlas writes/clears so the atlas doesn't grow due to outlier tile rects.
|
||||
pub doc_bounds: Option<skia::Rect>,
|
||||
/// Max width/height in pixels for the atlas surface (typically browser
|
||||
/// `MAX_TEXTURE_SIZE`). Set from ClojureScript after WebGL context creation.
|
||||
pub max_texture_size: i32,
|
||||
/// Tracks the last document-space rect written to the atlas per tile.
|
||||
/// Used to clear old content without clearing the whole (potentially huge) tile rect.
|
||||
pub tile_doc_rects: HashMap<Tile, skia::Rect>,
|
||||
@ -102,8 +90,8 @@ impl DocAtlas {
|
||||
pub fn try_new() -> Result<Self> {
|
||||
// Keep atlas as a regular surface like the rest. Start with a tiny
|
||||
// transparent surface and grow it on demand.
|
||||
let mut surface = get_gpu_state()
|
||||
.create_surface_with_dimensions("atlas".to_string(), 1, 1)?;
|
||||
let mut surface =
|
||||
get_gpu_state().create_surface_with_dimensions("atlas".to_string(), 1, 1)?;
|
||||
|
||||
surface.canvas().clear(skia::Color::TRANSPARENT);
|
||||
|
||||
@ -113,8 +101,7 @@ impl DocAtlas {
|
||||
size: skia::ISize::new(0, 0),
|
||||
scale: 1.0,
|
||||
doc_bounds: None,
|
||||
max_texture_size: MAX_ATLAS_TEXTURE_SIZE,
|
||||
tile_doc_rects: HashMap::default()
|
||||
tile_doc_rects: HashMap::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -122,13 +109,6 @@ impl DocAtlas {
|
||||
self.size.width <= 0 || self.size.height <= 0
|
||||
}
|
||||
|
||||
/// Sets the maximum atlas texture dimension (one side). Should match the
|
||||
/// WebGL `MAX_TEXTURE_SIZE` reported by the browser. Values are clamped to
|
||||
/// a small minimum so the atlas logic stays well-defined.
|
||||
pub fn set_max_texture_size(&mut self, max_px: i32) {
|
||||
self.max_texture_size = max_px.clamp(TILE_SIZE, self.max_texture_size);
|
||||
}
|
||||
|
||||
/// Sets the document-space bounds used to clamp atlas updates.
|
||||
/// Pass `None` to disable clamping.
|
||||
pub fn set_doc_bounds(&mut self, bounds: Option<skia::Rect>) {
|
||||
@ -198,7 +178,7 @@ impl DocAtlas {
|
||||
|
||||
// Compute atlas scale needed to fit within the fixed texture cap.
|
||||
// Keep the highest possible scale (closest to 1.0) that still fits.
|
||||
let cap = self.max_texture_size.max(TILE_SIZE) as f32;
|
||||
let cap = gpu_state.max_texture_size().max(TILE_SIZE) as f32;
|
||||
let required_scale = (cap / doc_w).min(cap / doc_h).clamp(0.01, 1.0);
|
||||
|
||||
// Never upscale the atlas (it would add blur and churn).
|
||||
@ -229,12 +209,8 @@ impl DocAtlas {
|
||||
let dy = (current_top - new_top) * new_scale;
|
||||
|
||||
let image = self.surface.image_snapshot();
|
||||
let src = skia::Rect::from_xywh(
|
||||
0.0,
|
||||
0.0,
|
||||
self.size.width as f32,
|
||||
self.size.height as f32,
|
||||
);
|
||||
let src =
|
||||
skia::Rect::from_xywh(0.0, 0.0, self.size.width as f32, self.size.height as f32);
|
||||
let dst = skia::Rect::from_xywh(
|
||||
dx,
|
||||
dy,
|
||||
@ -415,7 +391,6 @@ impl DocAtlas {
|
||||
self.origin,
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct Surfaces {
|
||||
@ -477,9 +452,7 @@ impl Surfaces {
|
||||
let backbuffer =
|
||||
gpu_state.create_surface_with_dimensions("backbuffer".to_string(), width, height)?;
|
||||
|
||||
// TODO: Obtener este tamaño de alguna otra parte.
|
||||
let max_texture_size = 8192;
|
||||
// NOTA: Esta textura debería utilizar el máximo permitido por la GPU.
|
||||
let max_texture_size = gpu_state.max_texture_size();
|
||||
let tile_atlas = gpu_state.create_surface_with_dimensions(
|
||||
"tile_atlas".to_string(),
|
||||
max_texture_size,
|
||||
@ -536,15 +509,6 @@ impl Surfaces {
|
||||
self.dpr = dpr;
|
||||
}
|
||||
|
||||
pub fn set_max_texture_size(&mut self, max_texture_size: i32) {
|
||||
self.atlas.set_max_texture_size(max_texture_size);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max_texture_dimension_px(&self) -> i32 {
|
||||
self.atlas.max_texture_size
|
||||
}
|
||||
|
||||
pub fn clear_tiles(&mut self) {
|
||||
self.tiles.clear();
|
||||
}
|
||||
@ -1157,7 +1121,9 @@ impl Surfaces {
|
||||
|
||||
// Incrementally update persistent 1:1 atlas in document space.
|
||||
// `tile_doc_rect` is in world/document coordinates (1 unit == 1 px at 100%).
|
||||
let _ = self.atlas.blit_tile_image_into_atlas(gpu_state, &tile_image, tile_doc_rect);
|
||||
let _ = self
|
||||
.atlas
|
||||
.blit_tile_image_into_atlas(gpu_state, &tile_image, tile_doc_rect);
|
||||
self.atlas.tile_doc_rects.insert(*tile, tile_doc_rect);
|
||||
|
||||
// Draws current tile into tile atlas
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user