diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index d9ebccf50a..bdc7a456a9 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -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) diff --git a/frontend/src/app/render_wasm/api/webgl.cljs b/frontend/src/app/render_wasm/api/webgl.cljs index 7442947953..3ea6445d54 100644 --- a/frontend/src/app/render_wasm/api/webgl.cljs +++ b/frontend/src/app/render_wasm/api/webgl.cljs @@ -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" [] diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 1824ccddb5..bf01095b99 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -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<()> { diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 4cb53b1634..1d0f537353 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -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); } } diff --git a/render-wasm/src/render/gpu_state.rs b/render-wasm/src/render/gpu_state.rs index f8e4fa0db0..e934dd4f34 100644 --- a/render-wasm/src/render/gpu_state.rs +++ b/render-wasm/src/render/gpu_state.rs @@ -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); diff --git a/render-wasm/src/render/surfaces.rs b/render-wasm/src/render/surfaces.rs index f57eda0491..5c60e20db7 100644 --- a/render-wasm/src/render/surfaces.rs +++ b/render-wasm/src/render/surfaces.rs @@ -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, - /// 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, @@ -102,8 +90,8 @@ impl DocAtlas { pub fn try_new() -> Result { // 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) { @@ -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