core: Make `BitmapHandle` hold a trait object instead of an id
`BitmapHandle` now holds `Arc<dyn BitmapHandleImpl>`. This allows us to move all of the per-bitmap backend data into `BitmapHandle`, instead of holding an id to a backend-specific hashmap. This fixes the memory leak issue with bitmaps. Once the AVM side of a bitmap (`Bitmap`/`BitmapData`) gets garbage-collected, the `BitmapHandle` will get dropped, freeing all of the GPU resources assoicated with the bitmap.
This commit is contained in:
parent
0861153626
commit
1b3070ab85
|
@ -3489,6 +3489,7 @@ dependencies = [
|
|||
name = "ruffle_render_canvas"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"downcast-rs",
|
||||
"fnv",
|
||||
"gc-arena",
|
||||
"js-sys",
|
||||
|
@ -3505,6 +3506,7 @@ name = "ruffle_render_webgl"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"downcast-rs",
|
||||
"fnv",
|
||||
"gc-arena",
|
||||
"js-sys",
|
||||
|
|
|
@ -57,9 +57,7 @@ impl<'gc> BitmapDataObject<'gc> {
|
|||
}
|
||||
|
||||
pub fn dispose(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
|
||||
self.bitmap_data()
|
||||
.write(context.gc_context)
|
||||
.dispose(context.renderer);
|
||||
self.bitmap_data().write(context.gc_context).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -818,9 +818,7 @@ pub fn dispose<'gc>(
|
|||
if let Some(bitmap_data) = this.and_then(|this| this.as_bitmap_data()) {
|
||||
// Don't check if we've already disposed this BitmapData - 'BitmapData.dispose()' can be called
|
||||
// multiple times
|
||||
bitmap_data
|
||||
.write(activation.context.gc_context)
|
||||
.dispose(activation.context.renderer);
|
||||
bitmap_data.write(activation.context.gc_context).dispose();
|
||||
}
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
|
|
@ -273,7 +273,7 @@ impl<'gc> Context3DObject<'gc> {
|
|||
if context3d.should_render() {
|
||||
let handle = context3d.bitmap_handle();
|
||||
context.commands.render_bitmap(
|
||||
handle,
|
||||
&handle,
|
||||
// FIXME - apply x and y translation from Stage3D
|
||||
&Transform::default(),
|
||||
false,
|
||||
|
|
|
@ -217,14 +217,11 @@ impl<'gc> BitmapData<'gc> {
|
|||
self.disposed
|
||||
}
|
||||
|
||||
pub fn dispose(&mut self, renderer: &mut dyn RenderBackend) {
|
||||
pub fn dispose(&mut self) {
|
||||
self.width = 0;
|
||||
self.height = 0;
|
||||
self.pixels.clear();
|
||||
if let Some(handle) = self.bitmap_handle {
|
||||
renderer.unregister_bitmap(handle);
|
||||
self.bitmap_handle = None;
|
||||
}
|
||||
self.bitmap_handle = None;
|
||||
// There's no longer a handle to update
|
||||
self.dirty = false;
|
||||
self.disposed = true;
|
||||
|
@ -245,7 +242,7 @@ impl<'gc> BitmapData<'gc> {
|
|||
self.bitmap_handle = bitmap_handle.ok();
|
||||
}
|
||||
|
||||
self.bitmap_handle
|
||||
self.bitmap_handle.clone()
|
||||
}
|
||||
|
||||
pub fn transparency(&self) -> bool {
|
||||
|
@ -914,7 +911,7 @@ impl<'gc> BitmapData<'gc> {
|
|||
let handle = self.bitmap_handle(context.renderer).unwrap();
|
||||
if self.dirty() {
|
||||
if let Err(e) = context.renderer.update_texture(
|
||||
handle,
|
||||
&handle,
|
||||
self.width(),
|
||||
self.height(),
|
||||
self.pixels_rgba(),
|
||||
|
@ -1028,7 +1025,7 @@ impl<'gc> BitmapData<'gc> {
|
|||
bitmap_data.update_dirty_texture(&mut render_context);
|
||||
let bitmap_handle = bitmap_data.bitmap_handle(render_context.renderer).unwrap();
|
||||
render_context.commands.render_bitmap(
|
||||
bitmap_handle,
|
||||
&bitmap_handle,
|
||||
render_context.transform_stack.transform(),
|
||||
smoothing,
|
||||
);
|
||||
|
|
|
@ -140,7 +140,7 @@ impl<'gc> Bitmap<'gc> {
|
|||
|
||||
#[allow(dead_code)]
|
||||
pub fn bitmap_handle(self) -> Option<BitmapHandle> {
|
||||
self.0.read().bitmap_handle
|
||||
self.0.read().bitmap_handle.clone()
|
||||
}
|
||||
|
||||
pub fn width(self) -> u16 {
|
||||
|
@ -306,7 +306,7 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> {
|
|||
}
|
||||
|
||||
let bitmap_data = self.0.read();
|
||||
if let Some(bitmap_handle) = bitmap_data.bitmap_handle {
|
||||
if let Some(bitmap_handle) = &bitmap_data.bitmap_handle {
|
||||
if let Some(inner_bitmap_data) = bitmap_data.bitmap_data {
|
||||
if let Ok(mut bd) = inner_bitmap_data.try_write(context.gc_context) {
|
||||
bd.update_dirty_texture(context);
|
||||
|
@ -316,7 +316,7 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> {
|
|||
}
|
||||
|
||||
context.commands.render_bitmap(
|
||||
bitmap_handle,
|
||||
&bitmap_handle,
|
||||
context.transform_stack.transform(),
|
||||
bitmap_data.smoothing,
|
||||
);
|
||||
|
|
|
@ -467,7 +467,7 @@ impl<'gc> TDisplayObject<'gc> for Video<'gc> {
|
|||
|
||||
context
|
||||
.commands
|
||||
.render_bitmap(bitmap.handle, &transform, smoothing);
|
||||
.render_bitmap(&bitmap.handle, &transform, smoothing);
|
||||
} else {
|
||||
log::warn!("Video has no decoded frame to render.");
|
||||
}
|
||||
|
|
|
@ -409,7 +409,7 @@ impl BitmapSource for Drawing {
|
|||
})
|
||||
}
|
||||
fn bitmap_handle(&self, id: u16, _backend: &mut dyn RenderBackend) -> Option<BitmapHandle> {
|
||||
self.bitmaps.get(id as usize).map(|bm| bm.handle)
|
||||
self.bitmaps.get(id as usize).map(|bm| bm.handle.clone())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ fnv = "1.0.7"
|
|||
ruffle_render = { path = "..", features = ["web"] }
|
||||
gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" }
|
||||
swf = { path = "../../swf" }
|
||||
downcast-rs = "1.2.0"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.60"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use downcast_rs::Downcast;
|
||||
use gc_arena::MutationContext;
|
||||
use ruffle_render::backend::null::NullBitmapSource;
|
||||
use ruffle_render::backend::{
|
||||
|
@ -28,12 +30,10 @@ pub struct WebCanvasRenderBackend {
|
|||
context: CanvasRenderingContext2d,
|
||||
color_matrix: Element,
|
||||
shapes: Vec<ShapeData>,
|
||||
bitmaps: FnvHashMap<BitmapHandle, BitmapData>,
|
||||
viewport_width: u32,
|
||||
viewport_height: u32,
|
||||
rect: Path2d,
|
||||
mask_state: MaskState,
|
||||
next_bitmap_handle: BitmapHandle,
|
||||
blend_modes: Vec<BlendMode>,
|
||||
|
||||
// This is currnetly unused - we just store it to report
|
||||
|
@ -135,6 +135,7 @@ struct CanvasBitmap {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct BitmapData {
|
||||
bitmap: Bitmap,
|
||||
image_data: ImageData,
|
||||
|
@ -142,6 +143,12 @@ struct BitmapData {
|
|||
context: CanvasRenderingContext2d,
|
||||
}
|
||||
|
||||
impl ruffle_render::bitmap::BitmapHandleImpl for BitmapData {}
|
||||
|
||||
fn as_bitmap_data(handle: &BitmapHandle) -> &BitmapData {
|
||||
handle.as_any().downcast_ref::<BitmapData>().unwrap()
|
||||
}
|
||||
|
||||
impl BitmapData {
|
||||
/// Puts the image data into a newly created <canvas>, and caches it.
|
||||
fn new(bitmap: Bitmap) -> Result<Self, JsValue> {
|
||||
|
@ -175,6 +182,19 @@ impl BitmapData {
|
|||
context,
|
||||
})
|
||||
}
|
||||
|
||||
fn update_pixels(&self, bitmap: Bitmap) -> Result<(), JsValue> {
|
||||
let bitmap = bitmap.to_rgba();
|
||||
let image_data =
|
||||
ImageData::new_with_u8_clamped_array(Clamped(bitmap.data()), bitmap.width())
|
||||
.into_js_result()?;
|
||||
self.canvas.set_width(bitmap.width());
|
||||
self.canvas.set_height(bitmap.height());
|
||||
self.context
|
||||
.put_image_data(&image_data, 0.0, 0.0)
|
||||
.into_js_result()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WebCanvasRenderBackend {
|
||||
|
@ -269,13 +289,11 @@ impl WebCanvasRenderBackend {
|
|||
color_matrix,
|
||||
context,
|
||||
shapes: vec![],
|
||||
bitmaps: Default::default(),
|
||||
viewport_width: 0,
|
||||
viewport_height: 0,
|
||||
viewport_scale_factor: 1.0,
|
||||
rect,
|
||||
mask_state: MaskState::DrawContent,
|
||||
next_bitmap_handle: BitmapHandle(0),
|
||||
blend_modes: vec![BlendMode::Normal],
|
||||
};
|
||||
Ok(renderer)
|
||||
|
@ -440,31 +458,20 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
}
|
||||
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
let handle = self.next_bitmap_handle;
|
||||
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||
let bitmap_data = BitmapData::new(bitmap).map_err(Error::JavascriptError)?;
|
||||
self.bitmaps.insert(handle, bitmap_data);
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) {
|
||||
self.bitmaps.remove(&bitmap);
|
||||
Ok(BitmapHandle(Arc::new(bitmap_data)))
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
handle: &BitmapHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<(), Error> {
|
||||
// TODO: Could be optimized to a single put_image_data call
|
||||
// in case it is already stored as a canvas+context.
|
||||
self.bitmaps.insert(
|
||||
handle,
|
||||
BitmapData::new(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))
|
||||
.map_err(Error::JavascriptError)?,
|
||||
);
|
||||
let data = as_bitmap_data(handle);
|
||||
data.update_pixels(Bitmap::new(width, height, BitmapFormat::Rgba, rgba))
|
||||
.map_err(Error::JavascriptError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -481,8 +488,8 @@ impl RenderBackend for WebCanvasRenderBackend {
|
|||
}
|
||||
}
|
||||
|
||||
impl CommandHandler for WebCanvasRenderBackend {
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
impl<'a> CommandHandler<'a> for WebCanvasRenderBackend {
|
||||
fn render_bitmap(&mut self, bitmap: &BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
if self.mask_state == MaskState::ClearMask {
|
||||
return;
|
||||
}
|
||||
|
@ -491,11 +498,10 @@ impl CommandHandler for WebCanvasRenderBackend {
|
|||
|
||||
self.set_transform(&transform.matrix);
|
||||
self.set_color_filter(transform);
|
||||
if let Some(bitmap) = self.bitmaps.get(&bitmap) {
|
||||
let _ = self
|
||||
.context
|
||||
.draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0);
|
||||
}
|
||||
let bitmap = as_bitmap_data(bitmap);
|
||||
let _ = self
|
||||
.context
|
||||
.draw_image_with_html_canvas_element(&bitmap.canvas, 0.0, 0.0);
|
||||
self.clear_color_filter();
|
||||
}
|
||||
|
||||
|
@ -1149,10 +1155,8 @@ fn create_bitmap_pattern(
|
|||
bitmap_source: &dyn BitmapSource,
|
||||
backend: &mut WebCanvasRenderBackend,
|
||||
) -> Option<CanvasBitmap> {
|
||||
if let Some(bitmap) = bitmap_source
|
||||
.bitmap_handle(id, backend)
|
||||
.and_then(|handle| backend.bitmaps.get(&handle))
|
||||
{
|
||||
if let Some(handle) = bitmap_source.bitmap_handle(id, backend) {
|
||||
let bitmap = as_bitmap_data(&handle);
|
||||
let repeat = if !is_repeating {
|
||||
// NOTE: The WebGL backend does clamping in this case, just like
|
||||
// Flash Player, but CanvasPattern has no such option...
|
||||
|
|
|
@ -47,12 +47,9 @@ pub trait RenderBackend: Downcast {
|
|||
fn submit_frame(&mut self, clear: swf::Color, commands: CommandList);
|
||||
|
||||
fn register_bitmap(&mut self, bitmap: Bitmap) -> Result<BitmapHandle, Error>;
|
||||
// Frees memory used by the bitmap. After this call, `handle` can no longer
|
||||
// be used.
|
||||
fn unregister_bitmap(&mut self, handle: BitmapHandle);
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
bitmap: BitmapHandle,
|
||||
bitmap: &BitmapHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::backend::{RenderBackend, ShapeHandle, ViewportDimensions};
|
||||
use crate::bitmap::{Bitmap, BitmapHandle, BitmapSize, BitmapSource};
|
||||
use crate::bitmap::{Bitmap, BitmapHandle, BitmapHandleImpl, BitmapSize, BitmapSource};
|
||||
use crate::commands::CommandList;
|
||||
use crate::error::Error;
|
||||
use crate::shape_utils::DistilledShape;
|
||||
|
@ -28,6 +30,9 @@ impl NullRenderer {
|
|||
Self { dimensions }
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
struct NullBitmapHandle;
|
||||
impl BitmapHandleImpl for NullBitmapHandle {}
|
||||
|
||||
impl RenderBackend for NullRenderer {
|
||||
fn viewport_dimensions(&self) -> ViewportDimensions {
|
||||
|
@ -66,13 +71,12 @@ impl RenderBackend for NullRenderer {
|
|||
|
||||
fn submit_frame(&mut self, _clear: Color, _commands: CommandList) {}
|
||||
fn register_bitmap(&mut self, _bitmap: Bitmap) -> Result<BitmapHandle, Error> {
|
||||
Ok(BitmapHandle(0))
|
||||
Ok(BitmapHandle(Arc::new(NullBitmapHandle)))
|
||||
}
|
||||
fn unregister_bitmap(&mut self, _bitmap: BitmapHandle) {}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
_bitmap: BitmapHandle,
|
||||
_bitmap: &BitmapHandle,
|
||||
_width: u32,
|
||||
_height: u32,
|
||||
_rgba: Vec<u8>,
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use downcast_rs::{impl_downcast, Downcast};
|
||||
|
||||
use crate::backend::RenderBackend;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct BitmapHandle(pub usize);
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BitmapHandle(pub Arc<dyn BitmapHandleImpl>);
|
||||
|
||||
pub trait BitmapHandleImpl: Downcast + Debug {}
|
||||
impl_downcast!(BitmapHandleImpl);
|
||||
|
||||
/// Info returned by the `register_bitmap` methods.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BitmapInfo {
|
||||
pub handle: BitmapHandle,
|
||||
|
|
|
@ -4,8 +4,8 @@ use crate::matrix::Matrix;
|
|||
use crate::transform::Transform;
|
||||
use swf::{BlendMode, Color};
|
||||
|
||||
pub trait CommandHandler {
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool);
|
||||
pub trait CommandHandler<'a> {
|
||||
fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool);
|
||||
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform);
|
||||
fn draw_rect(&mut self, color: Color, matrix: &Matrix);
|
||||
fn push_mask(&mut self);
|
||||
|
@ -25,33 +25,33 @@ impl CommandList {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn execute(self, handler: &mut impl CommandHandler) {
|
||||
for command in self.0 {
|
||||
pub fn execute<'a>(&'a self, handler: &mut impl CommandHandler<'a>) {
|
||||
for command in &self.0 {
|
||||
match command {
|
||||
Command::RenderBitmap {
|
||||
bitmap,
|
||||
transform,
|
||||
smoothing,
|
||||
} => handler.render_bitmap(bitmap, &transform, smoothing),
|
||||
} => handler.render_bitmap(bitmap, &transform, *smoothing),
|
||||
Command::RenderShape { shape, transform } => {
|
||||
handler.render_shape(shape, &transform)
|
||||
handler.render_shape(*shape, &transform)
|
||||
}
|
||||
Command::DrawRect { color, matrix } => handler.draw_rect(color, &matrix),
|
||||
Command::DrawRect { color, matrix } => handler.draw_rect(color.clone(), &matrix),
|
||||
Command::PushMask => handler.push_mask(),
|
||||
Command::ActivateMask => handler.activate_mask(),
|
||||
Command::DeactivateMask => handler.deactivate_mask(),
|
||||
Command::PopMask => handler.pop_mask(),
|
||||
Command::PushBlendMode(blend) => handler.push_blend_mode(blend),
|
||||
Command::PushBlendMode(blend) => handler.push_blend_mode(*blend),
|
||||
Command::PopBlendMode => handler.pop_blend_mode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandHandler for CommandList {
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
impl<'a> CommandHandler<'a> for CommandList {
|
||||
fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
self.0.push(Command::RenderBitmap {
|
||||
bitmap,
|
||||
bitmap: bitmap.clone(),
|
||||
transform: transform.clone(),
|
||||
smoothing,
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ gc-arena = { git = "https://github.com/ruffle-rs/gc-arena" }
|
|||
fnv = "1.0.7"
|
||||
swf = { path = "../../swf" }
|
||||
thiserror = "1.0"
|
||||
downcast-rs = "1.2.0"
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.60"
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use fnv::FnvHashMap;
|
||||
|
||||
use downcast_rs::Downcast;
|
||||
use gc_arena::MutationContext;
|
||||
use ruffle_render::backend::null::NullBitmapSource;
|
||||
use ruffle_render::backend::{
|
||||
Context3D, Context3DCommand, RenderBackend, ShapeHandle, ViewportDimensions,
|
||||
};
|
||||
use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapSource};
|
||||
use ruffle_render::bitmap::{Bitmap, BitmapFormat, BitmapHandle, BitmapHandleImpl, BitmapSource};
|
||||
use ruffle_render::commands::{CommandHandler, CommandList};
|
||||
use ruffle_render::error::Error as BitmapError;
|
||||
use ruffle_render::shape_utils::DistilledShape;
|
||||
|
@ -17,6 +18,7 @@ use ruffle_render::tessellator::{
|
|||
};
|
||||
use ruffle_render::transform::Transform;
|
||||
use ruffle_web_common::{JsError, JsResult};
|
||||
use std::sync::Arc;
|
||||
use swf::{BlendMode, Color};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
@ -140,14 +142,12 @@ pub struct WebGlRenderBackend {
|
|||
renderbuffer_height: i32,
|
||||
view_matrix: [[f32; 4]; 4],
|
||||
|
||||
bitmap_registry: FnvHashMap<BitmapHandle, RegistryData>,
|
||||
next_bitmap_handle: BitmapHandle,
|
||||
|
||||
// This is currently unused - we just hold on to it
|
||||
// to expose via `get_viewport_dimensions`
|
||||
viewport_scale_factor: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RegistryData {
|
||||
gl: Gl,
|
||||
bitmap: Bitmap,
|
||||
|
@ -160,6 +160,12 @@ impl Drop for RegistryData {
|
|||
}
|
||||
}
|
||||
|
||||
impl BitmapHandleImpl for RegistryData {}
|
||||
|
||||
fn as_registry_data(handle: &BitmapHandle) -> &RegistryData {
|
||||
handle.as_any().downcast_ref::<RegistryData>().unwrap()
|
||||
}
|
||||
|
||||
const MAX_GRADIENT_COLORS: usize = 15;
|
||||
|
||||
impl WebGlRenderBackend {
|
||||
|
@ -311,8 +317,6 @@ impl WebGlRenderBackend {
|
|||
blend_modes: vec![],
|
||||
mult_color: None,
|
||||
add_color: None,
|
||||
bitmap_registry: Default::default(),
|
||||
next_bitmap_handle: BitmapHandle(0),
|
||||
|
||||
viewport_scale_factor: 1.0,
|
||||
};
|
||||
|
@ -404,8 +408,7 @@ impl WebGlRenderBackend {
|
|||
draw_type: if program.program == self.bitmap_program.program {
|
||||
DrawType::Bitmap(BitmapDraw {
|
||||
matrix: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
||||
handle: BitmapHandle(0),
|
||||
|
||||
handle: None,
|
||||
is_smoothed: true,
|
||||
is_repeating: false,
|
||||
})
|
||||
|
@ -668,7 +671,7 @@ impl WebGlRenderBackend {
|
|||
TessDrawType::Bitmap(bitmap) => Draw {
|
||||
draw_type: DrawType::Bitmap(BitmapDraw {
|
||||
matrix: bitmap.matrix,
|
||||
handle: bitmap_source.bitmap_handle(bitmap.bitmap_id, self).unwrap(),
|
||||
handle: bitmap_source.bitmap_handle(bitmap.bitmap_id, self),
|
||||
is_smoothed: bitmap.is_smoothed,
|
||||
is_repeating: bitmap.is_repeating,
|
||||
}),
|
||||
|
@ -1024,36 +1027,21 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, Gl::LINEAR as i32);
|
||||
|
||||
let handle = self.next_bitmap_handle;
|
||||
self.next_bitmap_handle = BitmapHandle(self.next_bitmap_handle.0 + 1);
|
||||
self.bitmap_registry.insert(
|
||||
handle,
|
||||
RegistryData {
|
||||
gl: self.gl.clone(),
|
||||
bitmap,
|
||||
texture,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, bitmap: BitmapHandle) {
|
||||
self.bitmap_registry.remove(&bitmap);
|
||||
Ok(BitmapHandle(Arc::new(RegistryData {
|
||||
gl: self.gl.clone(),
|
||||
bitmap,
|
||||
texture,
|
||||
})))
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
handle: &BitmapHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<(), BitmapError> {
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture
|
||||
} else {
|
||||
return Err(BitmapError::UnknownHandle(handle));
|
||||
};
|
||||
let texture = &as_registry_data(handle).texture;
|
||||
|
||||
self.gl.bind_texture(Gl::TEXTURE_2D, Some(&texture));
|
||||
|
||||
|
@ -1088,97 +1076,95 @@ impl RenderBackend for WebGlRenderBackend {
|
|||
}
|
||||
}
|
||||
|
||||
impl CommandHandler for WebGlRenderBackend {
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
impl<'a> CommandHandler<'a> for WebGlRenderBackend {
|
||||
fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
self.set_stencil_state();
|
||||
if let Some(entry) = self.bitmap_registry.get(&bitmap) {
|
||||
// Adjust the quad draw to use the target bitmap.
|
||||
let mesh = &self.meshes[self.bitmap_quad_shape.0];
|
||||
let draw = &mesh.draws[0];
|
||||
let bitmap_matrix = if let DrawType::Bitmap(BitmapDraw { matrix, .. }) = &draw.draw_type
|
||||
{
|
||||
matrix
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let entry = as_registry_data(bitmap);
|
||||
// Adjust the quad draw to use the target bitmap.
|
||||
let mesh = &self.meshes[self.bitmap_quad_shape.0];
|
||||
let draw = &mesh.draws[0];
|
||||
let bitmap_matrix = if let DrawType::Bitmap(BitmapDraw { matrix, .. }) = &draw.draw_type {
|
||||
matrix
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
// Scale the quad to the bitmap's dimensions.
|
||||
let matrix = transform.matrix
|
||||
* ruffle_render::matrix::Matrix::scale(
|
||||
entry.bitmap.width() as f32,
|
||||
entry.bitmap.height() as f32,
|
||||
);
|
||||
// Scale the quad to the bitmap's dimensions.
|
||||
let matrix = transform.matrix
|
||||
* ruffle_render::matrix::Matrix::scale(
|
||||
entry.bitmap.width() as f32,
|
||||
entry.bitmap.height() as f32,
|
||||
);
|
||||
|
||||
let world_matrix = [
|
||||
[matrix.a, matrix.b, 0.0, 0.0],
|
||||
[matrix.c, matrix.d, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[
|
||||
matrix.tx.to_pixels() as f32,
|
||||
matrix.ty.to_pixels() as f32,
|
||||
0.0,
|
||||
1.0,
|
||||
],
|
||||
];
|
||||
let world_matrix = [
|
||||
[matrix.a, matrix.b, 0.0, 0.0],
|
||||
[matrix.c, matrix.d, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[
|
||||
matrix.tx.to_pixels() as f32,
|
||||
matrix.ty.to_pixels() as f32,
|
||||
0.0,
|
||||
1.0,
|
||||
],
|
||||
];
|
||||
|
||||
let mult_color = transform.color_transform.mult_rgba_normalized();
|
||||
let add_color = transform.color_transform.add_rgba_normalized();
|
||||
let mult_color = transform.color_transform.mult_rgba_normalized();
|
||||
let add_color = transform.color_transform.add_rgba_normalized();
|
||||
|
||||
self.bind_vertex_array(Some(&draw.vao));
|
||||
self.bind_vertex_array(Some(&draw.vao));
|
||||
|
||||
let program = &self.bitmap_program;
|
||||
let program = &self.bitmap_program;
|
||||
|
||||
// Set common render state, while minimizing unnecessary state changes.
|
||||
// TODO: Using designated layout specifiers in WebGL2/OpenGL ES 3, we could guarantee that uniforms
|
||||
// are in the same location between shaders, and avoid changing them unless necessary.
|
||||
if program as *const ShaderProgram != self.active_program {
|
||||
self.gl.use_program(Some(&program.program));
|
||||
self.active_program = program as *const ShaderProgram;
|
||||
// Set common render state, while minimizing unnecessary state changes.
|
||||
// TODO: Using designated layout specifiers in WebGL2/OpenGL ES 3, we could guarantee that uniforms
|
||||
// are in the same location between shaders, and avoid changing them unless necessary.
|
||||
if program as *const ShaderProgram != self.active_program {
|
||||
self.gl.use_program(Some(&program.program));
|
||||
self.active_program = program as *const ShaderProgram;
|
||||
|
||||
program.uniform_matrix4fv(&self.gl, ShaderUniform::ViewMatrix, &self.view_matrix);
|
||||
program.uniform_matrix4fv(&self.gl, ShaderUniform::ViewMatrix, &self.view_matrix);
|
||||
|
||||
self.mult_color = None;
|
||||
self.add_color = None;
|
||||
}
|
||||
|
||||
program.uniform_matrix4fv(&self.gl, ShaderUniform::WorldMatrix, &world_matrix);
|
||||
if Some(mult_color) != self.mult_color {
|
||||
program.uniform4fv(&self.gl, ShaderUniform::MultColor, &mult_color);
|
||||
self.mult_color = Some(mult_color);
|
||||
}
|
||||
if Some(add_color) != self.add_color {
|
||||
program.uniform4fv(&self.gl, ShaderUniform::AddColor, &add_color);
|
||||
self.add_color = Some(add_color);
|
||||
}
|
||||
|
||||
program.uniform_matrix3fv(&self.gl, ShaderUniform::TextureMatrix, bitmap_matrix);
|
||||
|
||||
// Bind texture.
|
||||
self.gl.active_texture(Gl::TEXTURE0);
|
||||
self.gl.bind_texture(Gl::TEXTURE_2D, Some(&entry.texture));
|
||||
program.uniform1i(&self.gl, ShaderUniform::BitmapTexture, 0);
|
||||
|
||||
// Set texture parameters.
|
||||
let filter = if smoothing {
|
||||
Gl::LINEAR as i32
|
||||
} else {
|
||||
Gl::NEAREST as i32
|
||||
};
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, filter);
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MIN_FILTER, filter);
|
||||
|
||||
let wrap = Gl::CLAMP_TO_EDGE as i32;
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_S, wrap);
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_T, wrap);
|
||||
|
||||
// Draw the triangles.
|
||||
self.gl
|
||||
.draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0);
|
||||
self.mult_color = None;
|
||||
self.add_color = None;
|
||||
}
|
||||
|
||||
program.uniform_matrix4fv(&self.gl, ShaderUniform::WorldMatrix, &world_matrix);
|
||||
if Some(mult_color) != self.mult_color {
|
||||
program.uniform4fv(&self.gl, ShaderUniform::MultColor, &mult_color);
|
||||
self.mult_color = Some(mult_color);
|
||||
}
|
||||
if Some(add_color) != self.add_color {
|
||||
program.uniform4fv(&self.gl, ShaderUniform::AddColor, &add_color);
|
||||
self.add_color = Some(add_color);
|
||||
}
|
||||
|
||||
program.uniform_matrix3fv(&self.gl, ShaderUniform::TextureMatrix, bitmap_matrix);
|
||||
|
||||
// Bind texture.
|
||||
self.gl.active_texture(Gl::TEXTURE0);
|
||||
self.gl.bind_texture(Gl::TEXTURE_2D, Some(&entry.texture));
|
||||
program.uniform1i(&self.gl, ShaderUniform::BitmapTexture, 0);
|
||||
|
||||
// Set texture parameters.
|
||||
let filter = if smoothing {
|
||||
Gl::LINEAR as i32
|
||||
} else {
|
||||
Gl::NEAREST as i32
|
||||
};
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MAG_FILTER, filter);
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_MIN_FILTER, filter);
|
||||
|
||||
let wrap = Gl::CLAMP_TO_EDGE as i32;
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_S, wrap);
|
||||
self.gl
|
||||
.tex_parameteri(Gl::TEXTURE_2D, Gl::TEXTURE_WRAP_T, wrap);
|
||||
|
||||
// Draw the triangles.
|
||||
self.gl
|
||||
.draw_elements_with_i32(Gl::TRIANGLES, draw.num_indices, Gl::UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
|
||||
|
@ -1281,12 +1267,7 @@ impl CommandHandler for WebGlRenderBackend {
|
|||
);
|
||||
}
|
||||
DrawType::Bitmap(bitmap) => {
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&bitmap.handle) {
|
||||
&entry.texture
|
||||
} else {
|
||||
// Bitmap not registered
|
||||
continue;
|
||||
};
|
||||
let texture = &as_registry_data(&bitmap.handle.as_ref().unwrap()).texture;
|
||||
|
||||
program.uniform_matrix3fv(
|
||||
&self.gl,
|
||||
|
@ -1485,7 +1466,7 @@ impl From<TessGradient> for Gradient {
|
|||
#[derive(Clone, Debug)]
|
||||
struct BitmapDraw {
|
||||
matrix: [[f32; 3]; 3],
|
||||
handle: BitmapHandle,
|
||||
handle: Option<BitmapHandle>,
|
||||
is_repeating: bool,
|
||||
is_smoothed: bool,
|
||||
}
|
||||
|
|
|
@ -5,10 +5,9 @@ use crate::target::RenderTargetFrame;
|
|||
use crate::target::TextureTarget;
|
||||
use crate::uniform_buffer::BufferStorage;
|
||||
use crate::{
|
||||
format_list, get_backend_names, BufferDimensions, Descriptors, Error, Globals, RenderTarget,
|
||||
SwapChainTarget, Texture, TextureOffscreen, Transforms,
|
||||
as_texture, format_list, get_backend_names, BufferDimensions, Descriptors, Error, Globals,
|
||||
RenderTarget, SwapChainTarget, Texture, TextureOffscreen, Transforms,
|
||||
};
|
||||
use fnv::FnvHashMap;
|
||||
use gc_arena::MutationContext;
|
||||
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
|
||||
use ruffle_render::backend::{Context3D, Context3DCommand};
|
||||
|
@ -34,8 +33,6 @@ pub struct WgpuRenderBackend<T: RenderTarget> {
|
|||
surface: Surface,
|
||||
meshes: Vec<Mesh>,
|
||||
shape_tessellator: ShapeTessellator,
|
||||
bitmap_registry: FnvHashMap<BitmapHandle, Texture>,
|
||||
next_bitmap_handle: BitmapHandle,
|
||||
// This is currently unused - we just store it to report in
|
||||
// `get_viewport_dimensions`
|
||||
viewport_scale_factor: f64,
|
||||
|
@ -156,9 +153,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
|||
surface,
|
||||
meshes: Vec::new(),
|
||||
shape_tessellator: ShapeTessellator::new(),
|
||||
|
||||
bitmap_registry: Default::default(),
|
||||
next_bitmap_handle: BitmapHandle(0),
|
||||
viewport_scale_factor: 1.0,
|
||||
})
|
||||
}
|
||||
|
@ -221,19 +215,6 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
|||
pub fn device(&self) -> &wgpu::Device {
|
||||
&self.descriptors.device
|
||||
}
|
||||
|
||||
pub fn bitmap_registry(&self) -> &FnvHashMap<BitmapHandle, Texture> {
|
||||
&self.bitmap_registry
|
||||
}
|
||||
|
||||
fn raw_register_bitmap(&mut self, data: Texture) -> BitmapHandle {
|
||||
let handle = self.next_bitmap_handle;
|
||||
self.next_bitmap_handle.0 += 1;
|
||||
if self.bitmap_registry.insert(handle, data).is_some() {
|
||||
panic!("Overwrote existing bitmap {:?}", handle);
|
||||
}
|
||||
handle
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||
|
@ -283,14 +264,14 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
usage: wgpu::TextureUsages::COPY_SRC,
|
||||
});
|
||||
|
||||
let handle = self.raw_register_bitmap(Texture {
|
||||
let handle = BitmapHandle(Arc::new(Texture {
|
||||
bind_linear: Default::default(),
|
||||
bind_nearest: Default::default(),
|
||||
texture: dummy_texture,
|
||||
texture_offscreen: None,
|
||||
texture: Arc::new(dummy_texture),
|
||||
texture_offscreen: Default::default(),
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
}));
|
||||
Ok(Box::new(WgpuContext3D::new(
|
||||
self.descriptors.clone(),
|
||||
handle,
|
||||
|
@ -307,14 +288,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
.as_any_mut()
|
||||
.downcast_mut::<WgpuContext3D>()
|
||||
.unwrap();
|
||||
if let Some(new_registry_data) = context.present(commands, mc) {
|
||||
// Update the registry with the new texture, which will later
|
||||
// be rendered by `Stage`
|
||||
*self
|
||||
.bitmap_registry
|
||||
.get_mut(&context.bitmap_handle())
|
||||
.unwrap() = new_registry_data;
|
||||
}
|
||||
context.present(commands, mc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -385,7 +359,6 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
&mut self.globals,
|
||||
&mut self.uniform_buffers_storage,
|
||||
&self.meshes,
|
||||
&self.bitmap_registry,
|
||||
commands,
|
||||
);
|
||||
|
||||
|
@ -444,34 +417,26 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
extent,
|
||||
);
|
||||
|
||||
let handle = self.raw_register_bitmap(Texture {
|
||||
texture,
|
||||
let handle = BitmapHandle(Arc::new(Texture {
|
||||
texture: Arc::new(texture),
|
||||
bind_linear: Default::default(),
|
||||
bind_nearest: Default::default(),
|
||||
texture_offscreen: None,
|
||||
width: extent.width,
|
||||
height: extent.height,
|
||||
});
|
||||
texture_offscreen: Default::default(),
|
||||
width: bitmap.width(),
|
||||
height: bitmap.height(),
|
||||
}));
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
fn unregister_bitmap(&mut self, handle: BitmapHandle) {
|
||||
self.bitmap_registry.remove(&handle);
|
||||
}
|
||||
|
||||
fn update_texture(
|
||||
&mut self,
|
||||
handle: BitmapHandle,
|
||||
handle: &BitmapHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
rgba: Vec<u8>,
|
||||
) -> Result<(), BitmapError> {
|
||||
let texture = if let Some(entry) = self.bitmap_registry.get(&handle) {
|
||||
&entry.texture
|
||||
} else {
|
||||
return Err(BitmapError::UnknownHandle(handle));
|
||||
};
|
||||
let texture = as_texture(handle);
|
||||
|
||||
let extent = wgpu::Extent3d {
|
||||
width,
|
||||
|
@ -481,7 +446,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
|
||||
self.descriptors.queue.write_texture(
|
||||
wgpu::ImageCopyTexture {
|
||||
texture,
|
||||
texture: &texture.texture,
|
||||
mip_level: 0,
|
||||
origin: Default::default(),
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
|
@ -505,16 +470,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
height: u32,
|
||||
commands: CommandList,
|
||||
) -> Result<Bitmap, ruffle_render::error::Error> {
|
||||
// We need ownership of `Texture` to access the non-`Clone`
|
||||
// `wgpu` fields. At the end of this method, we re-insert
|
||||
// `texture` into the map.
|
||||
//
|
||||
// This means that the target texture will be inaccessible
|
||||
// while the callback `f` is a problem. This would only be
|
||||
// an issue if a caller tried to render the target texture
|
||||
// to itself, which probably isn't supported by Flash. If it
|
||||
// is, then we could change `TextureTarget` to use an `Rc<wgpu::Texture>`
|
||||
let mut texture = self.bitmap_registry.remove(&handle).unwrap();
|
||||
let texture = as_texture(&handle);
|
||||
|
||||
let extent = wgpu::Extent3d {
|
||||
width,
|
||||
|
@ -531,7 +487,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
// many buffers / depth textures rendered at once, we could
|
||||
// try storing this data in an LRU cache, evicting entries
|
||||
// as needed.
|
||||
let mut texture_offscreen = texture.texture_offscreen.unwrap_or_else(|| {
|
||||
let texture_offscreen = texture.texture_offscreen.get_or_init(|| {
|
||||
let buffer_dimensions = BufferDimensions::new(width as usize, height as usize);
|
||||
let buffer_label = create_debug_label!("Render target buffer");
|
||||
let buffer = self
|
||||
|
@ -545,7 +501,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
mapped_at_creation: false,
|
||||
});
|
||||
TextureOffscreen {
|
||||
buffer,
|
||||
buffer: Arc::new(buffer),
|
||||
buffer_dimensions,
|
||||
surface: Surface::new(
|
||||
&self.descriptors,
|
||||
|
@ -559,10 +515,10 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
|
||||
let mut target = TextureTarget {
|
||||
size: extent,
|
||||
texture: texture.texture,
|
||||
texture: texture.texture.clone(),
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
buffer: texture_offscreen.buffer,
|
||||
buffer_dimensions: texture_offscreen.buffer_dimensions,
|
||||
buffer: texture_offscreen.buffer.clone(),
|
||||
buffer_dimensions: texture_offscreen.buffer_dimensions.clone(),
|
||||
};
|
||||
|
||||
let (old_width, old_height) = self.globals.resolution();
|
||||
|
@ -579,7 +535,6 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
&mut self.globals,
|
||||
&mut self.uniform_buffers_storage,
|
||||
&self.meshes,
|
||||
&self.bitmap_registry,
|
||||
commands,
|
||||
);
|
||||
target.submit(
|
||||
|
@ -602,11 +557,6 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
|||
});
|
||||
|
||||
self.globals.set_resolution(old_width, old_height);
|
||||
texture_offscreen.buffer = target.buffer;
|
||||
texture_offscreen.buffer_dimensions = target.buffer_dimensions;
|
||||
texture.texture_offscreen = Some(texture_offscreen);
|
||||
texture.texture = target.texture;
|
||||
self.bitmap_registry.insert(handle, texture);
|
||||
|
||||
Ok(image.unwrap())
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use crate::frame::Frame;
|
||||
use crate::mesh::{DrawType, Mesh};
|
||||
use crate::pipelines::BlendMode as ActualBlendMode;
|
||||
use crate::{ColorAdjustments, MaskState, Texture};
|
||||
use fnv::FnvHashMap;
|
||||
use crate::{as_texture, ColorAdjustments, MaskState};
|
||||
use ruffle_render::backend::ShapeHandle;
|
||||
use ruffle_render::bitmap::BitmapHandle;
|
||||
use ruffle_render::commands::CommandHandler;
|
||||
|
@ -11,7 +10,6 @@ use swf::{BlendMode, Color};
|
|||
|
||||
pub struct CommandRenderer<'a, 'b> {
|
||||
frame: &'b mut Frame<'a>,
|
||||
bitmap_registry: &'a FnvHashMap<BitmapHandle, Texture>,
|
||||
meshes: &'a Vec<Mesh>,
|
||||
quad_vertices: wgpu::BufferSlice<'a>,
|
||||
quad_indices: wgpu::BufferSlice<'a>,
|
||||
|
@ -23,13 +21,11 @@ impl<'a, 'b> CommandRenderer<'a, 'b> {
|
|||
pub fn new(
|
||||
frame: &'b mut Frame<'a>,
|
||||
meshes: &'a Vec<Mesh>,
|
||||
bitmap_registry: &'a FnvHashMap<BitmapHandle, Texture>,
|
||||
quad_vertices: wgpu::BufferSlice<'a>,
|
||||
quad_indices: wgpu::BufferSlice<'a>,
|
||||
) -> Self {
|
||||
Self {
|
||||
frame,
|
||||
bitmap_registry,
|
||||
meshes,
|
||||
quad_vertices,
|
||||
quad_indices,
|
||||
|
@ -39,32 +35,32 @@ impl<'a, 'b> CommandRenderer<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> CommandHandler for CommandRenderer<'a, 'b> {
|
||||
fn render_bitmap(&mut self, bitmap: BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
if let Some(texture) = self.bitmap_registry.get(&bitmap) {
|
||||
self.frame.apply_transform(
|
||||
&(transform.matrix
|
||||
* ruffle_render::matrix::Matrix {
|
||||
a: texture.width as f32,
|
||||
d: texture.height as f32,
|
||||
..Default::default()
|
||||
}),
|
||||
ColorAdjustments::from(transform.color_transform),
|
||||
);
|
||||
let descriptors = self.frame.descriptors();
|
||||
let bind = texture.bind_group(
|
||||
smoothing,
|
||||
&descriptors.device,
|
||||
&descriptors.bind_layouts.bitmap,
|
||||
&descriptors.quad,
|
||||
bitmap,
|
||||
&descriptors.bitmap_samplers,
|
||||
);
|
||||
impl<'a, 'b> CommandHandler<'a> for CommandRenderer<'a, 'b> {
|
||||
fn render_bitmap(&mut self, bitmap: &'a BitmapHandle, transform: &Transform, smoothing: bool) {
|
||||
let texture = as_texture(bitmap);
|
||||
|
||||
self.frame.prep_bitmap(&bind.bind_group);
|
||||
self.frame.apply_transform(
|
||||
&(transform.matrix
|
||||
* ruffle_render::matrix::Matrix {
|
||||
a: texture.width as f32,
|
||||
d: texture.height as f32,
|
||||
..Default::default()
|
||||
}),
|
||||
ColorAdjustments::from(transform.color_transform),
|
||||
);
|
||||
let descriptors = self.frame.descriptors();
|
||||
let bind = texture.bind_group(
|
||||
smoothing,
|
||||
&descriptors.device,
|
||||
&descriptors.bind_layouts.bitmap,
|
||||
&descriptors.quad,
|
||||
bitmap.clone(),
|
||||
&descriptors.bitmap_samplers,
|
||||
);
|
||||
|
||||
self.frame.draw(self.quad_vertices, self.quad_indices, 6);
|
||||
}
|
||||
self.frame.prep_bitmap(&bind.bind_group);
|
||||
|
||||
self.frame.draw(self.quad_vertices, self.quad_indices, 6);
|
||||
}
|
||||
|
||||
fn render_shape(&mut self, shape: ShapeHandle, transform: &Transform) {
|
||||
|
|
|
@ -177,14 +177,11 @@ impl WgpuContext3D {
|
|||
}
|
||||
}
|
||||
// Executes all of the given `commands` in response to a `Context3D.present` call.
|
||||
// If we needed to re-create the target Texture due to a `ConfigureBackBuffer` command,
|
||||
// then we return the new Texture.
|
||||
// If we re-used the same Texture, then we return `None`.
|
||||
pub(crate) fn present<'gc>(
|
||||
&mut self,
|
||||
commands: Vec<Context3DCommand<'gc>>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Option<Texture> {
|
||||
) {
|
||||
let mut render_command_encoder =
|
||||
self.descriptors
|
||||
.device
|
||||
|
@ -216,10 +213,6 @@ impl WgpuContext3D {
|
|||
// `clear_color`, which may be `None` even if we've seen a `Clear` command.
|
||||
let mut seen_clear_command = false;
|
||||
|
||||
// If we execute any `ConfigureBackBuffer` commands, this will store the newly-create
|
||||
// Texture.
|
||||
let mut recreated_texture = None;
|
||||
|
||||
for command in &commands {
|
||||
match command {
|
||||
Context3DCommand::Clear {
|
||||
|
@ -293,14 +286,14 @@ impl WgpuContext3D {
|
|||
finish_render_pass!(render_pass);
|
||||
self.texture_view = Some(wgpu_texture.create_view(&Default::default()));
|
||||
|
||||
recreated_texture = Some(Texture {
|
||||
texture: wgpu_texture,
|
||||
self.raw_texture_handle = BitmapHandle(Arc::new(Texture {
|
||||
texture: Arc::new(wgpu_texture),
|
||||
bind_linear: Default::default(),
|
||||
bind_nearest: Default::default(),
|
||||
texture_offscreen: None,
|
||||
texture_offscreen: Default::default(),
|
||||
width: *width,
|
||||
height: *height,
|
||||
});
|
||||
}));
|
||||
}
|
||||
Context3DCommand::UploadToIndexBuffer {
|
||||
buffer,
|
||||
|
@ -514,8 +507,6 @@ impl WgpuContext3D {
|
|||
self.buffer_staging_belt.recall();
|
||||
|
||||
self.compiled_pipeline = compiled_pipeline;
|
||||
|
||||
recreated_texture
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -548,7 +539,7 @@ pub struct VertexAttributeInfo {
|
|||
|
||||
impl Context3D for WgpuContext3D {
|
||||
fn bitmap_handle(&self) -> BitmapHandle {
|
||||
self.raw_texture_handle
|
||||
self.raw_texture_handle.clone()
|
||||
}
|
||||
fn should_render(&self) -> bool {
|
||||
// If this is None, we haven't called configureBackBuffer yet.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::bitmaps::BitmapSamplers;
|
||||
use crate::descriptors::Quad;
|
||||
use crate::globals::Globals;
|
||||
|
@ -13,7 +15,7 @@ use bytemuck::{Pod, Zeroable};
|
|||
use descriptors::Descriptors;
|
||||
use enum_map::Enum;
|
||||
use once_cell::sync::OnceCell;
|
||||
use ruffle_render::bitmap::BitmapHandle;
|
||||
use ruffle_render::bitmap::{BitmapHandle, BitmapHandleImpl};
|
||||
use ruffle_render::color_transform::ColorTransform;
|
||||
use ruffle_render::tessellator::{Gradient as TessGradient, GradientType, Vertex as TessVertex};
|
||||
pub use wgpu;
|
||||
|
@ -41,6 +43,12 @@ mod mesh;
|
|||
mod shaders;
|
||||
mod surface;
|
||||
|
||||
impl BitmapHandleImpl for Texture {}
|
||||
|
||||
pub fn as_texture(handle: &BitmapHandle) -> &Texture {
|
||||
handle.0.as_any().downcast_ref().unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)]
|
||||
pub enum MaskState {
|
||||
NoMask,
|
||||
|
@ -186,10 +194,10 @@ impl From<TessGradient> for GradientStorage {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Texture {
|
||||
texture: wgpu::Texture,
|
||||
texture: Arc<wgpu::Texture>,
|
||||
bind_linear: OnceCell<BitmapBinds>,
|
||||
bind_nearest: OnceCell<BitmapBinds>,
|
||||
texture_offscreen: Option<TextureOffscreen>,
|
||||
texture_offscreen: OnceCell<TextureOffscreen>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
@ -215,7 +223,7 @@ impl Texture {
|
|||
samplers.get_sampler(false, smoothed),
|
||||
&quad.texture_transforms,
|
||||
self.texture.create_view(&Default::default()),
|
||||
create_debug_label!("Bitmap {} bind group (smoothed: {})", handle.0, smoothed),
|
||||
create_debug_label!("Bitmap {:?} bind group (smoothed: {})", handle.0, smoothed),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -223,7 +231,7 @@ impl Texture {
|
|||
|
||||
#[derive(Debug)]
|
||||
struct TextureOffscreen {
|
||||
buffer: wgpu::Buffer,
|
||||
buffer: Arc<wgpu::Buffer>,
|
||||
buffer_dimensions: BufferDimensions,
|
||||
surface: Surface,
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::backend::WgpuRenderBackend;
|
||||
use crate::target::RenderTarget;
|
||||
use crate::{
|
||||
create_buffer_with_data, Descriptors, GradientStorage, GradientUniforms, Texture,
|
||||
as_texture, create_buffer_with_data, Descriptors, GradientStorage, GradientUniforms,
|
||||
TextureTransforms, Vertex,
|
||||
};
|
||||
|
||||
use ruffle_render::backend::RenderBackend;
|
||||
use ruffle_render::bitmap::BitmapSource;
|
||||
use ruffle_render::tessellator::{Bitmap, Draw as LyonDraw, DrawType as TessDrawType, Gradient};
|
||||
use swf::CharacterId;
|
||||
|
@ -32,7 +33,7 @@ impl Draw {
|
|||
draw_id: usize,
|
||||
) -> Self {
|
||||
let vertices: Vec<_> = draw.vertices.into_iter().map(Vertex::from).collect();
|
||||
let descriptors = backend.descriptors();
|
||||
let descriptors = backend.descriptors().clone();
|
||||
let vertex_buffer = create_buffer_with_data(
|
||||
&descriptors.device,
|
||||
bytemuck::cast_slice(&vertices),
|
||||
|
@ -63,23 +64,20 @@ impl Draw {
|
|||
num_indices: index_count,
|
||||
num_mask_indices: draw.mask_index_count,
|
||||
},
|
||||
TessDrawType::Bitmap(bitmap) => {
|
||||
let bitmap_handle = source.bitmap_handle(bitmap.bitmap_id, backend).unwrap();
|
||||
let texture = &backend.bitmap_registry()[&bitmap_handle];
|
||||
Draw {
|
||||
draw_type: DrawType::bitmap(
|
||||
&backend.descriptors(),
|
||||
bitmap,
|
||||
texture,
|
||||
shape_id,
|
||||
draw_id,
|
||||
),
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_indices: index_count,
|
||||
num_mask_indices: draw.mask_index_count,
|
||||
}
|
||||
}
|
||||
TessDrawType::Bitmap(bitmap) => Draw {
|
||||
draw_type: DrawType::bitmap(
|
||||
&descriptors,
|
||||
bitmap,
|
||||
shape_id,
|
||||
draw_id,
|
||||
source,
|
||||
backend,
|
||||
),
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_indices: index_count,
|
||||
num_mask_indices: draw.mask_index_count,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,12 +187,14 @@ impl DrawType {
|
|||
pub fn bitmap(
|
||||
descriptors: &Descriptors,
|
||||
bitmap: Bitmap,
|
||||
texture: &Texture,
|
||||
shape_id: CharacterId,
|
||||
draw_id: usize,
|
||||
source: &dyn BitmapSource,
|
||||
backend: &mut dyn RenderBackend,
|
||||
) -> Self {
|
||||
let handle = source.bitmap_handle(bitmap.bitmap_id, backend).unwrap();
|
||||
let texture = as_texture(&handle);
|
||||
let texture_view = texture.texture.create_view(&Default::default());
|
||||
|
||||
let texture_transforms = create_texture_transforms(
|
||||
&descriptors.device,
|
||||
&bitmap.matrix,
|
||||
|
|
|
@ -7,11 +7,10 @@ use crate::surface::Surface::{Direct, DirectSrgb, Resolve, ResolveSrgb};
|
|||
use crate::uniform_buffer::BufferStorage;
|
||||
use crate::utils::remove_srgb;
|
||||
use crate::{
|
||||
create_buffer_with_data, ColorAdjustments, Descriptors, Globals, Pipelines, Texture,
|
||||
TextureTransforms, Transforms, UniformBuffer,
|
||||
create_buffer_with_data, ColorAdjustments, Descriptors, Globals, Pipelines, TextureTransforms,
|
||||
Transforms, UniformBuffer,
|
||||
};
|
||||
use fnv::FnvHashMap;
|
||||
use ruffle_render::bitmap::BitmapHandle;
|
||||
|
||||
use ruffle_render::commands::CommandList;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -387,7 +386,6 @@ impl Surface {
|
|||
globals: &mut Globals,
|
||||
uniform_buffers_storage: &mut BufferStorage<Transforms>,
|
||||
meshes: &Vec<Mesh>,
|
||||
bitmap_registry: &FnvHashMap<BitmapHandle, Texture>,
|
||||
commands: CommandList,
|
||||
) -> Vec<wgpu::CommandBuffer> {
|
||||
let label = create_debug_label!("Draw encoder");
|
||||
|
@ -445,7 +443,6 @@ impl Surface {
|
|||
commands.execute(&mut CommandRenderer::new(
|
||||
&mut frame,
|
||||
meshes,
|
||||
bitmap_registry,
|
||||
descriptors.quad.vertices.slice(..),
|
||||
descriptors.quad.indices.slice(..),
|
||||
));
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::utils::BufferDimensions;
|
|||
use crate::Error;
|
||||
use ruffle_render::utils::unmultiply_alpha_rgba;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait RenderTargetFrame: Debug {
|
||||
fn into_view(self) -> wgpu::TextureView;
|
||||
|
@ -136,9 +137,9 @@ impl RenderTarget for SwapChainTarget {
|
|||
#[derive(Debug)]
|
||||
pub struct TextureTarget {
|
||||
pub size: wgpu::Extent3d,
|
||||
pub texture: wgpu::Texture,
|
||||
pub texture: Arc<wgpu::Texture>,
|
||||
pub format: wgpu::TextureFormat,
|
||||
pub buffer: wgpu::Buffer,
|
||||
pub buffer: Arc<wgpu::Buffer>,
|
||||
pub buffer_dimensions: BufferDimensions,
|
||||
}
|
||||
|
||||
|
@ -197,9 +198,9 @@ impl TextureTarget {
|
|||
});
|
||||
Ok(Self {
|
||||
size,
|
||||
texture,
|
||||
texture: Arc::new(texture),
|
||||
format,
|
||||
buffer,
|
||||
buffer: Arc::new(buffer),
|
||||
buffer_dimensions,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ pub fn create_buffer_with_data(
|
|||
}
|
||||
|
||||
// Based off wgpu example 'capture'
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BufferDimensions {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
|
|
|
@ -78,12 +78,12 @@ impl VideoBackend for SoftwareVideoBackend {
|
|||
.ok_or(Error::VideoStreamIsNotRegistered)?;
|
||||
|
||||
let frame = stream.decoder.decode_frame(encoded_frame)?;
|
||||
let handle = if let Some(bitmap) = stream.bitmap {
|
||||
let handle = if let Some(bitmap) = stream.bitmap.clone() {
|
||||
renderer.update_texture(
|
||||
bitmap,
|
||||
&bitmap,
|
||||
frame.width.into(),
|
||||
frame.height.into(),
|
||||
frame.rgba.clone(),
|
||||
frame.rgba,
|
||||
)?;
|
||||
bitmap
|
||||
} else {
|
||||
|
@ -95,7 +95,7 @@ impl VideoBackend for SoftwareVideoBackend {
|
|||
);
|
||||
renderer.register_bitmap(bitmap)?
|
||||
};
|
||||
stream.bitmap = Some(handle);
|
||||
stream.bitmap = Some(handle.clone());
|
||||
|
||||
Ok(BitmapInfo {
|
||||
handle,
|
||||
|
|
Loading…
Reference in New Issue