Skip to content

Commit 617ba5a

Browse files
committed
fix: Use aligned buffer when copying buffers from texture
When an image we are trying to get from the renderer does not have width divisible by 64 the operation failed because WGPU requires buffer width to be aligned to 256 bytes. So we need to align the buffer size and copy bytes to a pixel buffer of requested size later.
1 parent 1429e88 commit 617ba5a

3 files changed

Lines changed: 35 additions & 10 deletions

File tree

galileo/examples/render_to_file.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ async fn main() -> Result<()> {
5353
.expect("cannot project extent");
5454
let center = extent.center();
5555

56-
let image_size = Size::new(512, 512);
56+
let image_size = Size::new(400, 400);
5757

5858
let width_resolution = extent.width() / image_size.width() as f64;
5959
let height_resolution = extent.height() / image_size.height() as f64;

galileo/src/layer/feature_layer/bundle_store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ impl BundleStore {
7676
self.required_update.updated();
7777
}
7878

79-
pub(super) fn packed(&self) -> Vec<BundleToDraw> {
79+
pub(super) fn packed(&self) -> Vec<BundleToDraw<'_>> {
8080
self.packed
8181
.values()
8282
.map(|v| BundleToDraw::with_opacity(&**v, 1.0))

galileo/src/render/wgpu/mod.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use wgpu::{
1818
Origin3d, Queue, RenderPassDepthStencilAttachment, StoreOp, Surface, SurfaceConfiguration,
1919
SurfaceError, SurfaceTexture, TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo,
2020
Texture, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
21-
TextureView, TextureViewDescriptor, WasmNotSendSync,
21+
TextureView, TextureViewDescriptor, WasmNotSendSync, COPY_BYTES_PER_ROW_ALIGNMENT,
2222
};
2323

2424
use super::render_bundle::screen_set::{RenderSetState, ScreenSetData};
@@ -543,8 +543,16 @@ impl WgpuRenderer {
543543
return Err(SurfaceError::Lost);
544544
};
545545

546-
let size = renderer_targets.render_target.size();
547-
let buffer_size = (size.width() * size.height() * size_of::<u32>() as u32) as BufferAddress;
546+
let render_target_size = renderer_targets.render_target.size();
547+
548+
const RGBA_BYTES_PER_PIXEL: u32 = 4;
549+
let bytes_per_row = render_target_size.width() * RGBA_BYTES_PER_PIXEL;
550+
let bytes_per_row_aligned = match bytes_per_row / COPY_BYTES_PER_ROW_ALIGNMENT {
551+
0 => bytes_per_row,
552+
v => (v + 1) * COPY_BYTES_PER_ROW_ALIGNMENT,
553+
};
554+
555+
let buffer_size = (bytes_per_row_aligned * render_target_size.height()) as BufferAddress;
548556
let buffer_desc = BufferDescriptor {
549557
size: buffer_size,
550558
usage: BufferUsages::COPY_DST | BufferUsages::MAP_READ,
@@ -569,13 +577,13 @@ impl WgpuRenderer {
569577
buffer: &buffer,
570578
layout: TexelCopyBufferLayout {
571579
offset: 0,
572-
bytes_per_row: Some(size_of::<u32>() as u32 * size.width()),
573-
rows_per_image: Some(size.height()),
580+
bytes_per_row: Some(bytes_per_row_aligned),
581+
rows_per_image: Some(render_target_size.height()),
574582
},
575583
},
576584
Extent3d {
577-
width: size.width(),
578-
height: size.height(),
585+
width: render_target_size.width(),
586+
height: render_target_size.height(),
579587
depth_or_array_layers: 1,
580588
},
581589
);
@@ -609,7 +617,24 @@ impl WgpuRenderer {
609617
}
610618

611619
let data = buffer_slice.get_mapped_range();
612-
Ok(data.to_vec())
620+
let mut pixels = vec![
621+
0u8;
622+
(render_target_size.width() * render_target_size.height() * RGBA_BYTES_PER_PIXEL)
623+
as usize
624+
];
625+
626+
for row_index in 0..render_target_size.height() {
627+
let first_byte_index_buf = (row_index * bytes_per_row_aligned) as usize;
628+
let last_byte_index_buf = first_byte_index_buf + bytes_per_row as usize;
629+
630+
let first_byte_index_pix = (row_index * bytes_per_row) as usize;
631+
let last_byte_index_pix = first_byte_index_pix + bytes_per_row as usize;
632+
633+
pixels[first_byte_index_pix..last_byte_index_pix]
634+
.copy_from_slice(&data[first_byte_index_buf..last_byte_index_buf]);
635+
}
636+
637+
Ok(pixels)
613638
}
614639

615640
/// Renders the map to the given texture.

0 commit comments

Comments
 (0)