Skip to content

Commit

Permalink
pixel buffer for async framebuffer reads
Browse files Browse the repository at this point in the history
  • Loading branch information
mrDIMAS committed Aug 31, 2024
1 parent e8ca400 commit 1895039
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 4 deletions.
8 changes: 4 additions & 4 deletions fyrox-impl/src/renderer/framework/gpu_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ pub enum PixelElementKind {
}

pub struct PixelDescriptor {
data_type: u32,
format: u32,
internal_format: u32,
swizzle_mask: Option<[i32; 4]>,
pub data_type: u32,
pub format: u32,
pub internal_format: u32,
pub swizzle_mask: Option<[i32; 4]>,
}

impl PixelKind {
Expand Down
1 change: 1 addition & 0 deletions fyrox-impl/src/renderer/framework/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ pub mod framebuffer;
pub mod geometry_buffer;
pub mod gpu_program;
pub mod gpu_texture;
pub mod pixel_buffer;
pub mod query;
pub mod state;
124 changes: 124 additions & 0 deletions fyrox-impl/src/renderer/framework/pixel_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

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

pub struct PixelBuffer {
id: glow::NativeBuffer,
state: Weak<PipelineState>,
}

impl Drop for PixelBuffer {
fn drop(&mut self) {
if let Some(state) = self.state.upgrade() {
unsafe {
state.gl.delete_buffer(self.id);
}
}
}
}

impl PixelBuffer {
pub fn new(state: &PipelineState) -> Result<Self, FrameworkError> {
unsafe {
let id = state.gl.create_buffer()?;
Ok(Self {
id,
state: state.weak(),
})
}
}

pub fn schedule_pixels_transfer(
&self,
state: &PipelineState,
framebuffer: &FrameBuffer,
color_buffer_index: u32,
rect: Option<Rect<i32>>,
) -> Result<(), FrameworkError> {
let color_attachment = &framebuffer
.color_attachments()
.get(color_buffer_index as usize)
.ok_or_else(|| {
FrameworkError::Custom(format!(
"Framebuffer {:?} does not have {} color attachment!",
framebuffer.id(),
color_buffer_index
))
})?
.texture;
let color_attachment = color_attachment.borrow();
let attachment_pixel_descriptor = color_attachment.pixel_kind().pixel_descriptor();
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(),
));
}
}
};
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,
target_rect.size.x,
target_rect.size.y,
attachment_pixel_descriptor.format,
attachment_pixel_descriptor.data_type,
PixelPackData::BufferOffset(0),
);
state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, None);
Ok(())
}
}

pub fn read<T>(&self, state: &PipelineState, buffer: &mut [T])
where
T: Pod,
{
unsafe {
state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(self.id));
state
.gl
.get_buffer_sub_data(glow::PIXEL_PACK_BUFFER, 0, array_as_u8_slice_mut(buffer));
state.gl.bind_buffer(glow::PIXEL_PACK_BUFFER, None);
}
}
}

0 comments on commit 1895039

Please sign in to comment.