From 318cbcf9759e12998889b7605774eb6223d4c5a7 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Thu, 19 Jan 2017 09:40:36 +1000 Subject: [PATCH 1/2] Remove the tiling code, now that we have solutions for all the parts of the renderer that previously relied on tiling for efficiency. --- webrender/res/prim_shared.glsl | 70 +- webrender/res/ps_angle_gradient.vs.glsl | 4 +- webrender/res/ps_blend.vs.glsl | 44 +- webrender/res/ps_border.vs.glsl | 14 +- webrender/res/ps_box_shadow.vs.glsl | 4 +- webrender/res/ps_cache_image.vs.glsl | 4 +- webrender/res/ps_composite.fs.glsl | 9 - webrender/res/ps_composite.glsl | 1 - webrender/res/ps_composite.vs.glsl | 60 +- webrender/res/ps_gradient.vs.glsl | 10 +- webrender/res/ps_image.vs.glsl | 8 +- webrender/res/ps_radial_gradient.vs.glsl | 4 +- webrender/res/ps_rectangle.vs.glsl | 6 +- webrender/res/ps_text_run.vs.glsl | 8 +- webrender/res/ps_yuv_image.vs.glsl | 8 +- webrender/src/device.rs | 24 +- webrender/src/prim_store.rs | 4 - webrender/src/renderer.rs | 277 +++-- webrender/src/tiling.rs | 1390 ++++++++-------------- webrender/src/util.rs | 11 +- 20 files changed, 791 insertions(+), 1169 deletions(-) diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 1d9e8a95e6..b604388ebb 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -146,19 +146,23 @@ RenderTaskData fetch_render_task(int index) { return task; } -struct Tile { - vec4 screen_origin_task_origin; - vec4 size_target_index; +struct AlphaBatchTask { + vec2 screen_space_origin; + vec2 render_target_origin; + vec2 size; + float render_target_layer_index; }; -Tile fetch_tile(int index) { - RenderTaskData task = fetch_render_task(index); +AlphaBatchTask fetch_alpha_batch_task(int index) { + RenderTaskData data = fetch_render_task(index); - Tile tile; - tile.screen_origin_task_origin = task.data0; - tile.size_target_index = task.data1; + AlphaBatchTask task; + task.render_target_origin = data.data0.xy; + task.size = data.data0.zw; + task.screen_space_origin = data.data1.xy; + task.render_target_layer_index = data.data1.z; - return tile; + return task; } struct ClipArea { @@ -320,8 +324,8 @@ CachePrimitiveInstance fetch_cache_instance() { struct Primitive { Layer layer; - Tile tile; ClipArea clip_area; + AlphaBatchTask task; vec4 local_rect; vec4 local_clip_rect; int prim_index; @@ -336,8 +340,8 @@ Primitive load_primitive_custom(PrimitiveInstance pi) { Primitive prim; prim.layer = fetch_layer(pi.layer_index); - prim.tile = fetch_tile(pi.render_task_index); prim.clip_area = fetch_clip_area(pi.clip_task_index); + prim.task = fetch_alpha_batch_task(pi.render_task_index); PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index); prim.local_rect = pg.local_rect; @@ -413,15 +417,15 @@ struct Rect { struct VertexInfo { Rect local_rect; - vec2 local_clamped_pos; - vec2 global_clamped_pos; + vec2 local_pos; + vec2 screen_pos; }; VertexInfo write_vertex(vec4 instance_rect, vec4 local_clip_rect, float z, Layer layer, - Tile tile) { + AlphaBatchTask task) { vec2 p0 = floor(0.5 + instance_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; vec2 p1 = floor(0.5 + (instance_rect.xy + instance_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; @@ -438,18 +442,11 @@ VertexInfo write_vertex(vec4 instance_rect, vec2 device_pos = world_pos.xy * uDevicePixelRatio; - vec2 clamped_pos = clamp(device_pos, - tile.screen_origin_task_origin.xy, - tile.screen_origin_task_origin.xy + tile.size_target_index.xy); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1); - local_clamped_pos.xyz /= local_clamped_pos.w; - - vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy; + vec2 final_pos = device_pos - task.screen_space_origin + task.render_target_origin; gl_Position = uTransform * vec4(final_pos, z, 1.0); - VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy); + VertexInfo vi = VertexInfo(Rect(p0, p1), local_pos.xy, device_pos.xy); return vi; } @@ -457,7 +454,7 @@ VertexInfo write_vertex(vec4 instance_rect, struct TransformVertexInfo { vec3 local_pos; - vec2 global_clamped_pos; + vec2 screen_pos; vec4 clipped_local_rect; }; @@ -465,7 +462,7 @@ TransformVertexInfo write_transform_vertex(vec4 instance_rect, vec4 local_clip_rect, float z, Layer layer, - Tile tile) { + AlphaBatchTask task) { vec2 lp0_base = instance_rect.xy; vec2 lp1_base = instance_rect.xy + instance_rect.zw; @@ -492,32 +489,21 @@ TransformVertexInfo write_transform_vertex(vec4 instance_rect, vec2 tp3 = t3.xy / t3.w; // compute a CSS space aligned bounding box - vec2 min_pos = min(min(tp0.xy, tp1.xy), min(tp2.xy, tp3.xy)); - vec2 max_pos = max(max(tp0.xy, tp1.xy), max(tp2.xy, tp3.xy)); - - // clamp to the tile boundaries, in device space - vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, - tile.screen_origin_task_origin.xy, - tile.screen_origin_task_origin.xy + tile.size_target_index.xy); - - vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, - tile.screen_origin_task_origin.xy, - tile.screen_origin_task_origin.xy + tile.size_target_index.xy); + vec2 min_pos = uDevicePixelRatio * min(min(tp0.xy, tp1.xy), min(tp2.xy, tp3.xy)); + vec2 max_pos = uDevicePixelRatio * max(max(tp0.xy, tp1.xy), max(tp2.xy, tp3.xy)); // compute the device space position of this vertex - vec2 clamped_pos = mix(min_pos_clamped, - max_pos_clamped, - aPosition.xy); + vec2 device_pos = mix(min_pos, max_pos, aPosition.xy); // compute the point position in side the layer, in CSS space - vec4 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, layer); + vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer); // apply the task offset - vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy; + vec2 final_pos = device_pos - task.screen_space_origin + task.render_target_origin; gl_Position = uTransform * vec4(final_pos, z, 1.0); - return TransformVertexInfo(layer_pos.xyw, clamped_pos, clipped_local_rect); + return TransformVertexInfo(layer_pos.xyw, device_pos, clipped_local_rect); } #endif //WR_FEATURE_TRANSFORM diff --git a/webrender/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl index 53c39ec441..bdafc88b80 100644 --- a/webrender/res/ps_angle_gradient.vs.glsl +++ b/webrender/res/ps_angle_gradient.vs.glsl @@ -11,10 +11,10 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vStopCount = int(prim.user_data.x); - vPos = vi.local_clamped_pos; + vPos = vi.local_pos; // Snap the start/end points to device pixel units. // I'm not sure this is entirely correct, but the diff --git a/webrender/res/ps_blend.vs.glsl b/webrender/res/ps_blend.vs.glsl index 30960d8402..cf155e1b74 100644 --- a/webrender/res/ps_blend.vs.glsl +++ b/webrender/res/ps_blend.vs.glsl @@ -3,44 +3,26 @@ * 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/. */ -struct Blend { - ivec4 src_id_target_id_op_amount; - int z; -}; - -Blend fetch_blend() { - PrimitiveInstance pi = fetch_prim_instance(); - - Blend blend; - blend.src_id_target_id_op_amount = ivec4(pi.user_data.x, - pi.render_task_index, - pi.sub_index, - pi.user_data.y); - blend.z = pi.z; - - return blend; -} - void main(void) { - Blend blend = fetch_blend(); - Tile src = fetch_tile(blend.src_id_target_id_op_amount.x); - Tile dest = fetch_tile(blend.src_id_target_id_op_amount.y); + PrimitiveInstance pi = fetch_prim_instance(); + AlphaBatchTask dest_task = fetch_alpha_batch_task(pi.render_task_index); + AlphaBatchTask src_task = fetch_alpha_batch_task(pi.user_data.x); - vec2 dest_origin = dest.screen_origin_task_origin.zw - - dest.screen_origin_task_origin.xy + - src.screen_origin_task_origin.xy; + vec2 dest_origin = dest_task.render_target_origin - + dest_task.screen_space_origin + + src_task.screen_space_origin; vec2 local_pos = mix(dest_origin, - dest_origin + src.size_target_index.xy, + dest_origin + src_task.size, aPosition.xy); vec2 texture_size = vec2(textureSize(sCache, 0)); - vec2 st0 = src.screen_origin_task_origin.zw / texture_size; - vec2 st1 = (src.screen_origin_task_origin.zw + src.size_target_index.xy) / texture_size; - vUv = vec3(mix(st0, st1, aPosition.xy), src.size_target_index.z); + vec2 st0 = src_task.render_target_origin / texture_size; + vec2 st1 = (src_task.render_target_origin + src_task.size) / texture_size; + vUv = vec3(mix(st0, st1, aPosition.xy), src_task.render_target_layer_index); - vOp = blend.src_id_target_id_op_amount.z; - vAmount = float(blend.src_id_target_id_op_amount.w) / 65535.0; + vOp = pi.sub_index; + vAmount = float(pi.user_data.y) / 65535.0; - gl_Position = uTransform * vec4(local_pos, blend.z, 1.0); + gl_Position = uTransform * vec4(local_pos, pi.z, 1.0); } diff --git a/webrender/res/ps_border.vs.glsl b/webrender/res/ps_border.vs.glsl index 2d60f8dc5e..78f3578e60 100644 --- a/webrender/res/ps_border.vs.glsl +++ b/webrender/res/ps_border.vs.glsl @@ -138,7 +138,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalPos = vi.local_pos; // Local space @@ -148,8 +148,8 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); - vLocalPos = vi.local_clamped_pos.xy; + prim.task); + vLocalPos = vi.local_pos.xy; // Local space vLocalRect = prim.local_rect; @@ -217,10 +217,10 @@ void main(void) { #ifdef WR_FEATURE_TRANSFORM vPieceRectHypotenuseLength = sqrt(pow(width, 2.0) + pow(height, 2.0)); #else - vDistanceFromMixLine = (vi.local_clamped_pos.x - x0) * height - - (vi.local_clamped_pos.y - y0) * width; - vDistanceFromMiddle = (vi.local_clamped_pos.x - vLocalRect.x) + - (vi.local_clamped_pos.y - vLocalRect.y) - + vDistanceFromMixLine = (vi.local_pos.x - x0) * height - + (vi.local_pos.y - y0) * width; + vDistanceFromMiddle = (vi.local_pos.x - vLocalRect.x) + + (vi.local_pos.y - vLocalRect.y) - 0.5 * (vLocalRect.z + vLocalRect.w); #endif } diff --git a/webrender/res/ps_box_shadow.vs.glsl b/webrender/res/ps_box_shadow.vs.glsl index 47cfae5174..84b29ab3af 100644 --- a/webrender/res/ps_box_shadow.vs.glsl +++ b/webrender/res/ps_box_shadow.vs.glsl @@ -12,7 +12,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); RenderTaskData child_task = fetch_render_task(prim.user_data.x); vUv.z = child_task.data1.x; @@ -22,7 +22,7 @@ void main(void) { vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0); vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio; - vUv.xy = (vi.local_clamped_pos - prim.local_rect.xy) / patch_size; + vUv.xy = (vi.local_pos - prim.local_rect.xy) / patch_size; vMirrorPoint = 0.5 * prim.local_rect.zw / patch_size; vec2 texture_size = vec2(textureSize(sCache, 0)); diff --git a/webrender/res/ps_cache_image.vs.glsl b/webrender/res/ps_cache_image.vs.glsl index 84701b842d..35c7b2236d 100644 --- a/webrender/res/ps_cache_image.vs.glsl +++ b/webrender/res/ps_cache_image.vs.glsl @@ -13,7 +13,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); RenderTaskData child_task = fetch_render_task(prim.user_data.x); vUv.z = child_task.data1.x; @@ -22,7 +22,7 @@ void main(void) { vec2 uv0 = child_task.data0.xy / texture_size; vec2 uv1 = (child_task.data0.xy + child_task.data0.zw) / texture_size; - vec2 f = (vi.local_clamped_pos - prim.local_rect.xy) / prim.local_rect.zw; + vec2 f = (vi.local_pos - prim.local_rect.xy) / prim.local_rect.zw; vUv.xy = mix(uv0, uv1, f); } diff --git a/webrender/res/ps_composite.fs.glsl b/webrender/res/ps_composite.fs.glsl index 0384d1070e..3b747e18d5 100644 --- a/webrender/res/ps_composite.fs.glsl +++ b/webrender/res/ps_composite.fs.glsl @@ -153,15 +153,6 @@ vec3 Luminosity(vec3 Cb, vec3 Cs) { void main(void) { vec4 Cb = texture(sCache, vUv0); - - if (vUv1.x < vUv1Rect.x || - vUv1.x > vUv1Rect.z || - vUv1.y < vUv1Rect.y || - vUv1.y > vUv1Rect.w) { - oFragColor = Cb; - return; - } - vec4 Cs = texture(sCache, vUv1); // Return yellow if none of the branches match (shouldn't happen). diff --git a/webrender/res/ps_composite.glsl b/webrender/res/ps_composite.glsl index d2a1310d59..378e76eaf4 100644 --- a/webrender/res/ps_composite.glsl +++ b/webrender/res/ps_composite.glsl @@ -4,5 +4,4 @@ varying vec3 vUv0; varying vec3 vUv1; -flat varying vec4 vUv1Rect; flat varying int vOp; diff --git a/webrender/res/ps_composite.vs.glsl b/webrender/res/ps_composite.vs.glsl index 4486f53d17..7e85129ae6 100644 --- a/webrender/res/ps_composite.vs.glsl +++ b/webrender/res/ps_composite.vs.glsl @@ -3,48 +3,32 @@ * 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/. */ -struct Composite { - ivec4 src0_src1_target_id_op; - int z; -}; - -Composite fetch_composite() { +void main(void) { PrimitiveInstance pi = fetch_prim_instance(); + AlphaBatchTask dest_task = fetch_alpha_batch_task(pi.render_task_index); + AlphaBatchTask backdrop_task = fetch_alpha_batch_task(pi.user_data.x); + AlphaBatchTask src_task = fetch_alpha_batch_task(pi.user_data.y); - Composite composite; - composite.src0_src1_target_id_op = ivec4(pi.user_data.xy, - pi.render_task_index, - pi.sub_index); - composite.z = pi.z; - - return composite; -} - -void main(void) { - Composite composite = fetch_composite(); - Tile src0 = fetch_tile(composite.src0_src1_target_id_op.x); - Tile src1 = fetch_tile(composite.src0_src1_target_id_op.y); - Tile dest = fetch_tile(composite.src0_src1_target_id_op.z); + vec2 dest_origin = dest_task.render_target_origin - + dest_task.screen_space_origin + + src_task.screen_space_origin; - vec2 local_pos = mix(dest.screen_origin_task_origin.zw, - dest.screen_origin_task_origin.zw + dest.size_target_index.xy, + vec2 local_pos = mix(dest_origin, + dest_origin + src_task.size, aPosition.xy); vec2 texture_size = vec2(textureSize(sCache, 0)); - vec2 st0 = src0.screen_origin_task_origin.zw / texture_size; - vec2 st1 = (src0.screen_origin_task_origin.zw + src0.size_target_index.xy) / texture_size; - vUv0 = vec3(mix(st0, st1, aPosition.xy), src0.size_target_index.z); - - st0 = vec2(src1.screen_origin_task_origin.zw) / texture_size; - st1 = vec2(src1.screen_origin_task_origin.zw + src1.size_target_index.xy) / texture_size; - vec2 local_virtual_pos = mix(dest.screen_origin_task_origin.xy, - dest.screen_origin_task_origin.xy + dest.size_target_index.xy, - aPosition.xy); - vec2 f = (local_virtual_pos - src1.screen_origin_task_origin.xy) / src1.size_target_index.xy; - vUv1 = vec3(mix(st0, st1, f), src1.size_target_index.z); - vUv1Rect = vec4(st0, st1); - - vOp = composite.src0_src1_target_id_op.w; - - gl_Position = uTransform * vec4(local_pos, composite.z, 1.0); + + vec2 st0 = (backdrop_task.render_target_origin + vec2(0.0, backdrop_task.size.y)) / texture_size; + vec2 st1 = (backdrop_task.render_target_origin + vec2(backdrop_task.size.x, 0.0)) / texture_size; + vUv0 = vec3(mix(st0, st1, aPosition.xy), backdrop_task.render_target_layer_index); + + st0 = src_task.render_target_origin / texture_size; + st1 = (src_task.render_target_origin + src_task.size) / texture_size; + vUv1 = vec3(mix(st0, st1, aPosition.xy), src_task.render_target_layer_index); + + vOp = pi.sub_index; + + gl_Position = uTransform * vec4(local_pos, pi.z, 1.0); + } diff --git a/webrender/res/ps_gradient.vs.glsl b/webrender/res/ps_gradient.vs.glsl index 9bf70401e2..5528b0823b 100644 --- a/webrender/res/ps_gradient.vs.glsl +++ b/webrender/res/ps_gradient.vs.glsl @@ -41,7 +41,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw; @@ -50,13 +50,13 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); - vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw; - vPos = vi.local_clamped_pos; + vec2 f = (vi.local_pos - segment_rect.xy) / segment_rect.zw; + vPos = vi.local_pos; #endif - write_clip(vi.global_clamped_pos, prim.clip_area); + write_clip(vi.screen_pos, prim.clip_area); switch (int(gradient.kind.x)) { case GRADIENT_HORIZONTAL: diff --git a/webrender/res/ps_image.vs.glsl b/webrender/res/ps_image.vs.glsl index d930ab1443..bac236cb22 100644 --- a/webrender/res/ps_image.vs.glsl +++ b/webrender/res/ps_image.vs.glsl @@ -13,7 +13,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; #else @@ -21,11 +21,11 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); - vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; + prim.task); + vLocalPos = vi.local_pos - vi.local_rect.p0; #endif - write_clip(vi.global_clamped_pos, prim.clip_area); + write_clip(vi.screen_pos, prim.clip_area); // vUv will contain how many times this image has wrapped around the image size. vec2 texture_size = vec2(textureSize(sColor0, 0)); diff --git a/webrender/res/ps_radial_gradient.vs.glsl b/webrender/res/ps_radial_gradient.vs.glsl index d571bdfbdf..22dbfe2f5b 100644 --- a/webrender/res/ps_radial_gradient.vs.glsl +++ b/webrender/res/ps_radial_gradient.vs.glsl @@ -11,10 +11,10 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vStopCount = int(prim.user_data.x); - vPos = vi.local_clamped_pos; + vPos = vi.local_pos; // Snap the start/end points to device pixel units. // I'm not sure this is entirely correct, but the diff --git a/webrender/res/ps_rectangle.vs.glsl b/webrender/res/ps_rectangle.vs.glsl index 298a1bd07f..c706fbbe5d 100644 --- a/webrender/res/ps_rectangle.vs.glsl +++ b/webrender/res/ps_rectangle.vs.glsl @@ -12,7 +12,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; #else @@ -20,10 +20,10 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); #endif #ifdef WR_FEATURE_CLIP - write_clip(vi.global_clamped_pos, prim.clip_area); + write_clip(vi.screen_pos, prim.clip_area); #endif } diff --git a/webrender/res/ps_text_run.vs.glsl b/webrender/res/ps_text_run.vs.glsl index 0a41740075..31bbb1c338 100644 --- a/webrender/res/ps_text_run.vs.glsl +++ b/webrender/res/ps_text_run.vs.glsl @@ -16,7 +16,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.xy) / local_rect.zw; @@ -25,11 +25,11 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); - vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0); + prim.task); + vec2 f = (vi.local_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0); #endif - write_clip(vi.global_clamped_pos, prim.clip_area); + write_clip(vi.screen_pos, prim.clip_area); vec2 texture_size = vec2(textureSize(sColor0, 0)); vec2 st0 = res.uv_rect.xy / texture_size; diff --git a/webrender/res/ps_yuv_image.vs.glsl b/webrender/res/ps_yuv_image.vs.glsl index 1163f3bbfd..382e8bbbae 100644 --- a/webrender/res/ps_yuv_image.vs.glsl +++ b/webrender/res/ps_yuv_image.vs.glsl @@ -10,7 +10,7 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); + prim.task); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; #else @@ -18,8 +18,8 @@ void main(void) { prim.local_clip_rect, prim.z, prim.layer, - prim.tile); - vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; + prim.task); + vLocalPos = vi.local_pos - vi.local_rect.p0; #endif YuvImage image = fetch_yuv_image(prim.prim_index); @@ -72,6 +72,6 @@ void main(void) { ); } - write_clip(vi.global_clamped_pos, prim.clip_area); + write_clip(vi.screen_pos, prim.clip_area); } diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 74880e40ed..ea0807404d 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -19,7 +19,7 @@ use std::path::PathBuf; //use std::sync::mpsc::{channel, Sender}; //use std::thread; use webrender_traits::{ColorF, ImageFormat}; -use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; +use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize}; #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] const GL_FORMAT_A: gl::GLuint = gl::RED; @@ -41,8 +41,6 @@ const SHADER_VERSION: &'static str = "#version 300 es\n"; static SHADER_PREAMBLE: &'static str = "shared"; -pub type ViewportDimensions = [u32; 2]; - lazy_static! { pub static ref MAX_TEXTURE_SIZE: gl::GLint = { gl::get_integer_v(gl::MAX_TEXTURE_SIZE) @@ -959,7 +957,7 @@ impl Device { pub fn bind_draw_target(&mut self, texture_id: Option<(TextureId, i32)>, - dimensions: Option) { + dimensions: Option) { debug_assert!(self.inside_frame); let fbo_id = texture_id.map_or(FBOId(self.default_draw_fbo), |texture_id| { @@ -972,7 +970,7 @@ impl Device { } if let Some(dimensions) = dimensions { - gl::viewport(0, 0, dimensions[0] as gl::GLint, dimensions[1] as gl::GLint); + gl::viewport(0, 0, dimensions.width as gl::GLint, dimensions.height as gl::GLint); } } @@ -1028,9 +1026,9 @@ impl Device { texture_ids } - pub fn get_texture_dimensions(&self, texture_id: TextureId) -> (u32, u32) { + pub fn get_texture_dimensions(&self, texture_id: TextureId) -> DeviceUintSize { let texture = &self.textures[&texture_id]; - (texture.width, texture.height) + DeviceUintSize::new(texture.width, texture.height) } fn set_texture_parameters(&mut self, target: gl::GLuint, filter: TextureFilter) { @@ -1244,10 +1242,10 @@ impl Device { mode: RenderTargetMode) { debug_assert!(self.inside_frame); - let (old_width, old_height) = self.get_texture_dimensions(texture_id); + let old_size = self.get_texture_dimensions(texture_id); let temp_texture_id = self.create_texture_ids(1, TextureTarget::Default)[0]; - self.init_texture(temp_texture_id, old_width, old_height, format, filter, mode, None); + self.init_texture(temp_texture_id, old_size.width, old_size.height, format, filter, mode, None); self.create_fbo_for_texture_if_necessary(temp_texture_id, None); self.bind_read_target(Some((texture_id, 0))); @@ -1259,8 +1257,8 @@ impl Device { 0, 0, 0, - old_width as i32, - old_height as i32); + old_size.width as i32, + old_size.height as i32); self.deinit_texture(texture_id); self.init_texture(texture_id, new_width, new_height, format, filter, mode, None); @@ -1274,8 +1272,8 @@ impl Device { 0, 0, 0, - old_width as i32, - old_height as i32); + old_size.width as i32, + old_size.height as i32); self.bind_read_target(None); self.deinit_texture(temp_texture_id); diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index c9cf57e3ae..a6ce4b82b2 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -822,10 +822,6 @@ impl PrimitiveStore { deferred_resolves } - pub fn get_bounding_rect(&self, index: PrimitiveIndex) -> &Option { - &self.cpu_bounding_rects[index.0] - } - pub fn set_clip_source(&mut self, index: PrimitiveIndex, source: ClipSource) { let metadata = &mut self.cpu_metadata[index.0]; let (rect, is_complex) = match source { diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 4dabf2621a..321451f0c4 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -32,8 +32,8 @@ use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use texture_cache::TextureCache; -use tiling::{Frame, FrameBuilderConfig, PrimitiveBatch, PrimitiveBatchData}; -use tiling::{BlurCommand, CacheClipInstance, PrimitiveInstance, RenderTarget}; +use tiling::{AlphaBatchKind, Frame, FrameBuilderConfig, PrimitiveBatch, PrimitiveBatchData}; +use tiling::{BlurCommand, CacheClipInstance, PrimitiveInstance, RenderTarget, RenderTaskData}; use time::precise_time_ns; use util::TransformedRectKind; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher}; @@ -935,48 +935,6 @@ impl Renderer { } } - fn add_debug_rect(&mut self, - p0: DeviceIntPoint, - p1: DeviceIntPoint, - label: &str, - c: &ColorF) { - let tile_x0 = p0.x; - let tile_y0 = p0.y; - let tile_x1 = p1.x; - let tile_y1 = p1.y; - - self.debug.add_line(tile_x0, - tile_y0, - c, - tile_x1, - tile_y0, - c); - self.debug.add_line(tile_x0, - tile_y1, - c, - tile_x1, - tile_y1, - c); - self.debug.add_line(tile_x0, - tile_y0, - c, - tile_x0, - tile_y1, - c); - self.debug.add_line(tile_x1, - tile_y0, - c, - tile_x1, - tile_y1, - c); - if label.len() > 0 { - self.debug.add_text((tile_x0 as f32 + tile_x1 as f32) * 0.5, - (tile_y0 as f32 + tile_y1 as f32) * 0.5, - label, - c); - } - } - fn draw_instanced_batch(&mut self, data: &[T], vao: VAOId, @@ -999,93 +957,163 @@ impl Renderer { fn submit_batch(&mut self, batch: &PrimitiveBatch, - projection: &Matrix4D) { + projection: &Matrix4D, + render_task_data: &Vec, + cache_texture: Option, + render_target: Option<(TextureId, i32)>, + target_dimensions: DeviceUintSize) { let transform_kind = batch.key.flags.transform_kind(); let needs_clipping = batch.key.flags.needs_clipping(); debug_assert!(!needs_clipping || batch.key.blend_mode == BlendMode::Alpha); - let (data, marker, shader) = match &batch.data { - &PrimitiveBatchData::CacheImage(ref data) => { - let shader = self.ps_cache_image.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_CACHE_IMAGE, shader) - } - &PrimitiveBatchData::Blend(ref data) => { - let shader = self.ps_blend.get(&mut self.device); - (data, GPU_TAG_PRIM_BLEND, shader) + match batch.data { + PrimitiveBatchData::Instances(ref data) => { + let (marker, shader) = match batch.key.kind { + AlphaBatchKind::Composite => unreachable!(), + AlphaBatchKind::Blend => { + let shader = self.ps_blend.get(&mut self.device); + (GPU_TAG_PRIM_BLEND, shader) + } + AlphaBatchKind::Rectangle => { + let shader = if needs_clipping { + self.ps_rectangle_clip.get(&mut self.device, transform_kind) + } else { + self.ps_rectangle.get(&mut self.device, transform_kind) + }; + (GPU_TAG_PRIM_RECT, shader) + } + AlphaBatchKind::TextRun => { + let shader = match batch.key.blend_mode { + BlendMode::Subpixel(..) => self.ps_text_run_subpixel.get(&mut self.device, transform_kind), + BlendMode::Alpha | BlendMode::None => self.ps_text_run.get(&mut self.device, transform_kind), + }; + (GPU_TAG_PRIM_TEXT_RUN, shader) + } + AlphaBatchKind::Image => { + let shader = self.ps_image.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_IMAGE, shader) + } + AlphaBatchKind::YuvImage => { + let shader = self.ps_yuv_image.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_YUV_IMAGE, shader) + } + AlphaBatchKind::Border => { + let shader = self.ps_border.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_BORDER, shader) + } + AlphaBatchKind::AlignedGradient => { + let shader = self.ps_gradient.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_GRADIENT, shader) + } + AlphaBatchKind::AngleGradient => { + let shader = self.ps_angle_gradient.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_ANGLE_GRADIENT, shader) + } + AlphaBatchKind::RadialGradient => { + let shader = self.ps_radial_gradient.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_RADIAL_GRADIENT, shader) + } + AlphaBatchKind::BoxShadow => { + let shader = self.ps_box_shadow.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_BOX_SHADOW, shader) + } + AlphaBatchKind::CacheImage => { + let shader = self.ps_cache_image.get(&mut self.device, transform_kind); + (GPU_TAG_PRIM_CACHE_IMAGE, shader) + } + }; + + let _gm = self.gpu_profile.add_marker(marker); + let vao = self.prim_vao_id; + self.draw_instanced_batch(data, + vao, + shader, + &batch.key.textures, + projection); } - &PrimitiveBatchData::Composite(ref data) => { - // The composite shader only samples from sCache. + PrimitiveBatchData::Composite(ref instance) => { + let _gm = self.gpu_profile.add_marker(GPU_TAG_PRIM_COMPOSITE); + let vao = self.prim_vao_id; let shader = self.ps_composite.get(&mut self.device); - (data, GPU_TAG_PRIM_COMPOSITE, shader) - } - &PrimitiveBatchData::Rectangles(ref data) => { - let shader = if needs_clipping { - self.ps_rectangle_clip.get(&mut self.device, transform_kind) + + // TODO(gw): This code branch is all a bit hacky. We rely + // on pulling specific values from the render target data + // and also cloning the single primitive instance to be + // able to pass to draw_instanced_batch(). We should + // think about a cleaner way to achieve this! + + // Before submitting the composite batch, do the + // framebuffer readbacks that are needed for each + // composite operation in this batch. + let cache_texture_id = cache_texture.unwrap(); + let cache_texture_dimensions = self.device.get_texture_dimensions(cache_texture_id); + + let backdrop = &render_task_data[instance.task_index as usize]; + let readback = &render_task_data[instance.user_data[0] as usize]; + let source = &render_task_data[instance.user_data[1] as usize]; + + // Bind the FBO to blit the backdrop to. + // Called per-instance in case the layer (and therefore FBO) + // changes. The device will skip the GL call if the requested + // target is already bound. + let cache_draw_target = (cache_texture_id, readback.data[4] as i32); + self.device.bind_draw_target(Some(cache_draw_target), Some(cache_texture_dimensions)); + + let src_x = backdrop.data[0] - backdrop.data[4] + source.data[4]; + let src_y = backdrop.data[1] - backdrop.data[5] + source.data[5]; + + let dest_x = readback.data[0]; + let dest_y = readback.data[1]; + + let width = readback.data[2]; + let height = readback.data[3]; + + // Need to invert the y coordinates when reading back from + // the framebuffer. + let y0 = if render_target.is_some() { + src_y as i32 } else { - self.ps_rectangle.get(&mut self.device, transform_kind) + target_dimensions.height as i32 - height as i32 - src_y as i32 }; - (data, GPU_TAG_PRIM_RECT, shader) - } - &PrimitiveBatchData::Image(ref data) => { - let shader = self.ps_image.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_IMAGE, shader) - } - &PrimitiveBatchData::YuvImage(ref data) => { - let shader = self.ps_yuv_image.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_YUV_IMAGE, shader) - } - &PrimitiveBatchData::Borders(ref data) => { - let shader = self.ps_border.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_BORDER, shader) - } - &PrimitiveBatchData::BoxShadow(ref data) => { - let shader = self.ps_box_shadow.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_BOX_SHADOW, shader) - } - &PrimitiveBatchData::TextRun(ref data) => { - let shader = match batch.key.blend_mode { - BlendMode::Subpixel(..) => self.ps_text_run_subpixel.get(&mut self.device, transform_kind), - BlendMode::Alpha | BlendMode::None => self.ps_text_run.get(&mut self.device, transform_kind), - }; - (data, GPU_TAG_PRIM_TEXT_RUN, shader) - } - &PrimitiveBatchData::AlignedGradient(ref data) => { - let shader = self.ps_gradient.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_GRADIENT, shader) - } - &PrimitiveBatchData::AngleGradient(ref data) => { - let shader = self.ps_angle_gradient.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_ANGLE_GRADIENT, shader) - } - &PrimitiveBatchData::RadialGradient(ref data) => { - let shader = self.ps_radial_gradient.get(&mut self.device, transform_kind); - (data, GPU_TAG_PRIM_RADIAL_GRADIENT, shader) - } - }; - let _gm = self.gpu_profile.add_marker(marker); - let vao = self.prim_vao_id; - self.draw_instanced_batch(data, - vao, - shader, - &batch.key.textures, - projection); + let src = DeviceIntRect::new(DeviceIntPoint::new(src_x as i32, + y0), + DeviceIntSize::new(width as i32, height as i32)); + let dest = DeviceIntRect::new(DeviceIntPoint::new(dest_x as i32, + dest_y as i32), + DeviceIntSize::new(width as i32, height as i32)); + + self.device.blit_render_target(render_target, + Some(src), + dest); + + // Restore draw target to current pass render target + layer. + self.device.bind_draw_target(render_target, Some(target_dimensions)); + + self.draw_instanced_batch(&[instance.clone()], + vao, + shader, + &batch.key.textures, + projection); + } + } } fn draw_target(&mut self, render_target: Option<(TextureId, i32)>, target: &RenderTarget, - target_size: &DeviceUintSize, + target_size: DeviceUintSize, cache_texture: Option, should_clear: bool, - background_color: Option) { + background_color: Option, + render_task_data: &Vec) { self.device.disable_depth(); self.device.enable_depth_write(); - let dimensions = [target_size.width, target_size.height]; let projection = { let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET); - self.device.bind_draw_target(render_target, Some(dimensions)); + self.device.bind_read_target(render_target); + self.device.bind_draw_target(render_target, Some(target_size)); self.device.set_blend(false); self.device.set_blend_mode_alpha(); @@ -1238,7 +1266,12 @@ impl Renderer { self.device.enable_depth_write(); for batch in &target.alpha_batcher.opaque_batches { - self.submit_batch(batch, &projection); + self.submit_batch(batch, + &projection, + render_task_data, + cache_texture, + render_target, + target_size); } self.device.disable_depth_write(); @@ -1261,7 +1294,12 @@ impl Renderer { prev_blend_mode = batch.key.blend_mode; } - self.submit_batch(batch, &projection); + self.submit_batch(batch, + &projection, + render_task_data, + cache_texture, + render_target, + target_size); } self.device.disable_depth(); @@ -1336,16 +1374,6 @@ impl Renderer { let needs_clear = viewport_size.width < framebuffer_size.width as i32 || viewport_size.height < framebuffer_size.height as i32; - { - let _gm2 = GpuMarker::new("debug rectangles"); - for debug_rect in frame.debug_rects.iter().rev() { - self.add_debug_rect(debug_rect.rect.origin, - debug_rect.rect.bottom_right(), - &debug_rect.label, - &debug_rect.color); - } - } - self.device.disable_depth_write(); self.device.disable_stencil(); self.device.set_blend(false); @@ -1398,10 +1426,11 @@ impl Renderer { }); self.draw_target(render_target, target, - size, + *size, src_id, do_clear, - frame.background_color); + frame.background_color, + &frame.render_task_data); } diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 56f085adde..8e34c3603f 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -28,10 +28,9 @@ use std::collections::{HashMap}; use std::{i32, f32}; use std::mem; use std::hash::{BuildHasherDefault}; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::usize; use texture_cache::TexturePage; -use util::{self, rect_from_points, rect_from_points_f}; +use util::{self, rect_from_points_f}; use util::{TransformedRect, TransformedRectKind, subtract_rect, pack_as_float}; use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, MixBlendMode}; use webrender_traits::{BorderDisplayItem, BorderSide, BorderStyle, YuvColorSpace}; @@ -57,11 +56,6 @@ trait AlphaBatchHelpers { fn get_batch_kind(&self, metadata: &PrimitiveMetadata) -> AlphaBatchKind; fn get_color_textures(&self, metadata: &PrimitiveMetadata) -> [SourceTexture; 3]; fn get_blend_mode(&self, needs_blending: bool, metadata: &PrimitiveMetadata) -> BlendMode; - fn prim_affects_tile(&self, - prim_index: PrimitiveIndex, - tile_rect: &DeviceIntRect, - transform: &LayerToWorldTransform, - device_pixel_ratio: f32) -> bool; fn add_prim_to_batch(&self, prim_index: PrimitiveIndex, batch: &mut PrimitiveBatch, @@ -70,6 +64,13 @@ trait AlphaBatchHelpers { render_tasks: &RenderTaskCollection, pass_index: RenderPassIndex, z_sort_index: i32); + fn add_blend_to_batch(&self, + layer_index: StackingContextIndex, + batch: &mut PrimitiveBatch, + task_index: RenderTaskIndex, + src_task_index: RenderTaskIndex, + filter: LowLevelFilterOp, + z_sort_index: i32); } impl AlphaBatchHelpers for PrimitiveStore { @@ -155,29 +156,43 @@ impl AlphaBatchHelpers for PrimitiveStore { } } - // Optional narrow phase intersection test, depending on primitive type. - fn prim_affects_tile(&self, - prim_index: PrimitiveIndex, - tile_rect: &DeviceIntRect, - transform: &LayerToWorldTransform, - device_pixel_ratio: f32) -> bool { - let metadata = self.get_metadata(prim_index); - match metadata.prim_kind { - PrimitiveKind::Rectangle | - PrimitiveKind::TextRun | - PrimitiveKind::Image | - PrimitiveKind::YuvImage | - PrimitiveKind::Gradient | - PrimitiveKind::RadialGradient | - PrimitiveKind::BoxShadow => true, - PrimitiveKind::Border => { - let border = &self.cpu_borders[metadata.cpu_prim_index.0]; - let inner_rect = TransformedRect::new(&border.inner_rect, - transform, - device_pixel_ratio); - - !inner_rect.bounding_rect.contains_rect(tile_rect) + fn add_blend_to_batch(&self, + layer_index: StackingContextIndex, + batch: &mut PrimitiveBatch, + task_index: RenderTaskIndex, + src_task_index: RenderTaskIndex, + filter: LowLevelFilterOp, + z_sort_index: i32) { + let (filter_mode, amount) = match filter { + LowLevelFilterOp::Blur(..) => (0, 0.0), + LowLevelFilterOp::Contrast(amount) => (1, amount.to_f32_px()), + LowLevelFilterOp::Grayscale(amount) => (2, amount.to_f32_px()), + LowLevelFilterOp::HueRotate(angle) => (3, (angle as f32) / ANGLE_FLOAT_TO_FIXED), + LowLevelFilterOp::Invert(amount) => (4, amount.to_f32_px()), + LowLevelFilterOp::Saturate(amount) => (5, amount.to_f32_px()), + LowLevelFilterOp::Sepia(amount) => (6, amount.to_f32_px()), + LowLevelFilterOp::Brightness(amount) => (7, amount.to_f32_px()), + LowLevelFilterOp::Opacity(amount) => (8, amount.to_f32_px()), + }; + + let amount = (amount * 65535.0).round() as i32; + + batch.items.push(PrimitiveBatchItem::StackingContext(layer_index)); + + match &mut batch.data { + &mut PrimitiveBatchData::Instances(ref mut data) => { + data.push(PrimitiveInstance { + global_prim_id: -1, + prim_address: GpuStoreAddress(0), + task_index: task_index.0 as i32, + clip_task_index: -1, + layer_index: -1, + sub_index: filter_mode, + user_data: [src_task_index.0 as i32, amount], + z_sort_index: z_sort_index, + }); } + _ => unreachable!(), } } @@ -203,153 +218,158 @@ impl AlphaBatchHelpers for PrimitiveStore { }; let task_index = task_index.0 as i32; let clip_task_index = clip_task_index.0 as i32; + batch.items.push(PrimitiveBatchItem::Primitive(prim_index)); match &mut batch.data { - &mut PrimitiveBatchData::Blend(..) | &mut PrimitiveBatchData::Composite(..) => unreachable!(), - - &mut PrimitiveBatchData::Rectangles(ref mut data) => { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: 0, - user_data: [0, 0], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::TextRun(ref mut data) => { - let text_cpu = &self.cpu_text_runs[metadata.cpu_prim_index.0]; - - for glyph_index in 0..metadata.gpu_data_count { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: metadata.gpu_data_address.0 + glyph_index, - user_data: [ text_cpu.resource_address.0 + glyph_index, 0 ], - z_sort_index: z_sort_index, - }); - } - } - &mut PrimitiveBatchData::Image(ref mut data) => { - let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; - - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: 0, - user_data: [ image_cpu.resource_address.0, 0 ], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::YuvImage(ref mut data) => { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: 0, - user_data: [ 0, 0 ], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::Borders(ref mut data) => { - for border_segment in 0..8 { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: border_segment, - user_data: [ 0, 0 ], - z_sort_index: z_sort_index, - }); - } - } - &mut PrimitiveBatchData::AlignedGradient(ref mut data) => { - for part_index in 0..(metadata.gpu_data_count - 1) { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: metadata.gpu_data_address.0 + part_index, - user_data: [ 0, 0 ], - z_sort_index: z_sort_index, - }); - } - } - &mut PrimitiveBatchData::AngleGradient(ref mut data) => { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: metadata.gpu_data_address.0, - user_data: [ metadata.gpu_data_count, 0 ], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::RadialGradient(ref mut data) => { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: metadata.gpu_data_address.0, - user_data: [ metadata.gpu_data_count, 0 ], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::CacheImage(ref mut data) => { - // Find the render task index for the render task - // that this primitive depends on. Pass it to the - // shader so that it can sample from the cache texture - // at the correct location. - let cache_task_id = &metadata.render_task.as_ref().unwrap().id; - let cache_task_index = render_tasks.get_task_index(cache_task_id, - child_pass_index); - - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: 0, - user_data: [ cache_task_index.0 as i32, 0 ], - z_sort_index: z_sort_index, - }); - } - &mut PrimitiveBatchData::BoxShadow(ref mut data) => { - let cache_task_id = &metadata.render_task.as_ref().unwrap().id; - let cache_task_index = render_tasks.get_task_index(cache_task_id, - child_pass_index); - - for rect_index in 0..metadata.gpu_data_count { - data.push(PrimitiveInstance { - task_index: task_index, - clip_task_index: clip_task_index, - layer_index: layer_index, - global_prim_id: global_prim_id, - prim_address: prim_address, - sub_index: metadata.gpu_data_address.0 + rect_index, - user_data: [ cache_task_index.0 as i32, 0 ], - z_sort_index: z_sort_index, - }); + &mut PrimitiveBatchData::Instances(ref mut data) => { + match batch.key.kind { + AlphaBatchKind::Composite => unreachable!(), + AlphaBatchKind::Blend => unreachable!(), + AlphaBatchKind::Rectangle => { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: 0, + user_data: [0, 0], + z_sort_index: z_sort_index, + }); + } + AlphaBatchKind::TextRun => { + let text_cpu = &self.cpu_text_runs[metadata.cpu_prim_index.0]; + + for glyph_index in 0..metadata.gpu_data_count { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: metadata.gpu_data_address.0 + glyph_index, + user_data: [ text_cpu.resource_address.0 + glyph_index, 0 ], + z_sort_index: z_sort_index, + }); + } + } + AlphaBatchKind::Image => { + let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; + + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: 0, + user_data: [ image_cpu.resource_address.0, 0 ], + z_sort_index: z_sort_index, + }); + } + AlphaBatchKind::YuvImage => { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: 0, + user_data: [ 0, 0 ], + z_sort_index: z_sort_index, + }); + } + AlphaBatchKind::Border => { + for border_segment in 0..8 { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: border_segment, + user_data: [ 0, 0 ], + z_sort_index: z_sort_index, + }); + } + } + AlphaBatchKind::AlignedGradient => { + for part_index in 0..(metadata.gpu_data_count - 1) { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: metadata.gpu_data_address.0 + part_index, + user_data: [ 0, 0 ], + z_sort_index: z_sort_index, + }); + } + } + AlphaBatchKind::AngleGradient => { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: metadata.gpu_data_address.0, + user_data: [ metadata.gpu_data_count, 0 ], + z_sort_index: z_sort_index, + }); + } + AlphaBatchKind::RadialGradient => { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: metadata.gpu_data_address.0, + user_data: [ metadata.gpu_data_count, 0 ], + z_sort_index: z_sort_index, + }); + } + AlphaBatchKind::BoxShadow => { + let cache_task_id = &metadata.render_task.as_ref().unwrap().id; + let cache_task_index = render_tasks.get_task_index(cache_task_id, + child_pass_index); + + for rect_index in 0..metadata.gpu_data_count { + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: metadata.gpu_data_address.0 + rect_index, + user_data: [ cache_task_index.0 as i32, 0 ], + z_sort_index: z_sort_index, + }); + } + } + AlphaBatchKind::CacheImage => { + // Find the render task index for the render task + // that this primitive depends on. Pass it to the + // shader so that it can sample from the cache texture + // at the correct location. + let cache_task_id = &metadata.render_task.as_ref().unwrap().id; + let cache_task_index = render_tasks.get_task_index(cache_task_id, + child_pass_index); + + data.push(PrimitiveInstance { + task_index: task_index, + clip_task_index: clip_task_index, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + sub_index: 0, + user_data: [ cache_task_index.0 as i32, 0 ], + z_sort_index: z_sort_index, + }); + } } } } @@ -401,12 +421,14 @@ pub enum MaskCacheKey { pub enum RenderTaskKey { /// Draw this primitive to a cache target. CachePrimitive(PrimitiveCacheKey), - /// Draw the tile alpha mask for a primitive. + /// Draw the alpha mask for a primitive. CacheMask(MaskCacheKey), /// Apply a vertical blur pass of given radius for this primitive. VerticalBlur(i32, PrimitiveIndex), /// Apply a horizontal blur pass of given radius for this primitive. HorizontalBlur(i32, PrimitiveIndex), + /// Allocate a block of space in target for framebuffer readback. + Readback(StackingContextIndex), } #[derive(Debug, Copy, Clone)] @@ -446,7 +468,7 @@ impl RenderTaskCollection { self.dynamic_tasks.insert(key, DynamicTaskInfo { index: index, rect: match task.location { - RenderTaskLocation::Fixed(rect) => rect, + RenderTaskLocation::Fixed => panic!("Dynamic tasks should not have fixed locations!"), RenderTaskLocation::Dynamic(Some((origin, _)), size) => DeviceIntRect::new(origin, size), RenderTaskLocation::Dynamic(None, _) => panic!("Expect the task to be already allocated here"), }, @@ -482,7 +504,7 @@ impl RenderTaskCollection { #[derive(Debug, Clone)] pub struct RenderTaskData { - data: [f32; FLOATS_PER_RENDER_TASK_INFO], + pub data: [f32; FLOATS_PER_RENDER_TASK_INFO], } impl RenderTaskData { @@ -545,19 +567,33 @@ impl AlphaBatcher { for task in &mut self.tasks { let task_index = render_tasks.get_static_task_index(&task.task_id); - let mut existing_alpha_batch_index = 0; let mut existing_opaque_batch_index = 0; for item in &task.alpha_items { - let batch_key = match item { - &AlphaRenderItem::Composite(..) => { - AlphaBatchKey::composite() + let (batch_key, item_bounding_rect) = match item { + &AlphaRenderItem::Blend(sc_index, ..) => { + let layer = &ctx.layer_store[sc_index.0]; + (AlphaBatchKey::new(AlphaBatchKind::Blend, + AlphaBatchKeyFlags::empty(), + BlendMode::Alpha, + BatchTextures::no_texture()), + &layer.xf_rect.as_ref().unwrap().bounding_rect) } - &AlphaRenderItem::Blend(..) => { - AlphaBatchKey::blend() + &AlphaRenderItem::Composite(sc_index, backdrop_id, src_id, info, z) => { + // Composites always get added to their own batch. + // This is because the result of a composite can affect + // the input to the next composite. Perhaps we can + // optimize this in the future. + let batch = PrimitiveBatch::new_composite(sc_index, + task_index, + render_tasks.get_task_index(&backdrop_id, child_pass_index), + render_tasks.get_static_task_index(&src_id), + info, + z); + alpha_batches.push(batch); + continue; } &AlphaRenderItem::Primitive(sc_index, prim_index, _) => { - // See if this task fits into the tile UBO let layer = &ctx.layer_store[sc_index.0]; let prim_metadata = ctx.prim_store.get_metadata(prim_index); let transform_kind = layer.xf_rect.as_ref().unwrap().kind; @@ -581,52 +617,69 @@ impl AlphaBatcher { colors: ctx.prim_store.get_color_textures(prim_metadata), }; - AlphaBatchKey::primitive(batch_kind, - flags, - blend_mode, - textures) + (AlphaBatchKey::new(batch_kind, + flags, + blend_mode, + textures), + ctx.prim_store.cpu_bounding_rects[prim_index.0].as_ref().unwrap()) } }; - while existing_alpha_batch_index < alpha_batches.len() && - !alpha_batches[existing_alpha_batch_index].key.is_compatible_with(&batch_key) { - existing_alpha_batch_index += 1 + let mut alpha_batch_index = None; + 'outer: for (batch_index, batch) in alpha_batches.iter() + .enumerate() + .rev() + .take(10) { + if batch.key.is_compatible_with(&batch_key) { + alpha_batch_index = Some(batch_index); + break; + } + + // check for intersections + for item in &batch.items { + let intersects = match *item { + PrimitiveBatchItem::StackingContext(sc_index) => { + let layer = &ctx.layer_store[sc_index.0]; + layer.xf_rect.as_ref().unwrap().bounding_rect.intersects(item_bounding_rect) + } + PrimitiveBatchItem::Primitive(prim_index) => { + let bounding_rect = &ctx.prim_store.cpu_bounding_rects[prim_index.0]; + bounding_rect.as_ref().unwrap().intersects(item_bounding_rect) + } + }; + + if intersects { + break 'outer; + } + } } - if existing_alpha_batch_index == alpha_batches.len() { + if alpha_batch_index.is_none() { let new_batch = match item { - &AlphaRenderItem::Composite(..) => { - PrimitiveBatch::composite() - } + &AlphaRenderItem::Composite(..) => unreachable!(), &AlphaRenderItem::Blend(..) => { - PrimitiveBatch::blend() + PrimitiveBatch::new_instances(AlphaBatchKind::Blend, batch_key) } &AlphaRenderItem::Primitive(_, prim_index, _) => { - // See if this task fits into the tile UBO let prim_metadata = ctx.prim_store.get_metadata(prim_index); let batch_kind = ctx.prim_store.get_batch_kind(prim_metadata); - PrimitiveBatch::new(batch_kind, batch_key) + PrimitiveBatch::new_instances(batch_kind, batch_key) } }; - alpha_batches.push(new_batch) + alpha_batch_index = Some(alpha_batches.len()); + alpha_batches.push(new_batch); } - let batch = &mut alpha_batches[existing_alpha_batch_index]; + let batch = &mut alpha_batches[alpha_batch_index.unwrap()]; match item { - &AlphaRenderItem::Composite(src0_id, src1_id, info, z) => { - let ok = batch.pack_composite(render_tasks.get_static_task_index(&src0_id), - render_tasks.get_static_task_index(&src1_id), - render_tasks.get_static_task_index(&task.task_id), - info, - z); - debug_assert!(ok) - } - &AlphaRenderItem::Blend(src_id, info, z) => { - let ok = batch.pack_blend(render_tasks.get_static_task_index(&src_id), - render_tasks.get_static_task_index(&task.task_id), - info, - z); - debug_assert!(ok) + &AlphaRenderItem::Composite(..) => unreachable!(), + &AlphaRenderItem::Blend(sc_index, src_id, info, z) => { + ctx.prim_store.add_blend_to_batch(sc_index, + batch, + task_index, + render_tasks.get_static_task_index(&src_id), + info, + z); } &AlphaRenderItem::Primitive(sc_index, prim_index, z) => { ctx.prim_store.add_prim_to_batch(prim_index, @@ -645,7 +698,6 @@ impl AlphaBatcher { &AlphaRenderItem::Composite(..) => unreachable!(), &AlphaRenderItem::Blend(..) => unreachable!(), &AlphaRenderItem::Primitive(sc_index, prim_index, _) => { - // See if this task fits into the tile UBO let layer = &ctx.layer_store[sc_index.0]; let prim_metadata = ctx.prim_store.get_metadata(prim_index); let transform_kind = layer.xf_rect.as_ref().unwrap().kind; @@ -669,10 +721,10 @@ impl AlphaBatcher { colors: ctx.prim_store.get_color_textures(prim_metadata), }; - AlphaBatchKey::primitive(batch_kind, - flags, - blend_mode, - textures) + AlphaBatchKey::new(batch_kind, + flags, + blend_mode, + textures) } }; @@ -686,10 +738,9 @@ impl AlphaBatcher { &AlphaRenderItem::Composite(..) => unreachable!(), &AlphaRenderItem::Blend(..) => unreachable!(), &AlphaRenderItem::Primitive(_, prim_index, _) => { - // See if this task fits into the tile UBO let prim_metadata = ctx.prim_store.get_metadata(prim_index); let batch_kind = ctx.prim_store.get_batch_kind(prim_metadata); - PrimitiveBatch::new(batch_kind, batch_key) + PrimitiveBatch::new_instances(batch_kind, batch_key) } }; opaque_batches.push(new_batch) @@ -798,13 +849,6 @@ impl ClipBatcher { } } - -struct CompileTileContext<'a> { - layer_store: &'a [StackingContext], - prim_store: &'a PrimitiveStore, - render_task_id_counter: AtomicUsize, -} - struct RenderTargetContext<'a> { layer_store: &'a [StackingContext], prim_store: &'a PrimitiveStore, @@ -829,6 +873,7 @@ pub struct RenderTarget { // List of blur operations to apply for this render target. pub vertical_blurs: Vec, pub horizontal_blurs: Vec, + pub readbacks: Vec, page_allocator: TexturePage, } @@ -842,6 +887,7 @@ impl RenderTarget { text_run_textures: BatchTextures::no_texture(), vertical_blurs: Vec::new(), horizontal_blurs: Vec::new(), + readbacks: Vec::new(), page_allocator: TexturePage::new(CacheTextureId(0), size), } } @@ -955,6 +1001,9 @@ impl RenderTarget { &ctx.resource_cache, task_info.geometry_kind); } + RenderTaskKind::Readback(device_rect) => { + self.readbacks.push(device_rect); + } } } } @@ -1018,9 +1067,9 @@ impl RenderPass { // Find a target to assign this task to, or create a new // one if required. match task.location { - RenderTaskLocation::Fixed(..) => {} + RenderTaskLocation::Fixed => {} RenderTaskLocation::Dynamic(ref mut origin, ref size) => { - // See if this task is a duplicate from another tile. + // See if this task is a duplicate. // If so, just skip adding it! match task.id { RenderTaskId::Static(..) => {} @@ -1061,20 +1110,20 @@ impl RenderPass { #[derive(Debug, Clone)] pub enum RenderTaskLocation { - Fixed(DeviceIntRect), + Fixed, Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize), } #[derive(Debug, Clone)] enum AlphaRenderItem { Primitive(StackingContextIndex, PrimitiveIndex, i32), - Blend(RenderTaskId, LowLevelFilterOp, i32), - Composite(RenderTaskId, RenderTaskId, MixBlendMode, i32), + Blend(StackingContextIndex, RenderTaskId, LowLevelFilterOp, i32), + Composite(StackingContextIndex, RenderTaskId, RenderTaskId, MixBlendMode, i32), } #[derive(Debug, Clone)] pub struct AlphaRenderTask { - actual_rect: DeviceIntRect, + screen_origin: DeviceIntPoint, opaque_items: Vec, alpha_items: Vec, } @@ -1122,6 +1171,7 @@ pub enum RenderTaskKind { CacheMask(CacheMaskTask), VerticalBlur(DeviceIntLength, PrimitiveIndex), HorizontalBlur(DeviceIntLength, PrimitiveIndex), + Readback(DeviceIntRect), } // TODO(gw): Consider storing these in a separate array and having @@ -1136,15 +1186,15 @@ pub struct RenderTask { } impl RenderTask { - fn new_alpha_batch(actual_rect: DeviceIntRect, ctx: &CompileTileContext) -> RenderTask { - let task_index = ctx.render_task_id_counter.fetch_add(1, Ordering::Relaxed); - + fn new_alpha_batch(task_index: RenderTaskIndex, + screen_origin: DeviceIntPoint, + location: RenderTaskLocation) -> RenderTask { RenderTask { - id: RenderTaskId::Static(RenderTaskIndex(task_index)), + id: RenderTaskId::Static(task_index), children: Vec::new(), - location: RenderTaskLocation::Dynamic(None, actual_rect.size), + location: location, kind: RenderTaskKind::Alpha(AlphaRenderTask { - actual_rect: actual_rect, + screen_origin: screen_origin, alpha_items: Vec::new(), opaque_items: Vec::new(), }), @@ -1162,6 +1212,16 @@ impl RenderTask { } } + fn new_readback(key: StackingContextIndex, + screen_rect: DeviceIntRect) -> RenderTask { + RenderTask { + id: RenderTaskId::Dynamic(RenderTaskKey::Readback(key)), + children: Vec::new(), + location: RenderTaskLocation::Dynamic(None, screen_rect.size), + kind: RenderTaskKind::Readback(screen_rect), + } + } + fn new_mask(actual_rect: DeviceIntRect, mask_key: MaskCacheKey, clips: &[(StackingContextIndex, MaskCacheInfo)], @@ -1270,6 +1330,7 @@ impl RenderTask { RenderTaskKind::CachePrimitive(..) | RenderTaskKind::CacheMask(..) | RenderTaskKind::VerticalBlur(..) | + RenderTaskKind::Readback(..) | RenderTaskKind::HorizontalBlur(..) => unreachable!(), } } @@ -1279,17 +1340,25 @@ impl RenderTask { // via a vertex texture. fn write_task_data(&self) -> RenderTaskData { let (target_rect, target_index) = self.get_target_rect(); + + // NOTE: The ordering and layout of these structures are + // required to match both the GPU structures declared + // in prim_shared.glsl, and also the uses in submit_batch() + // in renderer.rs. + // TODO(gw): Maybe there's a way to make this stuff a bit + // more type-safe. Although, it will always need + // to be kept in sync with the GLSL code anyway. + match self.kind { RenderTaskKind::Alpha(ref task) => { - debug_assert_eq!(target_rect.size, task.actual_rect.size); RenderTaskData { data: [ - task.actual_rect.origin.x as f32, - task.actual_rect.origin.y as f32, target_rect.origin.x as f32, target_rect.origin.y as f32, - task.actual_rect.size.width as f32, - task.actual_rect.size.height as f32, + target_rect.size.width as f32, + target_rect.size.height as f32, + task.screen_origin.x as f32, + task.screen_origin.y as f32, target_index.0 as f32, 0.0, 0.0, @@ -1318,7 +1387,6 @@ impl RenderTask { } } RenderTaskKind::CacheMask(ref task) => { - debug_assert_eq!(target_rect.size, task.actual_rect.size); RenderTaskData { data: [ target_rect.origin.x as f32, @@ -1355,12 +1423,32 @@ impl RenderTask { ] } } + RenderTaskKind::Readback(..) => { + RenderTaskData { + data: [ + target_rect.origin.x as f32, + target_rect.origin.y as f32, + target_rect.size.width as f32, + target_rect.size.height as f32, + target_index.0 as f32, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ] + } + } } } fn get_target_rect(&self) -> (DeviceIntRect, RenderTargetIndex) { match self.location { - RenderTaskLocation::Fixed(rect) => (rect, RenderTargetIndex(0)), + RenderTaskLocation::Fixed => { + (DeviceIntRect::zero(), RenderTargetIndex(0)) + }, RenderTaskLocation::Dynamic(origin_and_target_index, size) => { let (origin, target_index) = origin_and_target_index.expect("Should have been allocated by now!"); (DeviceIntRect::new(origin, size), target_index) @@ -1378,7 +1466,7 @@ impl RenderTask { // Sanity check - can be relaxed if needed match self.location { - RenderTaskLocation::Fixed(..) => { + RenderTaskLocation::Fixed => { debug_assert!(pass_index == passes.len() - 1); } RenderTaskLocation::Dynamic(..) => { @@ -1401,18 +1489,9 @@ impl RenderTask { } } -pub const SCREEN_TILE_SIZE: i32 = 256; - -#[derive(Debug, Clone)] -pub struct DebugRect { - pub label: String, - pub color: ColorF, - pub rect: DeviceIntRect, -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[repr(u8)] -enum AlphaBatchKind { +pub enum AlphaBatchKind { Composite = 0, Blend, Rectangle, @@ -1450,36 +1529,17 @@ impl AlphaBatchKeyFlags { #[derive(Copy, Clone, Debug)] pub struct AlphaBatchKey { - kind: AlphaBatchKind, + pub kind: AlphaBatchKind, pub flags: AlphaBatchKeyFlags, pub blend_mode: BlendMode, pub textures: BatchTextures, } impl AlphaBatchKey { - fn blend() -> AlphaBatchKey { - AlphaBatchKey { - kind: AlphaBatchKind::Blend, - flags: AXIS_ALIGNED, - blend_mode: BlendMode::Alpha, - textures: BatchTextures::no_texture(), - } - } - - fn composite() -> AlphaBatchKey { - AlphaBatchKey { - kind: AlphaBatchKind::Composite, - flags: AXIS_ALIGNED, - blend_mode: BlendMode::Alpha, - textures: BatchTextures::no_texture(), - } - } - - fn primitive(kind: AlphaBatchKind, - flags: AlphaBatchKeyFlags, - blend_mode: BlendMode, - textures: BatchTextures) - -> AlphaBatchKey { + fn new(kind: AlphaBatchKind, + flags: AlphaBatchKeyFlags, + blend_mode: BlendMode, + textures: BatchTextures) -> AlphaBatchKey { AlphaBatchKey { kind: kind, flags: flags, @@ -1534,172 +1594,92 @@ pub struct CacheClipInstance { pub struct PrimitiveInstance { global_prim_id: i32, prim_address: GpuStoreAddress, - task_index: i32, + pub task_index: i32, clip_task_index: i32, layer_index: i32, sub_index: i32, z_sort_index: i32, - user_data: [i32; 2], + pub user_data: [i32; 2], } -impl PrimitiveInstance { - fn blend(src_task_id: i32, - target_task_id: i32, - op: i32, - amount: i32, - z_sort_index: i32) -> PrimitiveInstance { - PrimitiveInstance { - global_prim_id: -1, - prim_address: GpuStoreAddress(0), - task_index: target_task_id, - clip_task_index: -1, - layer_index: -1, - sub_index: op, - user_data: [src_task_id, amount], - z_sort_index: z_sort_index, - } - } - - fn composite(src_tasks_id: [i32; 2], - target_task_id: i32, - op: i32, - z_sort_index: i32) -> PrimitiveInstance { - PrimitiveInstance { - global_prim_id: -1, - prim_address: GpuStoreAddress(0), - task_index: target_task_id, - clip_task_index: -1, - layer_index: -1, - sub_index: op, - user_data: src_tasks_id, - z_sort_index: z_sort_index, - } - } +#[derive(Debug)] +pub enum PrimitiveBatchData { + Instances(Vec), + Composite(PrimitiveInstance), } #[derive(Debug)] -pub enum PrimitiveBatchData { - Rectangles(Vec), - TextRun(Vec), - Image(Vec), - YuvImage(Vec), - Borders(Vec), - AlignedGradient(Vec), - AngleGradient(Vec), - RadialGradient(Vec), - BoxShadow(Vec), - CacheImage(Vec), - Blend(Vec), - Composite(Vec), +pub enum PrimitiveBatchItem { + Primitive(PrimitiveIndex), + StackingContext(StackingContextIndex), } #[derive(Debug)] pub struct PrimitiveBatch { pub key: AlphaBatchKey, pub data: PrimitiveBatchData, + pub items: Vec, } impl PrimitiveBatch { - fn blend() -> PrimitiveBatch { - PrimitiveBatch { - key: AlphaBatchKey::blend(), - data: PrimitiveBatchData::Blend(Vec::new()), - } - } + fn new_instances(batch_kind: AlphaBatchKind, key: AlphaBatchKey) -> PrimitiveBatch { + let data = match batch_kind { + AlphaBatchKind::Rectangle | + AlphaBatchKind::TextRun | + AlphaBatchKind::Image | + AlphaBatchKind::YuvImage | + AlphaBatchKind::Border | + AlphaBatchKind::AlignedGradient | + AlphaBatchKind::AngleGradient | + AlphaBatchKind::RadialGradient | + AlphaBatchKind::BoxShadow | + AlphaBatchKind::Blend | + AlphaBatchKind::CacheImage => { + PrimitiveBatchData::Instances(Vec::new()) + } + AlphaBatchKind::Composite => unreachable!(), + }; - fn composite() -> PrimitiveBatch { PrimitiveBatch { - key: AlphaBatchKey::composite(), - data: PrimitiveBatchData::Composite(Vec::new()), - } - } - - fn pack_blend(&mut self, - src_rect_index: RenderTaskIndex, - target_rect_index: RenderTaskIndex, - filter: LowLevelFilterOp, - z_sort_index: i32) -> bool { - match &mut self.data { - &mut PrimitiveBatchData::Blend(ref mut ubo_data) => { - let (filter_mode, amount) = match filter { - LowLevelFilterOp::Blur(..) => (0, 0.0), - LowLevelFilterOp::Contrast(amount) => (1, amount.to_f32_px()), - LowLevelFilterOp::Grayscale(amount) => (2, amount.to_f32_px()), - LowLevelFilterOp::HueRotate(angle) => (3, (angle as f32) / ANGLE_FLOAT_TO_FIXED), - LowLevelFilterOp::Invert(amount) => (4, amount.to_f32_px()), - LowLevelFilterOp::Saturate(amount) => (5, amount.to_f32_px()), - LowLevelFilterOp::Sepia(amount) => (6, amount.to_f32_px()), - LowLevelFilterOp::Brightness(amount) => (7, amount.to_f32_px()), - LowLevelFilterOp::Opacity(amount) => (8, amount.to_f32_px()), - }; - - ubo_data.push(PrimitiveInstance::blend(src_rect_index.0 as i32, - target_rect_index.0 as i32, - filter_mode, - (amount * 65535.0).round() as i32, - z_sort_index)); - true - } - _ => false - } - } - - fn pack_composite(&mut self, - rect0_index: RenderTaskIndex, - rect1_index: RenderTaskIndex, - target_rect_index: RenderTaskIndex, - info: MixBlendMode, - z_sort_index: i32) -> bool { - match &mut self.data { - &mut PrimitiveBatchData::Composite(ref mut ubo_data) => { - ubo_data.push(PrimitiveInstance::composite([rect0_index.0 as i32, - rect1_index.0 as i32], - target_rect_index.0 as i32, - info as i32, - z_sort_index)); - true - } - _ => false + key: key, + data: data, + items: Vec::new(), } } - fn new(batch_kind: AlphaBatchKind, - key: AlphaBatchKey) -> PrimitiveBatch { - let data = match batch_kind { - AlphaBatchKind::Rectangle => PrimitiveBatchData::Rectangles(Vec::new()), - AlphaBatchKind::TextRun => PrimitiveBatchData::TextRun(Vec::new()), - AlphaBatchKind::Image => PrimitiveBatchData::Image(Vec::new()), - AlphaBatchKind::YuvImage => PrimitiveBatchData::YuvImage(Vec::new()), - AlphaBatchKind::Border => PrimitiveBatchData::Borders(Vec::new()), - AlphaBatchKind::AlignedGradient => PrimitiveBatchData::AlignedGradient(Vec::new()), - AlphaBatchKind::AngleGradient => PrimitiveBatchData::AngleGradient(Vec::new()), - AlphaBatchKind::RadialGradient => PrimitiveBatchData::RadialGradient(Vec::new()), - AlphaBatchKind::BoxShadow => PrimitiveBatchData::BoxShadow(Vec::new()), - AlphaBatchKind::Blend | AlphaBatchKind::Composite => unreachable!(), - AlphaBatchKind::CacheImage => PrimitiveBatchData::CacheImage(Vec::new()), - }; + fn new_composite(layer_index: StackingContextIndex, + task_index: RenderTaskIndex, + backdrop_task: RenderTaskIndex, + src_task_index: RenderTaskIndex, + mode: MixBlendMode, + z_sort_index: i32) -> PrimitiveBatch { + let data = PrimitiveBatchData::Composite(PrimitiveInstance { + global_prim_id: -1, + prim_address: GpuStoreAddress(0), + task_index: task_index.0 as i32, + clip_task_index: -1, + layer_index: -1, + sub_index: mode as u32 as i32, + user_data: [ backdrop_task.0 as i32, + src_task_index.0 as i32 ], + z_sort_index: z_sort_index, + }); + let key = AlphaBatchKey::new(AlphaBatchKind::Composite, + AlphaBatchKeyFlags::empty(), + BlendMode::Alpha, + BatchTextures::no_texture()); PrimitiveBatch { key: key, data: data, + items: vec![PrimitiveBatchItem::StackingContext(layer_index)], } } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct ScreenTileLayerIndex(usize); - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct StackingContextIndex(usize); -#[derive(Debug)] -struct TileRange { - x0: i32, - y0: i32, - x1: i32, - y1: i32, -} - struct StackingContext { pipeline_id: PipelineId, local_transform: LayerToScrollTransform, @@ -1707,12 +1687,12 @@ struct StackingContext { scroll_layer_id: ScrollLayerId, xf_rect: Option, composite_kind: CompositeKind, - tile_range: Option, clip_source: ClipSource, clip_cache_info: Option, } #[derive(Debug, Clone)] +#[repr(C)] pub struct PackedStackingContext { transform: LayerToWorldTransform, inv_transform: WorldToLayerTransform, @@ -1781,11 +1761,6 @@ impl StackingContext { } } -#[derive(Debug, Clone)] -pub struct ClearTile { - pub rect: DeviceIntRect, -} - #[derive(Clone, Copy)] pub struct FrameBuilderConfig { pub enable_scrollbars: bool, @@ -1807,7 +1782,7 @@ pub struct FrameBuilder { background_color: Option, prim_store: PrimitiveStore, cmds: Vec, - debug: bool, + _debug: bool, // Unused for now, but handy to keep around config: FrameBuilderConfig, layer_store: Vec, @@ -1822,7 +1797,6 @@ pub struct Frame { pub viewport_size: LayerSize, pub background_color: Option, pub device_pixel_ratio: f32, - pub debug_rects: Vec, pub cache_size: DeviceUintSize, pub passes: Vec, pub profile_counters: FrameProfileCounters, @@ -1843,193 +1817,6 @@ pub struct Frame { pub deferred_resolves: Vec, } -/// Some extra per-tile information stored for debugging purposes. -#[derive(Debug)] -struct CompiledScreenTileInfo { - cmd_count: usize, - prim_count: usize, -} - -#[derive(Debug)] -struct CompiledScreenTile { - main_render_task: RenderTask, - required_pass_count: usize, - info: CompiledScreenTileInfo, -} - -impl CompiledScreenTile { - fn new(main_render_task: RenderTask, - info: CompiledScreenTileInfo) - -> CompiledScreenTile { - let mut required_pass_count = 0; - main_render_task.max_depth(0, &mut required_pass_count); - - CompiledScreenTile { - main_render_task: main_render_task, - required_pass_count: required_pass_count, - info: info, - } - } - - fn build(self, passes: &mut Vec) { - self.main_render_task.assign_to_passes(passes.len() - 1, - passes); - } -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -enum TileCommand { - PushLayer(StackingContextIndex), - PopLayer, - DrawPrimitive(PrimitiveIndex), -} - -#[derive(Debug)] -struct ScreenTile { - rect: DeviceIntRect, - cmds: Vec, - prim_count: usize, -} - -impl ScreenTile { - fn new(rect: DeviceIntRect) -> ScreenTile { - ScreenTile { - rect: rect, - cmds: Vec::new(), - prim_count: 0, - } - } - - #[inline(always)] - fn push_layer(&mut self, - sc_index: StackingContextIndex) { - self.cmds.push(TileCommand::PushLayer(sc_index)); - } - - #[inline(always)] - fn push_primitive(&mut self, prim_index: PrimitiveIndex) { - self.cmds.push(TileCommand::DrawPrimitive(prim_index)); - self.prim_count += 1; - } - - #[inline(always)] - fn pop_layer(&mut self, sc_index: StackingContextIndex) { - let last_cmd = *self.cmds.last().unwrap(); - if last_cmd == TileCommand::PushLayer(sc_index) { - self.cmds.pop(); - } else { - self.cmds.push(TileCommand::PopLayer); - } - } - - fn compile(self, ctx: &CompileTileContext) -> Option { - if self.prim_count == 0 { - return None; - } - - let cmd_count = self.cmds.len(); - let mut actual_prim_count = 0; - let mut next_z = 0; - - let mut sc_stack = Vec::new(); - let mut current_task = RenderTask::new_alpha_batch(self.rect, ctx); - let mut alpha_task_stack = Vec::new(); - - for cmd in self.cmds { - match cmd { - TileCommand::PushLayer(sc_index) => { - sc_stack.push(sc_index); - - let layer = &ctx.layer_store[sc_index.0]; - match layer.composite_kind { - CompositeKind::None => {} - CompositeKind::Simple(..) | CompositeKind::Complex(..) => { - let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; - let needed_rect = layer_rect.intersection(&self.rect) - .expect("bug if these don't overlap"); - let prev_task = mem::replace(&mut current_task, - RenderTask::new_alpha_batch(needed_rect, ctx)); - alpha_task_stack.push(prev_task); - } - } - } - TileCommand::PopLayer => { - let sc_index = sc_stack.pop().unwrap(); - - let layer = &ctx.layer_store[sc_index.0]; - match layer.composite_kind { - CompositeKind::None => {} - CompositeKind::Simple(info) => { - let mut prev_task = alpha_task_stack.pop().unwrap(); - let item = AlphaRenderItem::Blend(current_task.id, info, next_z); - next_z += 1; - prev_task.as_alpha_batch().alpha_items.push(item); - prev_task.children.push(current_task); - current_task = prev_task; - } - CompositeKind::Complex(info) => { - let backdrop = alpha_task_stack.pop().unwrap(); - - let mut composite_task = RenderTask::new_alpha_batch(self.rect, ctx); - - let item = AlphaRenderItem::Composite(backdrop.id, - current_task.id, - info, - next_z); - next_z += 1; - composite_task.as_alpha_batch().alpha_items.push(item); - - composite_task.children.push(backdrop); - composite_task.children.push(current_task); - - current_task = composite_task; - } - } - } - TileCommand::DrawPrimitive(prim_index) => { - let sc_index = *sc_stack.last().unwrap(); - let prim_metadata = ctx.prim_store.get_metadata(prim_index); - - // Add any dynamic render tasks needed to render this primitive - if let Some(ref render_task) = prim_metadata.render_task { - current_task.children.push(render_task.clone()); - } - if let Some(ref clip_task) = prim_metadata.clip_task { - current_task.children.push(clip_task.clone()); - } - - actual_prim_count += 1; - - let layer = &ctx.layer_store[sc_index.0]; - let transform_kind = layer.xf_rect.as_ref().unwrap().kind; - let needs_clipping = prim_metadata.clip_task.is_some(); - let needs_blending = transform_kind == TransformedRectKind::Complex || - !prim_metadata.is_opaque || - needs_clipping; - - let items = if needs_blending { - &mut current_task.as_alpha_batch().alpha_items - } else { - &mut current_task.as_alpha_batch().opaque_items - }; - items.push(AlphaRenderItem::Primitive(sc_index, prim_index, next_z)); - next_z += 1; - } - } - } - - debug_assert!(alpha_task_stack.is_empty()); - - let info = CompiledScreenTileInfo { - cmd_count: cmd_count, - prim_count: actual_prim_count, - }; - - current_task.location = RenderTaskLocation::Fixed(self.rect); - Some(CompiledScreenTile::new(current_task, info)) - } -} - impl FrameBuilder { pub fn new(viewport_size: LayerSize, background_color: Option, @@ -2041,7 +1828,7 @@ impl FrameBuilder { layer_store: Vec::new(), prim_store: PrimitiveStore::new(), cmds: Vec::new(), - debug: debug, + _debug: debug, packed_layers: Vec::new(), scrollbar_prims: Vec::new(), config: config, @@ -2105,7 +1892,6 @@ impl FrameBuilder { pipeline_id: pipeline_id, xf_rect: None, composite_kind: CompositeKind::new(composition_operations), - tile_range: None, clip_source: clip_source, clip_cache_info: clip_info, }; @@ -2523,8 +2309,6 @@ impl FrameBuilder { screen_rect: &DeviceIntRect, scroll_tree: &ScrollTree, auxiliary_lists_map: &AuxiliaryListsMap, - x_tile_count: i32, - y_tile_count: i32, resource_cache: &mut ResourceCache, profile_counters: &mut FrameProfileCounters, device_pixel_ratio: f32) { @@ -2543,7 +2327,6 @@ impl FrameBuilder { let packed_layer = &mut self.packed_layers[sc_index.0]; layer.xf_rect = None; - layer.tile_range = None; let scroll_layer = &scroll_tree.layers[&layer.scroll_layer_id]; packed_layer.transform = scroll_layer.world_content_transform @@ -2571,31 +2354,7 @@ impl FrameBuilder { if layer_xf_rect.bounding_rect.intersects(&screen_rect) { packed_layer.screen_vertices = layer_xf_rect.vertices.clone(); packed_layer.local_clip_rect = layer_local_rect; - - let layer_rect = layer_xf_rect.bounding_rect; layer.xf_rect = Some(layer_xf_rect); - - let tile_x0 = layer_rect.origin.x / SCREEN_TILE_SIZE; - let tile_y0 = layer_rect.origin.y / SCREEN_TILE_SIZE; - let tile_x1 = (layer_rect.origin.x + layer_rect.size.width + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; - let tile_y1 = (layer_rect.origin.y + layer_rect.size.height + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; - - let tile_x0 = cmp::min(tile_x0, x_tile_count); - let tile_x0 = cmp::max(tile_x0, 0); - let tile_x1 = cmp::min(tile_x1, x_tile_count); - let tile_x1 = cmp::max(tile_x1, 0); - - let tile_y0 = cmp::min(tile_y0, y_tile_count); - let tile_y0 = cmp::max(tile_y0, 0); - let tile_y1 = cmp::min(tile_y1, y_tile_count); - let tile_y1 = cmp::max(tile_y1, 0); - - layer.tile_range = Some(TileRange { - x0: tile_x0, - y0: tile_y0, - x1: tile_x1, - y1: tile_y1, - }); } } @@ -2720,154 +2479,6 @@ impl FrameBuilder { } } - fn create_screen_tiles(&self, device_pixel_ratio: f32) -> (i32, i32, Vec) { - let dp_size = DeviceIntSize::from_lengths(device_length(self.screen_rect.size.width as f32, - device_pixel_ratio), - device_length(self.screen_rect.size.height as f32, - device_pixel_ratio)); - - let x_tile_size = SCREEN_TILE_SIZE; - let y_tile_size = SCREEN_TILE_SIZE; - let x_tile_count = (dp_size.width + x_tile_size - 1) / x_tile_size; - let y_tile_count = (dp_size.height + y_tile_size - 1) / y_tile_size; - - // Build screen space tiles, which are individual BSP trees. - let mut screen_tiles = Vec::new(); - for y in 0..y_tile_count { - let y0 = y * y_tile_size; - let y1 = y0 + y_tile_size; - - for x in 0..x_tile_count { - let x0 = x * x_tile_size; - let x1 = x0 + x_tile_size; - - let tile_rect = rect_from_points(DeviceIntLength::new(x0), - DeviceIntLength::new(y0), - DeviceIntLength::new(x1), - DeviceIntLength::new(y1)); - - screen_tiles.push(ScreenTile::new(tile_rect)); - } - } - - (x_tile_count, y_tile_count, screen_tiles) - } - - - fn assign_prims_to_screen_tiles(&self, - screen_tiles: &mut Vec, - x_tile_count: i32, - device_pixel_ratio: f32) { - let mut layer_stack: Vec = Vec::new(); - let mut clip_rect_stack = Vec::new(); - - for cmd in &self.cmds { - match cmd { - &PrimitiveRunCmd::PushStackingContext(sc_index) => { - layer_stack.push(sc_index); - - let layer = &self.layer_store[sc_index.0]; - if !layer.is_visible() { - continue; - } - - if let Some(ref clip_info) = layer.clip_cache_info { - clip_rect_stack.push(clip_info.outer_rect); - } - - let tile_range = layer.tile_range.as_ref().unwrap(); - for ly in tile_range.y0..tile_range.y1 { - for lx in tile_range.x0..tile_range.x1 { - let tile = &mut screen_tiles[(ly * x_tile_count + lx) as usize]; - tile.push_layer(sc_index); - } - } - } - &PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count) => { - let sc_index = layer_stack.last().unwrap(); - - let layer = &self.layer_store[sc_index.0]; - if !layer.is_visible() { - continue; - } - let packed_layer = &self.packed_layers[sc_index.0]; - - let tile_range = layer.tile_range.as_ref().unwrap(); - let xf_rect = &layer.xf_rect.as_ref().unwrap(); - - for i in 0..prim_count { - let prim_index = PrimitiveIndex(first_prim_index.0 + i); - - // check the bounding box - let mut p_rect = match self.prim_store.get_bounding_rect(prim_index) { - &Some(r) => r, - &None => continue, - }; - // check the clip bounding rectangle - if let Some(ref clip_info) = self.prim_store.get_metadata(prim_index).clip_cache_info { - p_rect = match p_rect.intersection(&clip_info.outer_rect) { - Some(r) => r, - None => continue, - } - } else - // check the parent layer clip rectangle - if let Some(clip_rect) = clip_rect_stack.last() { - p_rect = match p_rect.intersection(clip_rect) { - Some(r) => r, - None => continue, - } - } - - // TODO(gw): Ensure that certain primitives (such as background-image) only get - // assigned to tiles where their containing layer intersects with. - // Does this cause any problems / demonstrate other bugs? - // Restrict the tiles by clamping to the layer tile indices... - - let p_tile_x0 = p_rect.origin.x / SCREEN_TILE_SIZE; - let p_tile_y0 = p_rect.origin.y / SCREEN_TILE_SIZE; - let p_tile_x1 = (p_rect.origin.x + p_rect.size.width + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; - let p_tile_y1 = (p_rect.origin.y + p_rect.size.height + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; - - for py in cmp::max(p_tile_y0, tile_range.y0) .. cmp::min(p_tile_y1, tile_range.y1) { - for px in cmp::max(p_tile_x0, tile_range.x0) .. cmp::min(p_tile_x1, tile_range.x1) { - let tile = &mut screen_tiles[(py * x_tile_count + px) as usize]; - - // TODO(gw): Support narrow phase for 3d transform elements! - if xf_rect.kind == TransformedRectKind::Complex || - self.prim_store.prim_affects_tile(prim_index, - &tile.rect, - &packed_layer.transform, - device_pixel_ratio) { - tile.push_primitive(prim_index); - } - } - } - } - } - &PrimitiveRunCmd::PopStackingContext => { - let sc_index = layer_stack.pop().unwrap(); - - let layer = &self.layer_store[sc_index.0]; - if !layer.is_visible() { - continue; - } - - if layer.clip_cache_info.is_some() { - clip_rect_stack.pop(); - } - - let tile_range = layer.tile_range.as_ref().unwrap(); - for ly in tile_range.y0..tile_range.y1 { - for lx in tile_range.x0..tile_range.x1 { - let tile = &mut screen_tiles[(ly * x_tile_count + lx) as usize]; - tile.pop_layer(sc_index); - } - } - } - } - } - } - fn update_scroll_bars(&mut self, scroll_tree: &ScrollTree) { let distance_from_edge = 8.0; @@ -2913,6 +2524,118 @@ impl FrameBuilder { } } + fn build_render_task(&self) -> (RenderTask, usize) { + let mut next_z = 0; + let mut next_task_index = RenderTaskIndex(0); + + let mut sc_stack = Vec::new(); + let mut current_task = RenderTask::new_alpha_batch(next_task_index, + DeviceIntPoint::zero(), + RenderTaskLocation::Fixed); + next_task_index.0 += 1; + let mut alpha_task_stack = Vec::new(); + + for cmd in &self.cmds { + match *cmd { + PrimitiveRunCmd::PushStackingContext(sc_index) => { + let layer = &self.layer_store[sc_index.0]; + sc_stack.push(sc_index); + + if !layer.is_visible() { + continue; + } + + match layer.composite_kind { + CompositeKind::None => {} + CompositeKind::Simple(..) | CompositeKind::Complex(..) => { + let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; + let location = RenderTaskLocation::Dynamic(None, layer_rect.size); + let new_task = RenderTask::new_alpha_batch(next_task_index, + layer_rect.origin, + location); + next_task_index.0 += 1; + let prev_task = mem::replace(&mut current_task, new_task); + alpha_task_stack.push(prev_task); + } + } + } + PrimitiveRunCmd::PopStackingContext => { + let sc_index = sc_stack.pop().unwrap(); + let layer = &self.layer_store[sc_index.0]; + + if !layer.is_visible() { + continue; + } + + match layer.composite_kind { + CompositeKind::None => {} + CompositeKind::Simple(info) => { + let mut prev_task = alpha_task_stack.pop().unwrap(); + let item = AlphaRenderItem::Blend(sc_index, current_task.id, info, next_z); + next_z += 1; + prev_task.as_alpha_batch().alpha_items.push(item); + prev_task.children.push(current_task); + current_task = prev_task; + } + CompositeKind::Complex(info) => { + let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; + let readback_task = RenderTask::new_readback(sc_index, layer_rect); + + let mut prev_task = alpha_task_stack.pop().unwrap(); + let item = AlphaRenderItem::Composite(sc_index, readback_task.id, current_task.id, info, next_z); + next_z += 1; + prev_task.as_alpha_batch().alpha_items.push(item); + prev_task.children.push(current_task); + prev_task.children.push(readback_task); + current_task = prev_task; + } + } + } + PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count) => { + let sc_index = *sc_stack.last().unwrap(); + let layer = &self.layer_store[sc_index.0]; + + if !layer.is_visible() { + continue; + } + + for i in 0..prim_count { + let prim_index = PrimitiveIndex(first_prim_index.0 + i); + + if let Some(..) = self.prim_store.cpu_bounding_rects[prim_index.0] { + let prim_metadata = self.prim_store.get_metadata(prim_index); + + // Add any dynamic render tasks needed to render this primitive + if let Some(ref render_task) = prim_metadata.render_task { + current_task.children.push(render_task.clone()); + } + if let Some(ref clip_task) = prim_metadata.clip_task { + current_task.children.push(clip_task.clone()); + } + + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let needs_clipping = prim_metadata.clip_task.is_some(); + let needs_blending = transform_kind == TransformedRectKind::Complex || + !prim_metadata.is_opaque || + needs_clipping; + + let items = if needs_blending { + &mut current_task.as_alpha_batch().alpha_items + } else { + &mut current_task.as_alpha_batch().opaque_items + }; + items.push(AlphaRenderItem::Primitive(sc_index, prim_index, next_z)); + next_z += 1; + } + } + } + } + } + + debug_assert!(alpha_task_stack.is_empty()); + (current_task, next_task_index.0) + } + pub fn build(&mut self, resource_cache: &mut ResourceCache, frame_id: FrameId, @@ -2935,74 +2658,23 @@ impl FrameBuilder { // has to be at least as large as the framebuffer size. This ensures that it will // always be able to allocate the worst case render task (such as a clip mask that // covers the entire screen). - // However, there are some extremely subtle rounding errors that occur in the - // reftests under OSMesa if the cache targets are exactly the size of the - // framebuffer. To work around this, we'll align the cache size to a multiple - // of the tile size. This can be removed once the tiling code is gone. - // TODO(gw): Remove this hack once the tiling code is sorted out!! - let max_dimension = cmp::max(screen_rect.size.width, screen_rect.size.height); - let aligned_max_dimension = (max_dimension + SCREEN_TILE_SIZE - 1) & !(SCREEN_TILE_SIZE-1); - let cache_size = DeviceUintSize::new(aligned_max_dimension as u32, - aligned_max_dimension as u32); - - let mut debug_rects = Vec::new(); - - let (x_tile_count, y_tile_count, mut screen_tiles) = self.create_screen_tiles(device_pixel_ratio); + let cache_size = DeviceUintSize::new(cmp::max(1024, screen_rect.size.width as u32), + cmp::max(1024, screen_rect.size.height as u32)); self.update_scroll_bars(scroll_tree); self.cull_layers(&screen_rect, scroll_tree, auxiliary_lists_map, - x_tile_count, - y_tile_count, resource_cache, &mut profile_counters, device_pixel_ratio); - let mut compiled_screen_tiles = Vec::new(); - let mut max_passes_needed = 0; - - let mut render_tasks = { - let ctx = CompileTileContext { - layer_store: &self.layer_store, - prim_store: &self.prim_store, - - // This doesn't need to be atomic right now (all the screen tiles are - // compiled on a single thread). However, in the future each of the - // compile steps below will be run on a worker thread, which will - // require an atomic int here anyway. - render_task_id_counter: AtomicUsize::new(0), - }; - - if !self.layer_store.is_empty() { - self.assign_prims_to_screen_tiles(&mut screen_tiles, - x_tile_count, - device_pixel_ratio); - } - - // Build list of passes, target allocs that each tile needs. - for screen_tile in screen_tiles { - let rect = screen_tile.rect; - if let Some(compiled_screen_tile) = screen_tile.compile(&ctx) { - max_passes_needed = cmp::max(max_passes_needed, - compiled_screen_tile.required_pass_count); - if self.debug { - let label = format!("{}|{}", compiled_screen_tile.info.cmd_count, compiled_screen_tile.info.prim_count); - let color = ColorF::new(1.0, 0.0, 0.0, 1.0); - debug_rects.push(DebugRect { - label: label, - color: color, - rect: rect, - }); - } - compiled_screen_tiles.push(compiled_screen_tile); - } - } + let (main_render_task, static_render_task_count) = self.build_render_task(); + let mut render_tasks = RenderTaskCollection::new(static_render_task_count); - let static_render_task_count = ctx.render_task_id_counter.load(Ordering::SeqCst); - RenderTaskCollection::new(static_render_task_count) - }; + let mut required_pass_count = 0; + main_render_task.max_depth(0, &mut required_pass_count); resource_cache.block_until_all_resources_added(); @@ -3012,36 +2684,31 @@ impl FrameBuilder { } } - let deferred_resolves = self.prim_store.resolve_primitives(resource_cache, device_pixel_ratio); let mut passes = Vec::new(); - if !compiled_screen_tiles.is_empty() { + // Do the allocations now, assigning each tile's tasks to a render + // pass and target as required. + for index in 0..required_pass_count { + passes.push(RenderPass::new(index as isize, + index == required_pass_count-1, + cache_size)); + } + + main_render_task.assign_to_passes(passes.len() - 1, &mut passes); + + for pass in &mut passes { let ctx = RenderTargetContext { layer_store: &self.layer_store, prim_store: &self.prim_store, resource_cache: resource_cache, }; - // Do the allocations now, assigning each tile's tasks to a render - // pass and target as required. - for index in 0..max_passes_needed { - passes.push(RenderPass::new(index as isize, - index == max_passes_needed-1, - cache_size)); - } + pass.build(&ctx, &mut render_tasks); - for compiled_screen_tile in compiled_screen_tiles { - compiled_screen_tile.build(&mut passes); - } - - for pass in &mut passes { - pass.build(&ctx, &mut render_tasks); - - profile_counters.passes.inc(); - profile_counters.targets.add(pass.targets.len()); - } + profile_counters.passes.inc(); + profile_counters.targets.add(pass.targets.len()); } resource_cache.end_frame(); @@ -3050,7 +2717,6 @@ impl FrameBuilder { device_pixel_ratio: device_pixel_ratio, background_color: self.background_color, viewport_size: self.screen_rect.size, - debug_rects: debug_rects, profile_counters: profile_counters, passes: passes, cache_size: cache_size, diff --git a/webrender/src/util.rs b/webrender/src/util.rs index b7b7316431..a63ec1d347 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -4,7 +4,7 @@ use euclid::{Point2D, Rect, Size2D}; use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedPoint4D, TypedMatrix4D}; -use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize, DeviceIntLength}; +use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize}; use webrender_traits::{LayerRect, WorldPoint4D, LayerPoint4D, LayerToWorldTransform}; use num_traits::Zero; use time::precise_time_ns; @@ -120,15 +120,6 @@ pub fn rect_is_empty(rect: &TypedRect) -> bool { rect.size.width == Zero::zero() || rect.size.height == Zero::zero() } -#[inline] -pub fn rect_from_points(x0: DeviceIntLength, - y0: DeviceIntLength, - x1: DeviceIntLength, - y1: DeviceIntLength) -> DeviceIntRect { - DeviceIntRect::new(DeviceIntPoint::from_lengths(x0, y0), - DeviceIntSize::from_lengths(x1 - x0, y1 - y0)) -} - #[inline] pub fn rect_from_points_f(x0: f32, y0: f32, From a9e3aec5d9e159e1ab0429f21e04f65447ac2570 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 25 Jan 2017 08:57:32 +1000 Subject: [PATCH 2/2] Address some review comments. --- webrender/src/renderer.rs | 1 - webrender/src/tiling.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 321451f0c4..90c8077c2a 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -1112,7 +1112,6 @@ impl Renderer { let projection = { let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET); - self.device.bind_read_target(render_target); self.device.bind_draw_target(render_target, Some(target_size)); self.device.set_blend(false); diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 8e34c3603f..cb6b33f215 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -179,8 +179,8 @@ impl AlphaBatchHelpers for PrimitiveStore { batch.items.push(PrimitiveBatchItem::StackingContext(layer_index)); - match &mut batch.data { - &mut PrimitiveBatchData::Instances(ref mut data) => { + match batch.data { + PrimitiveBatchData::Instances(ref mut data) => { data.push(PrimitiveInstance { global_prim_id: -1, prim_address: GpuStoreAddress(0), @@ -427,8 +427,8 @@ pub enum RenderTaskKey { VerticalBlur(i32, PrimitiveIndex), /// Apply a horizontal blur pass of given radius for this primitive. HorizontalBlur(i32, PrimitiveIndex), - /// Allocate a block of space in target for framebuffer readback. - Readback(StackingContextIndex), + /// Allocate a block of space in target for framebuffer copy. + CopyFramebuffer(StackingContextIndex), } #[derive(Debug, Copy, Clone)] @@ -1215,7 +1215,7 @@ impl RenderTask { fn new_readback(key: StackingContextIndex, screen_rect: DeviceIntRect) -> RenderTask { RenderTask { - id: RenderTaskId::Dynamic(RenderTaskKey::Readback(key)), + id: RenderTaskId::Dynamic(RenderTaskKey::CopyFramebuffer(key)), children: Vec::new(), location: RenderTaskLocation::Dynamic(None, screen_rect.size), kind: RenderTaskKind::Readback(screen_rect), @@ -2602,7 +2602,7 @@ impl FrameBuilder { for i in 0..prim_count { let prim_index = PrimitiveIndex(first_prim_index.0 + i); - if let Some(..) = self.prim_store.cpu_bounding_rects[prim_index.0] { + if self.prim_store.cpu_bounding_rects[prim_index.0].is_some() { let prim_metadata = self.prim_store.get_metadata(prim_index); // Add any dynamic render tasks needed to render this primitive