Skip to content

Commit 8eb000c

Browse files
committed
render: Always copy directly to wgpu buffer in CopyBitmapToTexture.
Avoids allocating a temporary Vec when the texture needs to be padded.
1 parent dcf6d35 commit 8eb000c

File tree

1 file changed

+27
-25
lines changed
  • render/wgpu/src/context3d

1 file changed

+27
-25
lines changed

render/wgpu/src/context3d/mod.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use ruffle_render::backend::{
55
use ruffle_render::bitmap::BitmapHandle;
66
use ruffle_render::error::Error;
77
use std::any::Any;
8-
use std::borrow::Cow;
98
use std::cell::Cell;
109
use swf::{Rectangle, Twips};
1110

@@ -1007,42 +1006,45 @@ impl Context3D for WgpuContext3D {
10071006
// BitmapData's gpu texture might be modified before we actually submit
10081007
// `buffer_command_encoder` to the device.
10091008
let dest_format = dest.texture.format();
1010-
let mut bytes_per_row = dest_format.block_copy_size(None).unwrap()
1009+
let src_bytes_per_row = dest_format.block_copy_size(None).unwrap()
10111010
* (source_width / dest_format.block_dimensions().0);
10121011

10131012
let rows_per_image = source_height / dest_format.block_dimensions().1;
10141013

10151014
// Wgpu requires us to pad the image rows to a multiple of COPY_BYTES_PER_ROW_ALIGNMENT
1016-
let source = if (source_width * 4) % COPY_BYTES_PER_ROW_ALIGNMENT != 0
1017-
&& matches!(dest.texture.format(), wgpu::TextureFormat::Rgba8Unorm)
1018-
{
1019-
let padded: Vec<u8> = source
1020-
.chunks_exact(source_width as usize * 4)
1021-
.flat_map(|row| {
1022-
let padding_len = COPY_BYTES_PER_ROW_ALIGNMENT as usize
1023-
- (row.len() % COPY_BYTES_PER_ROW_ALIGNMENT as usize);
1024-
row.iter()
1025-
.copied()
1026-
.chain(std::iter::repeat_n(0, padding_len))
1027-
})
1028-
.collect();
1029-
1030-
bytes_per_row = padded.len() as u32 / source_height;
1031-
1032-
Cow::Owned(padded)
1033-
} else {
1034-
Cow::Borrowed(source)
1035-
};
1015+
let dest_bytes_per_row =
1016+
if matches!(dest.texture.format(), wgpu::TextureFormat::Rgba8Unorm) {
1017+
(source_width * 4).next_multiple_of(COPY_BYTES_PER_ROW_ALIGNMENT)
1018+
} else {
1019+
src_bytes_per_row
1020+
};
1021+
let dest_size = dest_bytes_per_row as u64 * rows_per_image as u64;
1022+
assert!(
1023+
dest_bytes_per_row >= src_bytes_per_row && dest_size >= source.len() as u64
1024+
);
10361025

10371026
let texture_buffer = self.descriptors.device.create_buffer(&BufferDescriptor {
10381027
label: None,
1039-
size: source.len() as u64,
1028+
size: dest_size,
10401029
usage: BufferUsages::COPY_SRC,
10411030
mapped_at_creation: true,
10421031
});
10431032

10441033
let mut texture_buffer_view = texture_buffer.slice(..).get_mapped_range_mut();
1045-
texture_buffer_view.copy_from_slice(&source);
1034+
if dest_bytes_per_row == src_bytes_per_row {
1035+
// No padding, we can copy everything in one go.
1036+
texture_buffer_view.copy_from_slice(source);
1037+
} else {
1038+
// Copy row by row.
1039+
for (dest, src) in texture_buffer_view
1040+
.chunks_exact_mut(dest_bytes_per_row as usize)
1041+
.zip(source.chunks_exact(src_bytes_per_row as usize))
1042+
{
1043+
let (dest, padding) = dest.split_at_mut(src_bytes_per_row as usize);
1044+
dest.copy_from_slice(src);
1045+
padding.fill(0);
1046+
}
1047+
}
10461048
drop(texture_buffer_view);
10471049
texture_buffer.unmap();
10481050

@@ -1052,7 +1054,7 @@ impl Context3D for WgpuContext3D {
10521054
// The copy source uses the padded image data, with larger rows
10531055
layout: wgpu::TexelCopyBufferLayout {
10541056
offset: 0,
1055-
bytes_per_row: Some(bytes_per_row),
1057+
bytes_per_row: Some(dest_bytes_per_row),
10561058
rows_per_image: Some(rows_per_image),
10571059
},
10581060
},

0 commit comments

Comments
 (0)