Created
February 24, 2023 20:04
-
-
Save Dzejkop/2d1dde8f64acc84f56ac5f0925cadf24 to your computer and use it in GitHub Desktop.
Weird Bevy perf thing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "canvas_time_test" | |
version = "0.1.0" | |
edition = "2021" | |
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
[dependencies] | |
bevy = "0.9.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod canvas { | |
use bevy::prelude::*; | |
pub trait Canvas { | |
fn set(&mut self, x: i32, y: i32, color: Color); | |
fn size(&self) -> (i32, i32); | |
fn clear(&mut self, color: Color) { | |
let (width, height) = self.size(); | |
for x in 0..width { | |
for y in 0..height { | |
self.set(x, y, color); | |
} | |
} | |
} | |
fn rect(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: Color) { | |
for x in x1..=x2 { | |
for y in y1..=y2 { | |
self.set(x, y, color); | |
} | |
} | |
} | |
} | |
impl<'a, T> Canvas for &'a mut T | |
where | |
T: Canvas, | |
{ | |
fn set(&mut self, x: i32, y: i32, color: Color) { | |
T::set(self, x, y, color); | |
} | |
fn size(&self) -> (i32, i32) { | |
T::size(self) | |
} | |
} | |
} | |
mod buffer { | |
use bevy::prelude::*; | |
use crate::canvas::Canvas; | |
pub struct PixelBuffer<'a> { | |
pub width: i32, | |
pub pixels: &'a mut [u8], | |
} | |
impl<'a> PixelBuffer<'a> { | |
pub fn new(width: i32, pixels: &'a mut [u8]) -> Self { | |
Self { width, pixels } | |
} | |
} | |
impl<'a> Canvas for PixelBuffer<'a> { | |
fn set(&mut self, x: i32, y: i32, color: Color) { | |
let [r, g, b, a] = color.as_rgba_f32(); | |
let index = (y * self.width + x) as usize * 4; | |
if index >= self.pixels.len() { | |
return; | |
} | |
self.pixels[index] = (r * 255.0) as u8; | |
self.pixels[index + 1] = (g * 255.0) as u8; | |
self.pixels[index + 2] = (b * 255.0) as u8; | |
self.pixels[index + 3] = (a * 255.0) as u8; | |
} | |
fn size(&self) -> (i32, i32) { | |
let width = self.width; | |
let height = self.pixels.len() as i32 / width; | |
(width, height) | |
} | |
// HERE: If this method override is commented out the perf becomes 60x worse | |
// fn clear(&mut self, color: Color) { | |
// let [r, g, b, a] = color.as_rgba_f32(); | |
// for pixel in self.pixels.chunks_exact_mut(4) { | |
// pixel[0] = (r * 255.0) as u8; | |
// pixel[1] = (g * 255.0) as u8; | |
// pixel[2] = (b * 255.0) as u8; | |
// pixel[3] = (a * 255.0) as u8; | |
// } | |
// } | |
} | |
} | |
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat}; | |
use bevy::render::texture::ImageSampler; | |
use buffer::PixelBuffer; | |
use canvas::Canvas; | |
const IMAGE_SCALE: f32 = 7.5; | |
const WIDTH: usize = 1920; | |
const HEIGHT: usize = 1080; | |
const IMG_WIDTH: usize = (WIDTH as f32 / IMAGE_SCALE) as usize; | |
const IMG_HEIGHT: usize = (HEIGHT as f32 / IMAGE_SCALE) as usize; | |
use bevy::log; | |
use bevy::prelude::*; | |
#[derive(Component)] | |
struct CanvasImage; | |
fn main() { | |
App::new() | |
.add_plugins(DefaultPlugins.set(WindowPlugin { | |
window: WindowDescriptor { | |
width: WIDTH as f32, | |
height: HEIGHT as f32, | |
..default() | |
}, | |
..default() | |
})) | |
.add_startup_system(setup) | |
.add_system(clear_canvas) | |
.run(); | |
} | |
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) { | |
commands.spawn(Camera2dBundle::default()); | |
log::info!("Setup - image size: {IMG_WIDTH}x{IMG_HEIGHT} - window size: {WIDTH}x{HEIGHT}"); | |
let size = Extent3d { | |
width: IMG_WIDTH as u32, | |
height: IMG_HEIGHT as u32, | |
depth_or_array_layers: 1, | |
}; | |
let data = vec![0; WIDTH * HEIGHT * 4]; | |
let mut ui_image = Image::new( | |
size, | |
TextureDimension::D2, | |
data, | |
TextureFormat::Rgba8UnormSrgb, | |
); | |
ui_image.sampler_descriptor = ImageSampler::nearest(); | |
let ui_image = images.add(ui_image); | |
commands | |
.spawn(SpriteBundle { | |
texture: ui_image, | |
transform: Transform::from_xyz(0.0, 0.0, 1.0).with_scale(Vec3::ONE * IMAGE_SCALE), | |
..Default::default() | |
}) | |
.insert(CanvasImage); | |
} | |
fn clear_canvas( | |
mut images: ResMut<Assets<Image>>, | |
canvas_image: Query<&Handle<Image>, With<CanvasImage>>, | |
) { | |
let mut ui_image = canvas_image.single(); | |
let image = images.get_mut(&mut ui_image).unwrap(); | |
let width = image.size().x as i32; | |
let mut canvas = PixelBuffer::new(width, &mut image.data); | |
let now = std::time::Instant::now(); | |
canvas.clear(Color::rgba_u8(0, 0, 0, 0)); | |
log::info!("clear took {:?}", now.elapsed()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment