use super::super::Handle;
use super::backend::GpuDevice;
use super::types::*;
use crate::fitz::geometry::Matrix;
#[cfg(target_os = "macos")]
pub struct MetalDevice {
capabilities: GpuCapabilities,
_device: u64,
_command_queue: u64,
_default_library: u64,
}
#[cfg(target_os = "macos")]
impl MetalDevice {
pub fn new() -> GpuResult<Self> {
let capabilities = GpuCapabilities {
max_texture_size: 16384,
max_texture_units: 128,
compute_shaders: true,
geometry_shaders: false, tessellation: true,
max_msaa_samples: 8,
float_textures: true,
instancing: true,
vram_mb: 0,
device_name: "Metal Device".into(),
vendor_name: "Apple".into(),
driver_version: "Metal 3".into(),
};
Ok(Self {
capabilities,
_device: 0,
_command_queue: 0,
_default_library: 0,
})
}
}
#[cfg(target_os = "macos")]
impl GpuDevice for MetalDevice {
fn backend(&self) -> GpuBackendType {
GpuBackendType::Metal
}
fn capabilities(&self) -> &GpuCapabilities {
&self.capabilities
}
fn create_texture(&self, width: u32, height: u32, format: GpuFormat) -> GpuResult<GpuTexture> {
let mut texture = GpuTexture::new(width, height, format, GpuBackendType::Metal);
texture.native_handle = 1;
Ok(texture)
}
fn destroy_texture(&self, _texture: &GpuTexture) -> GpuResult<()> {
Ok(())
}
fn upload_texture(
&self,
texture: &mut GpuTexture,
_data: &[u8],
_stride: u32,
) -> GpuResult<()> {
let _ = texture;
Ok(())
}
fn download_texture(
&self,
texture: &GpuTexture,
_data: &mut [u8],
_stride: u32,
) -> GpuResult<()> {
let _ = texture;
Ok(())
}
fn clear_texture(&self, texture: &mut GpuTexture, color: [f32; 4]) -> GpuResult<()> {
let _ = (texture, color);
Ok(())
}
fn create_shader(&self, _vertex_src: &str, _fragment_src: &str) -> GpuResult<GpuShader> {
let shader = GpuShader::new("shader", GpuBackendType::Metal);
Ok(shader)
}
fn destroy_shader(&self, _shader: &GpuShader) -> GpuResult<()> {
Ok(())
}
fn create_buffer(&self, size: usize, usage: GpuBufferUsage) -> GpuResult<GpuBuffer> {
let buffer = GpuBuffer::new(size, usage, GpuBackendType::Metal);
Ok(buffer)
}
fn destroy_buffer(&self, _buffer: &GpuBuffer) -> GpuResult<()> {
Ok(())
}
fn upload_buffer(&self, buffer: &mut GpuBuffer, _data: &[u8], _offset: usize) -> GpuResult<()> {
let _ = buffer;
Ok(())
}
fn render_page(
&self,
page: Handle,
texture: &mut GpuTexture,
transform: &Matrix,
) -> GpuResult<()> {
let _ = (page, texture, transform);
Ok(())
}
fn composite(
&self,
src: &GpuTexture,
dst: &mut GpuTexture,
x: i32,
y: i32,
blend_mode: GpuBlendMode,
) -> GpuResult<()> {
let _ = (src, dst, x, y, blend_mode);
Ok(())
}
fn draw_quad(
&self,
texture: &GpuTexture,
dst: &mut GpuTexture,
src_rect: [f32; 4],
dst_rect: [f32; 4],
color: [f32; 4],
) -> GpuResult<()> {
let _ = (texture, dst, src_rect, dst_rect, color);
Ok(())
}
fn flush(&self) -> GpuResult<()> {
Ok(())
}
fn finish(&self) -> GpuResult<()> {
Ok(())
}
}
pub const QUAD_VERTEX_SHADER_MSL: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float2 position [[attribute(0)]];
float2 texcoord [[attribute(1)]];
};
struct VertexOut {
float4 position [[position]];
float2 texcoord;
};
struct Uniforms {
float4x4 projection;
float4x4 transform;
float4 color;
};
vertex VertexOut quad_vertex(
VertexIn in [[stage_in]],
constant Uniforms& uniforms [[buffer(0)]]
) {
VertexOut out;
out.position = uniforms.projection * uniforms.transform * float4(in.position, 0.0, 1.0);
out.texcoord = in.texcoord;
return out;
}
"#;
pub const QUAD_FRAGMENT_SHADER_MSL: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
float2 texcoord;
};
struct Uniforms {
float4x4 projection;
float4x4 transform;
float4 color;
};
fragment float4 quad_fragment(
VertexOut in [[stage_in]],
texture2d<float> tex [[texture(0)]],
sampler samp [[sampler(0)]],
constant Uniforms& uniforms [[buffer(0)]]
) {
return tex.sample(samp, in.texcoord) * uniforms.color;
}
"#;
pub const PATH_VERTEX_SHADER_MSL: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float2 position [[attribute(0)]];
};
struct VertexOut {
float4 position [[position]];
};
struct Uniforms {
float4x4 projection;
float4x4 transform;
float4 color;
};
vertex VertexOut path_vertex(
VertexIn in [[stage_in]],
constant Uniforms& uniforms [[buffer(0)]]
) {
VertexOut out;
out.position = uniforms.projection * uniforms.transform * float4(in.position, 0.0, 1.0);
return out;
}
"#;
pub const PATH_FRAGMENT_SHADER_MSL: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Uniforms {
float4x4 projection;
float4x4 transform;
float4 color;
};
fragment float4 path_fragment(
constant Uniforms& uniforms [[buffer(0)]]
) {
return uniforms.color;
}
"#;
#[cfg(all(test, target_os = "macos"))]
mod tests {
use super::*;
#[test]
fn test_create_device() {
let device = MetalDevice::new().unwrap();
assert_eq!(device.backend(), GpuBackendType::Metal);
}
}