Skip to content

Commit

Permalink
pixel buffer api improvements
Browse files Browse the repository at this point in the history
- access to image size calculations
  • Loading branch information
mrDIMAS committed Aug 31, 2024
1 parent 1895039 commit 2c38dc3
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 22 deletions.
11 changes: 8 additions & 3 deletions fyrox-impl/src/renderer/framework/gpu_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,12 @@ fn ceil_div_4(x: usize) -> usize {
(x + 3) / 4
}

fn image_3d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize, depth: usize) -> usize {
pub fn image_3d_size_bytes(
pixel_kind: PixelKind,
width: usize,
height: usize,
depth: usize,
) -> usize {
let pixel_count = width * height * depth;
match pixel_kind {
PixelKind::RGBA32F => 16 * pixel_count,
Expand Down Expand Up @@ -455,7 +460,7 @@ fn image_3d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize, depth
}
}

fn image_2d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize) -> usize {
pub fn image_2d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize) -> usize {
let pixel_count = width * height;
match pixel_kind {
PixelKind::RGBA32F => 16 * pixel_count,
Expand Down Expand Up @@ -492,7 +497,7 @@ fn image_2d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize) -> us
}
}

fn image_1d_size_bytes(pixel_kind: PixelKind, length: usize) -> usize {
pub fn image_1d_size_bytes(pixel_kind: PixelKind, length: usize) -> usize {
match pixel_kind {
PixelKind::RGBA32F => 16 * length,
PixelKind::RGB32F => 12 * length,
Expand Down
125 changes: 106 additions & 19 deletions fyrox-impl/src/renderer/framework/pixel_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,31 @@
// SOFTWARE.

use crate::{
core::{array_as_u8_slice_mut, math::Rect},
core::{algebra::Vector2, array_as_u8_slice_mut, math::Rect},
renderer::framework::{
error::FrameworkError, framebuffer::FrameBuffer, gpu_texture::GpuTextureKind,
error::FrameworkError,
framebuffer::FrameBuffer,
gpu_texture::{image_2d_size_bytes, GpuTextureKind},
state::PipelineState,
},
};
use bytemuck::Pod;
use glow::{HasContext, PixelPackData};
use std::rc::Weak;
use std::{marker::PhantomData, rc::Weak};

pub struct PixelBuffer {
id: glow::NativeBuffer,
struct ReadRequest {
fence: glow::Fence,
}

pub struct PixelBuffer<T> {
id: glow::Buffer,
state: Weak<PipelineState>,
request: Option<ReadRequest>,
pixel_count: usize,
phantom_data: PhantomData<T>,
}

impl Drop for PixelBuffer {
impl<T> Drop for PixelBuffer<T> {
fn drop(&mut self) {
if let Some(state) = self.state.upgrade() {
unsafe {
Expand All @@ -44,24 +53,38 @@ impl Drop for PixelBuffer {
}
}

impl PixelBuffer {
pub fn new(state: &PipelineState) -> Result<Self, FrameworkError> {
impl<T> PixelBuffer<T> {
pub fn new(state: &PipelineState, pixel_count: usize) -> Result<Self, FrameworkError> {
unsafe {
let id = state.gl.create_buffer()?;
state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(id));
let size_bytes = pixel_count * size_of::<T>();
state.gl.buffer_data_size(
glow::PIXEL_PACK_BUFFER,
size_bytes as i32,
glow::STREAM_COPY,
);
Ok(Self {
id,
state: state.weak(),
request: None,
pixel_count,
phantom_data: Default::default(),
})
}
}

pub fn schedule_pixels_transfer(
&self,
&mut self,
state: &PipelineState,
framebuffer: &FrameBuffer,
color_buffer_index: u32,
rect: Option<Rect<i32>>,
) -> Result<(), FrameworkError> {
if self.request.is_some() {
return Ok(());
}

let color_attachment = &framebuffer
.color_attachments()
.get(color_buffer_index as usize)
Expand All @@ -73,28 +96,57 @@ impl PixelBuffer {
))
})?
.texture;

let color_attachment = color_attachment.borrow();
let attachment_pixel_descriptor = color_attachment.pixel_kind().pixel_descriptor();

let color_attachment_size =
if let GpuTextureKind::Rectangle { width, height } = color_attachment.kind() {
Vector2::new(width, height)
} else {
return Err(FrameworkError::Custom(
"Only rectangular textures can be read from GPU!".to_string(),
));
};

let actual_size = image_2d_size_bytes(
color_attachment.pixel_kind(),
color_attachment_size.x,
color_attachment_size.y,
);
let self_bytes_count = self.pixel_count * size_of::<T>();
if actual_size != self_bytes_count {
return Err(FrameworkError::Custom(format!(
"Pixel buffer size {} does not match the size {} of the color \
attachment {} of the frame buffer {:?}",
self_bytes_count,
actual_size,
color_buffer_index,
framebuffer.id()
)));
}

let target_rect = match rect {
Some(rect) => rect,
None => {
if let GpuTextureKind::Rectangle { width, height } = color_attachment.kind() {
Rect::new(0, 0, width as i32, height as i32)
} else {
return Err(FrameworkError::Custom(
"Only rectangular textures can be read from GPU!".to_string(),
));
}
}
None => Rect::new(
0,
0,
color_attachment_size.x as i32,
color_attachment_size.y as i32,
),
};

unsafe {
state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(self.id));

state
.gl
.bind_framebuffer(glow::READ_FRAMEBUFFER, framebuffer.id());

state
.gl
.read_buffer(glow::COLOR_ATTACHMENT0 + color_buffer_index);

state.gl.read_pixels(
target_rect.position.x,
target_rect.position.y,
Expand All @@ -104,12 +156,47 @@ impl PixelBuffer {
attachment_pixel_descriptor.data_type,
PixelPackData::BufferOffset(0),
);

self.request = Some(ReadRequest {
fence: state
.gl
.fence_sync(glow::SYNC_GPU_COMMANDS_COMPLETE, 0)
.unwrap(),
});

state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, None);

Ok(())
}
}

pub fn read<T>(&self, state: &PipelineState, buffer: &mut [T])
pub fn is_request_running(&self) -> bool {
self.request.is_some()
}

pub fn try_read(&mut self, state: &PipelineState) -> Option<Vec<T>>
where
T: Pod + Default + Copy,
{
let request = self.request.as_ref()?;

let mut buffer = vec![T::default(); self.pixel_count];

unsafe {
if state.gl.get_sync_status(request.fence) == glow::SIGNALED {
self.read_internal(state, &mut buffer);

state.gl.delete_sync(request.fence);
self.request = None;

Some(buffer)
} else {
None
}
}
}

fn read_internal(&self, state: &PipelineState, buffer: &mut [T])
where
T: Pod,
{
Expand Down

0 comments on commit 2c38dc3

Please sign in to comment.