diff --git a/webrender/res/cs_scale.glsl b/webrender/res/cs_scale.glsl new file mode 100644 index 0000000000..13070d05c9 --- /dev/null +++ b/webrender/res/cs_scale.glsl @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include shared,prim_shared + +varying vec3 vUv; +flat varying vec4 vUvRect; + +#ifdef WR_VERTEX_SHADER + +in int aScaleRenderTaskAddress; +in int aScaleSourceTaskAddress; + +struct ScaleTask { + RenderTaskCommonData common_data; +}; + +ScaleTask fetch_scale_task(int address) { + RenderTaskData task_data = fetch_render_task_data(address); + + ScaleTask task = ScaleTask(task_data.common_data); + + return task; +} + +void main(void) { + ScaleTask scale_task = fetch_scale_task(aScaleRenderTaskAddress); + RenderTaskCommonData src_task = fetch_render_task_common_data(aScaleSourceTaskAddress); + + RectWithSize src_rect = src_task.task_rect; + RectWithSize target_rect = scale_task.common_data.task_rect; + +#if defined WR_FEATURE_COLOR_TARGET + vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0).xy); +#else + vec2 texture_size = vec2(textureSize(sCacheA8, 0).xy); +#endif + + vUv.z = src_task.texture_layer_index; + + vUvRect = vec4(src_rect.p0 + vec2(0.5), + src_rect.p0 + src_rect.size - vec2(0.5)) / texture_size.xyxy; + + vec2 pos = target_rect.p0 + target_rect.size * aPosition.xy; + vUv.xy = (src_rect.p0 + src_rect.size * aPosition.xy) / texture_size; + + gl_Position = uTransform * vec4(pos, 0.0, 1.0); +} + +#endif + +#ifdef WR_FRAGMENT_SHADER + +#if defined WR_FEATURE_COLOR_TARGET +#define SAMPLE_TYPE vec4 +#define SAMPLE_TEXTURE(uv) texture(sCacheRGBA8, uv) +#else +#define SAMPLE_TYPE float +#define SAMPLE_TEXTURE(uv) texture(sCacheA8, uv).r +#endif + +void main(void) { + vec2 st = clamp(vUv.xy, vUvRect.xy, vUvRect.zw); + oFragColor = vec4(SAMPLE_TEXTURE(vec3(st, vUv.z))); +} + +#endif diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 50beff47f4..9ef9e7bec8 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -80,6 +80,15 @@ pub struct BlurInstance { pub blur_direction: BlurDirection, } +#[derive(Debug)] +#[repr(C)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ScalingInstance { + pub task_address: RenderTaskAddress, + pub src_task_address: RenderTaskAddress, +} + #[derive(Debug, Copy, Clone, PartialEq)] #[repr(C)] #[cfg_attr(feature = "capture", derive(Serialize))] diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index ba77a73761..1f0fab652d 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -229,6 +229,15 @@ impl BlurTask { } } +#[derive(Debug)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ScalingTask { + pub target_kind: RenderTargetKind, + pub uv_rect_handle: GpuCacheHandle, + uv_rect_kind: UvRectKind, +} + #[derive(Debug)] #[cfg(feature = "pathfinder")] #[cfg_attr(feature = "capture", derive(Serialize))] @@ -295,7 +304,7 @@ pub enum RenderTaskKind { #[allow(dead_code)] Glyph(GlyphTask), Readback(DeviceIntRect), - Scaling(RenderTargetKind), + Scaling(ScalingTask), Blit(BlitTask), Border(BorderTask), } @@ -569,8 +578,9 @@ impl RenderTask { scale_factor *= 2.0; adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32(); let downscaling_task = RenderTask::new_scaling( - target_kind, downscaling_src_task_id, + render_tasks, + target_kind, adjusted_blur_target_size, ); downscaling_src_task_id = render_tasks.add(downscaling_task); @@ -618,14 +628,21 @@ impl RenderTask { } pub fn new_scaling( - target_kind: RenderTargetKind, src_task_id: RenderTaskId, + render_tasks: &mut RenderTaskTree, + target_kind: RenderTargetKind, target_size: DeviceIntSize, ) -> Self { + let uv_rect_kind = render_tasks[src_task_id].uv_rect_kind(); + RenderTask::with_dynamic_location( target_size, vec![src_task_id], - RenderTaskKind::Scaling(target_kind), + RenderTaskKind::Scaling(ScalingTask { + target_kind, + uv_rect_handle: GpuCacheHandle::new(), + uv_rect_kind, + }), match target_kind { RenderTargetKind::Color => ClearMode::Transparent, RenderTargetKind::Alpha => ClearMode::One, @@ -659,8 +676,7 @@ impl RenderTask { fn uv_rect_kind(&self) -> UvRectKind { match self.kind { RenderTaskKind::CacheMask(..) | - RenderTaskKind::Readback(..) | - RenderTaskKind::Scaling(..) => { + RenderTaskKind::Readback(..) => { unreachable!("bug: unexpected render task"); } @@ -673,6 +689,10 @@ impl RenderTask { task.uv_rect_kind } + RenderTaskKind::Scaling(ref task) => { + task.uv_rect_kind + } + RenderTaskKind::ClipRegion(..) | RenderTaskKind::Glyph(_) | RenderTaskKind::Border(..) | @@ -836,8 +856,8 @@ impl RenderTask { RenderTargetKind::Color } - RenderTaskKind::Scaling(target_kind) => { - target_kind + RenderTaskKind::Scaling(ref task_info) => { + task_info.target_kind } RenderTaskKind::Border(..) | diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 818d04f820..f90c5ccee7 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -38,6 +38,7 @@ use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; use gpu_cache::GpuDebugChunk; #[cfg(feature = "pathfinder")] use gpu_glyph_renderer::GpuGlyphRenderer; +use gpu_types::ScalingInstance; use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError}; use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg}; use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource}; @@ -70,7 +71,7 @@ use texture_cache::TextureCache; use thread_profiler::{register_thread_with_profiler, write_profile}; use tiling::{AlphaRenderTarget, ColorRenderTarget}; use tiling::{BlitJob, BlitJobSource, RenderPass, RenderPassKind, RenderTargetList}; -use tiling::{Frame, RenderTarget, RenderTargetKind, ScalingInfo, TextureCacheRenderTarget}; +use tiling::{Frame, RenderTarget, RenderTargetKind, TextureCacheRenderTarget}; #[cfg(not(feature = "pathfinder"))] use tiling::GlyphJob; use time::precise_time_ns; @@ -432,6 +433,28 @@ pub(crate) mod desc { ], }; + pub const SCALE: VertexDescriptor = VertexDescriptor { + vertex_attributes: &[ + VertexAttribute { + name: "aPosition", + count: 2, + kind: VertexAttributeKind::F32, + }, + ], + instance_attributes: &[ + VertexAttribute { + name: "aScaleRenderTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + VertexAttribute { + name: "aScaleSourceTaskAddress", + count: 1, + kind: VertexAttributeKind::I32, + }, + ], + }; + pub const CLIP: VertexDescriptor = VertexDescriptor { vertex_attributes: &[ VertexAttribute { @@ -578,6 +601,7 @@ pub(crate) enum VertexArrayKind { VectorStencil, VectorCover, Border, + Scale, } #[derive(Clone, Debug, PartialEq)] @@ -1319,11 +1343,14 @@ impl LazyInitializedDebugRenderer { } } +// NB: If you add more VAOs here, be sure to deinitialize them in +// `Renderer::deinit()` below. pub struct RendererVAOs { prim_vao: VAO, blur_vao: VAO, clip_vao: VAO, border_vao: VAO, + scale_vao: VAO, } /// The renderer is responsible for submitting to the GPU the work prepared by the @@ -1622,8 +1649,8 @@ impl Renderer { let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao); let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao); - let border_vao = - device.create_vao_with_new_instances(&desc::BORDER, &prim_vao); + let border_vao = device.create_vao_with_new_instances(&desc::BORDER, &prim_vao); + let scale_vao = device.create_vao_with_new_instances(&desc::SCALE, &prim_vao); let texture_cache_upload_pbo = device.create_pbo(); let texture_resolver = SourceTextureResolver::new(&mut device); @@ -1814,6 +1841,7 @@ impl Renderer { blur_vao, clip_vao, border_vao, + scale_vao, }, transforms_texture, prim_header_i_texture, @@ -2826,26 +2854,35 @@ impl Renderer { fn handle_scaling( &mut self, - render_tasks: &RenderTaskTree, - scalings: &Vec, + scalings: &[ScalingInstance], source: SourceTexture, + projection: &Transform3D, + stats: &mut RendererStats, ) { - let cache_texture = self.texture_resolver - .resolve(&source) - .unwrap(); - for scaling in scalings { - let source = &render_tasks[scaling.src_task_id]; - let dest = &render_tasks[scaling.dest_task_id]; - - let (source_rect, source_layer) = source.get_target_rect(); - let (dest_rect, _) = dest.get_target_rect(); - - let cache_draw_target = (cache_texture, source_layer.0 as i32); - self.device - .bind_read_target(Some(cache_draw_target)); + if scalings.is_empty() { + return + } - self.device.blit_render_target(source_rect, dest_rect); + match source { + SourceTexture::CacheRGBA8 => { + self.shaders.cs_scale_rgba8.bind(&mut self.device, + &projection, + &mut self.renderer_errors); + } + SourceTexture::CacheA8 => { + self.shaders.cs_scale_a8.bind(&mut self.device, + &projection, + &mut self.renderer_errors); + } + _ => unreachable!(), } + + self.draw_instanced_batch( + &scalings, + VertexArrayKind::Scale, + &BatchTextures::no_texture(), + stats, + ); } fn draw_color_target( @@ -2954,7 +2991,7 @@ impl Renderer { } } - self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheRGBA8); + self.handle_scaling(&target.scalings, SourceTexture::CacheRGBA8, projection, stats); //TODO: record the pixel count for cached primitives @@ -3246,7 +3283,7 @@ impl Renderer { } } - self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheA8); + self.handle_scaling(&target.scalings, SourceTexture::CacheA8, projection, stats); // Draw the clip items into the tiled alpha mask. { @@ -4090,6 +4127,7 @@ impl Renderer { self.device.delete_vao(self.vaos.clip_vao); self.device.delete_vao(self.vaos.blur_vao); self.device.delete_vao(self.vaos.border_vao); + self.device.delete_vao(self.vaos.scale_vao); #[cfg(feature = "debug_renderer")] { @@ -4760,6 +4798,7 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind, VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao, VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao, VertexArrayKind::Border => &vaos.border_vao, + VertexArrayKind::Scale => &vaos.scale_vao, } } @@ -4774,6 +4813,7 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind, VertexArrayKind::Blur => &vaos.blur_vao, VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(), VertexArrayKind::Border => &vaos.border_vao, + VertexArrayKind::Scale => &vaos.scale_vao, } } diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 5d5700de82..abb230ccf9 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -369,6 +369,7 @@ fn create_prim_shader( VertexArrayKind::VectorStencil => desc::VECTOR_STENCIL, VertexArrayKind::VectorCover => desc::VECTOR_COVER, VertexArrayKind::Border => desc::BORDER, + VertexArrayKind::Scale => desc::SCALE, }; let program = device.create_program(name, &prefix, &vertex_descriptor); @@ -425,7 +426,8 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result, pub horizontal_blurs: Vec, pub readbacks: Vec, - pub scalings: Vec, + pub scalings: Vec, pub blits: Vec, // List of frame buffer outputs for this render target. pub outputs: Vec, @@ -447,9 +441,9 @@ impl RenderTarget for ColorRenderTarget { self.readbacks.push(device_rect); } RenderTaskKind::Scaling(..) => { - self.scalings.push(ScalingInfo { - src_task_id: task.children[0], - dest_task_id: task_id, + self.scalings.push(ScalingInstance { + task_address: render_tasks.get_task_address(task_id), + src_task_address: render_tasks.get_task_address(task.children[0]), }); } RenderTaskKind::Blit(ref task_info) => { @@ -519,7 +513,7 @@ pub struct AlphaRenderTarget { // List of blur operations to apply for this render target. pub vertical_blurs: Vec, pub horizontal_blurs: Vec, - pub scalings: Vec, + pub scalings: Vec, pub zero_clears: Vec, allocator: TextureAllocator, } @@ -610,11 +604,12 @@ impl RenderTarget for AlphaRenderTarget { task.clip_data_address, ); } - RenderTaskKind::Scaling(..) => { - self.scalings.push(ScalingInfo { - src_task_id: task.children[0], - dest_task_id: task_id, - }); + RenderTaskKind::Scaling(ref info) => { + info.add_instances( + &mut self.scalings, + render_tasks.get_task_address(task_id), + render_tasks.get_task_address(task.children[0]), + ); } } } @@ -1045,6 +1040,22 @@ impl BlurTask { } } +impl ScalingTask { + fn add_instances( + &self, + instances: &mut Vec, + task_address: RenderTaskAddress, + src_task_address: RenderTaskAddress, + ) { + let instance = ScalingInstance { + task_address, + src_task_address, + }; + + instances.push(instance); + } +} + pub struct SpecialRenderPasses { pub alpha_glyph_pass: RenderPass, pub color_glyph_pass: RenderPass, diff --git a/wrench/reftests/boxshadow/inset-border-radius.png b/wrench/reftests/boxshadow/inset-border-radius.png index f1980300f5..f2614d5fbc 100644 Binary files a/wrench/reftests/boxshadow/inset-border-radius.png and b/wrench/reftests/boxshadow/inset-border-radius.png differ diff --git a/wrench/reftests/filters/reftest.list b/wrench/reftests/filters/reftest.list index b70e18f945..04d98f11f9 100644 --- a/wrench/reftests/filters/reftest.list +++ b/wrench/reftests/filters/reftest.list @@ -1,5 +1,5 @@ == filter-grayscale.yaml filter-grayscale-ref.yaml -platform(linux,mac) == draw_calls(4) color_targets(5) alpha_targets(0) filter-blur.yaml filter-blur.png +platform(linux,mac) == draw_calls(6) color_targets(5) alpha_targets(0) filter-blur.yaml filter-blur.png == isolated.yaml isolated-ref.yaml == invisible.yaml invisible-ref.yaml color_targets(1) alpha_targets(0) == opacity.yaml opacity-ref.yaml diff --git a/wrench/reftests/snap/preserve-3d.png b/wrench/reftests/snap/preserve-3d.png index bdfcabb2b3..2fd522da4d 100644 Binary files a/wrench/reftests/snap/preserve-3d.png and b/wrench/reftests/snap/preserve-3d.png differ