Skip to content

Instantly share code, notes, and snippets.

@Dzejkop
Created February 24, 2023 20:04
Show Gist options
  • Save Dzejkop/2d1dde8f64acc84f56ac5f0925cadf24 to your computer and use it in GitHub Desktop.
Save Dzejkop/2d1dde8f64acc84f56ac5f0925cadf24 to your computer and use it in GitHub Desktop.
Weird Bevy perf thing
[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"
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