use super::error::*;
use super::offscreen_trait::*;
use crate::action::*;
use crate::metal_renderer::*;
use metal;
use std::ffi::{c_void};
struct MetalOffscreenRenderContext {
device: metal::Device
}
struct MetalOffscreenRenderTarget {
device: metal::Device,
render_target: RenderTarget,
renderer: MetalRenderer,
width: usize,
height: usize
}
pub fn initialize_offscreen_rendering() -> Result<impl OffscreenRenderContext, RenderInitError> {
let device = metal::Device::system_default();
let device = if let Some(device) = device { device } else { Err(RenderInitError::CannotOpenGraphicsDevice)? };
Ok(MetalOffscreenRenderContext {
device: device
})
}
impl OffscreenRenderContext for MetalOffscreenRenderContext {
type RenderTarget = MetalOffscreenRenderTarget;
fn create_render_target(&mut self, width: usize, height: usize) -> Self::RenderTarget {
let device = self.device.clone();
let render_target = RenderTarget::new(&self.device, width, height, RenderTargetType::StandardForReading);
let renderer = MetalRenderer::with_device(&self.device, true);
MetalOffscreenRenderTarget {
device: device,
render_target: render_target,
renderer: renderer,
width: width,
height: height
}
}
}
impl OffscreenRenderTarget for MetalOffscreenRenderTarget {
fn render<ActionIter: IntoIterator<Item=RenderAction>>(&mut self, actions: ActionIter) {
let buffer = self.renderer.render_to_buffer(actions, self.render_target.render_texture());
let blit_encoder = buffer.new_blit_command_encoder();
blit_encoder.synchronize_resource(self.render_target.render_texture());
blit_encoder.end_encoding();
buffer.commit();
buffer.wait_until_completed();
}
fn realize(self) -> Vec<u8> {
let mut result = vec![0; self.width * self.height * 4];
let texture = self.render_target.render_texture();
let region = metal::MTLRegion {
origin: metal::MTLOrigin { x: 0, y: 0, z: 0 },
size: metal::MTLSize { width: self.width as u64, height: self.height as u64, depth: 1 }
};
texture.get_bytes(result.as_mut_ptr() as *mut c_void, (self.width*4) as u64, region, 0);
result
}
}