Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions core/src/bitmap/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,13 @@ pub fn draw<'gc>(
library: context.library,
transform_stack: &mut transform_stack,
is_offscreen: true,
use_bitmap_cache: false,

// Use CAB only when drawing with the same quality, because this draw
// will update caches. When drawing with a different quality, we would
// either (1) update caches for regular draws with this temporary
// quality, or (2) draw cached bitmaps with the regular quality.
// TODO Support CAB draw with different quality and remove this param.
use_bitmap_cache: context.stage.quality() == quality,
stage: context.stage,
};

Expand Down Expand Up @@ -1597,13 +1603,10 @@ pub fn draw<'gc>(
dirty_region.union(old);
}

assert!(
cache_draws.is_empty(),
"BitmapData.draw() should not use cacheAsBitmap"
);
let image = context
.renderer
.render_offscreen(handle, commands, quality, dirty_region);
let image =
context
.renderer
.render_offscreen(handle, commands, quality, dirty_region, cache_draws);

match image {
Some(sync_handle) => {
Expand Down
1 change: 1 addition & 0 deletions render/canvas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ impl RenderBackend for WebCanvasRenderBackend {
_commands: CommandList,
_quality: StageQuality,
_bounds: PixelRegion,
_cache_entries: Vec<BitmapCacheEntry>,
) -> Option<Box<dyn SyncHandle>> {
None
}
Expand Down
1 change: 1 addition & 0 deletions render/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub trait RenderBackend: Any {
commands: CommandList,
quality: StageQuality,
bounds: PixelRegion,
cache_entries: Vec<BitmapCacheEntry>,
) -> Option<Box<dyn SyncHandle>>;

/// Applies the given filter with a `BitmapHandle` source onto a destination `BitmapHandle`.
Expand Down
1 change: 1 addition & 0 deletions render/src/backend/null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl RenderBackend for NullRenderer {
_commands: CommandList,
_quality: StageQuality,
_bounds: PixelRegion,
_cache_entries: Vec<BitmapCacheEntry>,
) -> Option<Box<dyn SyncHandle>> {
None
}
Expand Down
1 change: 1 addition & 0 deletions render/webgl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,7 @@ impl RenderBackend for WebGlRenderBackend {
_commands: CommandList,
_quality: StageQuality,
_bounds: PixelRegion,
_cache_entries: Vec<BitmapCacheEntry>,
) -> Option<Box<dyn SyncHandle>> {
None
}
Expand Down
159 changes: 83 additions & 76 deletions render/wgpu/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,85 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
}) => unreachable!("Buffer must be Borrowed as it was set to be Borrowed earlier"),
}
}

fn draw_cache(&mut self, cache_entries: Vec<BitmapCacheEntry>) {
for entry in cache_entries {
let texture = as_texture(&entry.handle);
let mut surface = Surface::new(
&self.descriptors,
self.surface.quality(),
texture.texture.width(),
texture.texture.height(),
wgpu::TextureFormat::Rgba8Unorm,
);
if entry.filters.is_empty() {
surface.draw_commands(
RenderTargetMode::ExistingWithColor(
texture.texture.clone(),
wgpu::Color {
r: f64::from(entry.clear.r) / 255.0,
g: f64::from(entry.clear.g) / 255.0,
b: f64::from(entry.clear.b) / 255.0,
a: f64::from(entry.clear.a) / 255.0,
},
),
&self.descriptors,
&self.meshes,
entry.commands,
&mut self.active_frame.staging_belt,
&self.dynamic_transforms,
&mut self.active_frame.command_encoder,
LayerRef::None,
&mut self.offscreen_texture_pool,
);
} else {
// We're relying on there being no impotent filters here,
// so that we can safely start by using the actual CAB texture.
// It's guaranteed that at least one filter would have used it and moved the target to something else,
// letting us safely copy back to it later.
let mut target = surface.draw_commands(
RenderTargetMode::ExistingWithColor(
texture.texture.clone(),
wgpu::Color {
r: f64::from(entry.clear.r) / 255.0,
g: f64::from(entry.clear.g) / 255.0,
b: f64::from(entry.clear.b) / 255.0,
a: f64::from(entry.clear.a) / 255.0,
},
),
&self.descriptors,
&self.meshes,
entry.commands,
&mut self.active_frame.staging_belt,
&self.dynamic_transforms,
&mut self.active_frame.command_encoder,
LayerRef::None,
&mut self.offscreen_texture_pool,
);
for filter in entry.filters {
target = self.descriptors.filters.apply(
&self.descriptors,
&mut self.active_frame.command_encoder,
&mut self.offscreen_texture_pool,
&mut self.active_frame.staging_belt,
FilterSource::for_entire_texture(target.color_texture()),
filter,
);
}
run_copy_pipeline(
&self.descriptors,
target.color_texture().format(),
texture.texture.format(),
&texture.texture.create_view(&Default::default()),
target.color_view(),
target.whole_frame_bind_group(&self.descriptors),
target.globals(),
target.color_texture().sample_count(),
&mut self.active_frame.command_encoder,
);
}
}
}
}

impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
Expand Down Expand Up @@ -499,82 +578,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
}
};

for entry in cache_entries {
let texture = as_texture(&entry.handle);
let mut surface = Surface::new(
&self.descriptors,
self.surface.quality(),
texture.texture.width(),
texture.texture.height(),
wgpu::TextureFormat::Rgba8Unorm,
);
if entry.filters.is_empty() {
surface.draw_commands(
RenderTargetMode::ExistingWithColor(
texture.texture.clone(),
wgpu::Color {
r: f64::from(entry.clear.r) / 255.0,
g: f64::from(entry.clear.g) / 255.0,
b: f64::from(entry.clear.b) / 255.0,
a: f64::from(entry.clear.a) / 255.0,
},
),
&self.descriptors,
&self.meshes,
entry.commands,
&mut self.active_frame.staging_belt,
&self.dynamic_transforms,
&mut self.active_frame.command_encoder,
LayerRef::None,
&mut self.offscreen_texture_pool,
);
} else {
// We're relying on there being no impotent filters here,
// so that we can safely start by using the actual CAB texture.
// It's guaranteed that at least one filter would have used it and moved the target to something else,
// letting us safely copy back to it later.
let mut target = surface.draw_commands(
RenderTargetMode::ExistingWithColor(
texture.texture.clone(),
wgpu::Color {
r: f64::from(entry.clear.r) / 255.0,
g: f64::from(entry.clear.g) / 255.0,
b: f64::from(entry.clear.b) / 255.0,
a: f64::from(entry.clear.a) / 255.0,
},
),
&self.descriptors,
&self.meshes,
entry.commands,
&mut self.active_frame.staging_belt,
&self.dynamic_transforms,
&mut self.active_frame.command_encoder,
LayerRef::None,
&mut self.offscreen_texture_pool,
);
for filter in entry.filters {
target = self.descriptors.filters.apply(
&self.descriptors,
&mut self.active_frame.command_encoder,
&mut self.offscreen_texture_pool,
&mut self.active_frame.staging_belt,
FilterSource::for_entire_texture(target.color_texture()),
filter,
);
}
run_copy_pipeline(
&self.descriptors,
target.color_texture().format(),
texture.texture.format(),
&texture.texture.create_view(&Default::default()),
target.color_view(),
target.whole_frame_bind_group(&self.descriptors),
target.globals(),
target.color_texture().sample_count(),
&mut self.active_frame.command_encoder,
);
}
}
self.draw_cache(cache_entries);

self.surface.draw_commands_and_copy_to(
frame_output.view(),
Expand Down Expand Up @@ -710,6 +714,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
commands: CommandList,
quality: StageQuality,
bounds: PixelRegion,
cache_entries: Vec<BitmapCacheEntry>,
) -> Option<Box<dyn SyncHandle>> {
let texture = as_texture(&handle);

Expand All @@ -730,6 +735,8 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
.get_next_texture()
.expect("TextureTargetFrame.get_next_texture is infallible");

self.draw_cache(cache_entries);

let mut surface = Surface::new(
&self.descriptors,
quality,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ num_ticks = 20

[image_comparisons.output]
tolerance = 30
max_outliers = 400
max_outliers = 500

[player_options]
with_renderer = { optional = false, sample_count = 1 }
Expand Down
39 changes: 39 additions & 0 deletions tests/tests/swfs/avm2/bitmapdata_draw_cab_quality/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package {
import flash.display.*;
import flash.geom.*;
import flash.filters.*;
import flash.utils.*;

[SWF(width="40", height="40")]
public class Test extends MovieClip {
public function Test() {
var s:Sprite = new Sprite();
s.graphics.beginFill(0xFF00FF);
s.graphics.drawTriangles(Vector.<Number>([
0, 0,
0, 20,
20, 20
]), Vector.<int>([
0, 1, 2
]));
s.graphics.endFill();
s.cacheAsBitmap = true;

var bd:BitmapData = new BitmapData(40, 20);
bd.fillRect(new Rectangle(0,0,40,20), 0xFF000000);
bd.drawWithQuality(
s,
new Matrix(1, 0, 0, 1, 20, 0),
new ColorTransform(0, 1, 1),
"difference",
new Rectangle(0, 10, 40, 10),
false,
"low"
);
var b:Bitmap = new Bitmap(bd);
b.y = 20;
addChild(b);
addChild(s);
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Binary file not shown.
10 changes: 10 additions & 0 deletions tests/tests/swfs/avm2/bitmapdata_draw_cab_quality/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
num_ticks = 1

[image_comparisons.output]
# Outliers come from the top triangle due to MSAA,
# the bottom one should produce a lot more in case something's wrong.
max_outliers = 80

[player_options]
with_renderer = { optional = false, sample_count = 4 }
viewport_dimensions = { width = 160, height = 160, scale_factor = 1 }
3 changes: 0 additions & 3 deletions tests/tests/swfs/avm2/bitmapdata_draw_filters/test.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
num_ticks = 1

# FIXME Ruffle does not use CAB in BitmapData.draw
known_failure = true

[image_comparisons.output]
tolerance = 0

Expand Down
Loading