Compare commits

...

10 Commits

Author SHA1 Message Date
Michael Pfaff 5fa9e8f883 Adjust C APIs to improve performance and clean-up a tiny bit 2024-06-19 00:07:55 -04:00
Michael Pfaff 4ac0bbae7e Improve canvas_text example 2024-06-18 18:18:46 -04:00
Michael Pfaff 1b070fc0db Merge remote-tracking branch 'origin/main' 2024-06-18 18:01:53 -04:00
Michael Pfaff e5912d7d70 Improve C bindings and canvas_text example 2024-06-18 18:01:18 -04:00
Philip Deuchler 4968e819c0
Remove stdarch_arm_crc32 feature as it is now stable (#566)
Fixes #565
2024-06-11 10:31:35 +00:00
Sebastian 30419d0766
Fix #553 (#555)
* use a Result for font functions that can fail

* derive Debug for FontError and add data to the variants
2024-03-10 15:08:16 +00:00
Samson dc6034f666
Replace platform-intrinsic with core_intrinsics (#559)
Co-authored-by: Sebastian <s3bk@protonmail.com>
2024-03-05 11:09:28 +00:00
John Vandenberg 91d821a1f2
fix typos (#556) 2024-03-05 10:56:30 +00:00
Jonas Pleyer f1bce9fd62
bump simd to 0.5.3 in order push fixes for stdsimd feature upstream (#557) 2024-03-05 10:49:13 +00:00
Sebastian cb4eb597c3
update pdf stuff (#552) 2024-02-14 16:32:57 +00:00
11 changed files with 1495 additions and 722 deletions

1949
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,8 @@ version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[features]
capi = []
[lib]
crate-type = ["staticlib"]
crate-type = ["staticlib", "cdylib"]
name = "pathfinder"
[dependencies]
@ -16,8 +13,13 @@ font-kit = "0.6"
foreign-types = "0.3"
gl = "0.14"
libc = "0.2"
simple_logger = "4.3"
usvg = "0.9"
[dependencies.log]
version = "0.4"
features = ["max_level_info"]
[dependencies.pathfinder_canvas]
features = ["pf-text"]
path = "../canvas"

View File

@ -10,6 +10,7 @@
//! C bindings to Pathfinder.
use font_kit::font::Font;
use font_kit::handle::Handle;
use gl;
use pathfinder_canvas::{Canvas, CanvasFontContext, CanvasRenderingContext2D, FillStyle, LineJoin};
@ -27,6 +28,7 @@ use pathfinder_gpu::Device;
use pathfinder_resources::ResourceLoader;
use pathfinder_resources::fs::FilesystemResourceLoader;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use pathfinder_renderer::concurrent::executor::SequentialExecutor;
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererLevel};
@ -39,7 +41,7 @@ use pathfinder_svg::SVGScene;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
use std::path::PathBuf;
use std::ptr;
use std::ptr::{self, NonNull};
use std::slice;
use std::str;
use usvg::{Options, Tree};
@ -51,6 +53,11 @@ use metal::{self, CoreAnimationDrawableRef, DeviceRef as NativeMetalDeviceRef};
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
use pathfinder_metal::MetalDevice;
#[no_mangle]
pub extern "system" fn init_logging() {
simple_logger::init_with_env().unwrap();
}
// Constants
// `canvas`
@ -102,6 +109,7 @@ pub type FKHandleRef = *mut Handle;
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
pub type PFCanvasFontContextRef = *mut CanvasFontContext;
pub type FKFontRef = NonNull<Font>;
pub type PFFillStyleRef = *mut FillStyle;
pub type PFLineCap = u8;
pub type PFLineJoin = u8;
@ -272,6 +280,13 @@ pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef
Box::into_raw(Box::new(Box::from_raw(canvas).into_canvas().into_scene()))
}
// Extensions
#[no_mangle]
pub unsafe extern "C" fn PFCanvasClear(canvas: PFCanvasRef) {
(*canvas).clear()
}
// Drawing rectangles
#[no_mangle]
@ -284,6 +299,11 @@ pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PF
(*canvas).stroke_rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasClearRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).clear_rect((*rect).to_rust())
}
// Drawing text
#[no_mangle]
@ -306,9 +326,8 @@ pub unsafe extern "C" fn PFCanvasStrokeText(canvas: PFCanvasRef,
pub unsafe extern "C" fn PFCanvasMeasureText(canvas: PFCanvasRef,
string: *const c_char,
string_len: usize,
out_text_metrics: *mut PFTextMetrics) {
debug_assert!(!out_text_metrics.is_null());
*out_text_metrics = (*canvas).measure_text(to_rust_string(&string, string_len)).to_c()
out_text_metrics: NonNull<PFTextMetrics>) {
out_text_metrics.write((*canvas).measure_text(to_rust_string(&string, string_len)).to_c())
}
#[no_mangle]
@ -375,10 +394,33 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef,
pub unsafe extern "C" fn PFCanvasFontContextGetFontByPostScriptName(context: PFCanvasFontContextRef,
postscript_name: *const c_char,
postscript_name_len: usize) {
(*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len))
postscript_name_len: usize) -> Option<FKFontRef> {
let name = to_rust_string(&postscript_name, postscript_name_len);
match (*context).get_font_by_postscript_name(name) {
Ok(font) => NonNull::new(Box::into_raw(Box::new(font))),
Err(e) => {
log::error!("Failed to get font {:?}: {:?}", name, e);
None
}
}
}
#[no_mangle]
pub unsafe extern "C" fn FKFontDestroy(font: FKFontRef) {
drop(Box::from_raw(font.as_ptr()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetFont(canvas: PFCanvasRef, font: FKFontRef) -> i32 {
match (*canvas).set_font(font.as_ref().clone()) {
Ok(_) => 0,
Err(e) => {
log::error!("Failed to set font: {:?}", e);
1
}
}
}
#[no_mangle]
@ -621,6 +663,33 @@ pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFG
(*renderer).device_mut()
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererSetViewport(renderer: PFGLRendererRef, new_viewport: PFRectI) -> i32 {
match (*renderer).options_mut().dest {
DestFramebuffer::Default { ref mut viewport, .. } => {
*viewport = new_viewport.to_rust();
0
}
DestFramebuffer::Other(_) => 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererSetWindowSize(renderer: PFGLRendererRef, new_window_size: PFVector2I) -> i32 {
match (*renderer).options_mut().dest {
DestFramebuffer::Default { ref mut window_size, .. } => {
*window_size = new_window_size.to_rust();
0
}
DestFramebuffer::Other(_) => 1,
}
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererDestFramebufferSizeChanged(renderer: PFGLRendererRef) {
(*renderer).dest_framebuffer_size_changed()
}
#[cfg(all(target_os = "macos", not(feature = "pf-gl")))]
#[no_mangle]
pub unsafe extern "C" fn PFMetalDestFramebufferCreateFullWindow(window_size: *const PFVector2I)
@ -785,12 +854,18 @@ pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef,
level: PFRendererLevel)
-> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene),
to_rust_renderer_level(level),
RayonExecutor)))
pub unsafe extern "C" fn PFSceneProxyCreateWithSequentialExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), SequentialExecutor)))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateWithRayonExecutor(level: PFRendererLevel) -> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::new(to_rust_renderer_level(level), RayonExecutor)))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyReplaceScene(scene_proxy: PFSceneProxyRef, scene: PFSceneRef) {
(*scene_proxy).replace_scene(*Box::from_raw(scene))
}
#[no_mangle]

View File

@ -10,6 +10,7 @@
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
use font_kit::canvas::RasterizationOptions;
use font_kit::error::{FontLoadingError, SelectionError};
use font_kit::family_name::FamilyName;
use font_kit::handle::Handle;
use font_kit::hinting::HintingOptions;
@ -103,9 +104,10 @@ impl CanvasRenderingContext2D {
}
#[inline]
pub fn set_font<FC>(&mut self, font_collection: FC) where FC: IntoFontCollection {
let font_collection = font_collection.into_font_collection(&self.canvas_font_context);
pub fn set_font<FC>(&mut self, font_collection: FC) -> Result<(), FontError> where FC: IntoFontCollection {
let font_collection = font_collection.into_font_collection(&self.canvas_font_context)?;
self.current_state.font_collection = font_collection;
Ok(())
}
#[inline]
@ -152,13 +154,7 @@ pub trait ToTextLayout {
impl ToTextLayout for str {
fn layout(&self, state: CanvasState) -> Cow<TextMetrics> {
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: state.0.font_size },
&state.0.font_collection,
self));
Cow::Owned(TextMetrics::new(skribo_layout,
state.0.font_size,
state.0.text_align,
state.0.text_baseline))
Cow::Owned(TextMetrics::layout(self, &state.0.font_collection, state.0.font_size, state.0.text_align, state.0.text_baseline))
}
}
@ -188,6 +184,13 @@ impl ToTextLayout for TextMetrics {
#[derive(Clone)]
pub struct CanvasFontContext(pub(crate) Rc<RefCell<CanvasFontContextData>>);
/// The reason a font could not be loaded
#[derive(Debug)]
pub enum FontError {
NotFound(SelectionError),
LoadError(FontLoadingError),
}
pub(super) struct CanvasFontContextData {
pub(super) font_context: FontContext<Font>,
#[allow(dead_code)]
@ -224,16 +227,15 @@ impl CanvasFontContext {
CanvasFontContext::new(Arc::new(MemSource::from_fonts(fonts).unwrap()))
}
fn get_font_by_postscript_name(&self, postscript_name: &str) -> Font {
pub fn get_font_by_postscript_name(&self, postscript_name: &str) -> Result<Font, FontError> {
let this = self.0.borrow();
if let Some(cached_font) = this.font_context.get_cached_font(postscript_name) {
return (*cached_font).clone();
return Ok((*cached_font).clone());
}
this.font_source
.select_by_postscript_name(postscript_name)
.expect("Couldn't find a font with that PostScript name!")
.load()
.expect("Failed to load the font!")
.map_err(FontError::NotFound)?
.load().map_err(FontError::LoadError)
}
}
@ -314,6 +316,13 @@ impl TextMetrics {
}
}
pub fn layout(string: &str, font_collection: &FontCollection, font_size: f32, text_align: TextAlign, text_baseline: TextBaseline) -> TextMetrics {
let skribo_layout = Rc::new(skribo::layout(&TextStyle { size: font_size },
font_collection,
string));
TextMetrics::new(skribo_layout, font_size, text_align, text_baseline)
}
pub fn text_x_offset(&self) -> f32 {
if self.text_x_offset.get().is_none() {
self.text_x_offset.set(Some(match self.align {
@ -523,46 +532,46 @@ impl VerticalMetrics {
/// Various things that can be conveniently converted into font collections for use with
/// `CanvasRenderingContext2D::set_font()`.
pub trait IntoFontCollection {
fn into_font_collection(self, font_context: &CanvasFontContext) -> Arc<FontCollection>;
fn into_font_collection(self, font_context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError>;
}
impl IntoFontCollection for Arc<FontCollection> {
#[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
self
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
Ok(self)
}
}
impl IntoFontCollection for FontFamily {
#[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new();
font_collection.add_family(self);
Arc::new(font_collection)
Ok(Arc::new(font_collection))
}
}
impl IntoFontCollection for Vec<FontFamily> {
#[inline]
fn into_font_collection(self, _: &CanvasFontContext) -> Arc<FontCollection> {
fn into_font_collection(self, _: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new();
for family in self {
font_collection.add_family(family);
}
Arc::new(font_collection)
Ok(Arc::new(font_collection))
}
}
impl IntoFontCollection for Font {
#[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
FontFamily::new_from_font(self).into_font_collection(context)
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
Ok(FontFamily::new_from_font(self).into_font_collection(context)?)
}
}
impl<'a> IntoFontCollection for &'a [Font] {
#[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut family = FontFamily::new();
for font in self {
family.add_font(FontRef::new((*font).clone()))
@ -573,19 +582,19 @@ impl<'a> IntoFontCollection for &'a [Font] {
impl<'a> IntoFontCollection for &'a str {
#[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
context.get_font_by_postscript_name(self).into_font_collection(context)
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
context.get_font_by_postscript_name(self)?.into_font_collection(context)
}
}
impl<'a, 'b> IntoFontCollection for &'a [&'b str] {
#[inline]
fn into_font_collection(self, context: &CanvasFontContext) -> Arc<FontCollection> {
fn into_font_collection(self, context: &CanvasFontContext) -> Result<Arc<FontCollection>, FontError> {
let mut font_collection = FontCollection::new();
for postscript_name in self {
let font = context.get_font_by_postscript_name(postscript_name);
let font = context.get_font_by_postscript_name(postscript_name)?;
font_collection.add_family(FontFamily::new_from_font(font));
}
Arc::new(font_collection)
Ok(Arc::new(font_collection))
}
}

View File

@ -367,14 +367,14 @@ impl Contour {
return Contour::from_rect(rect);
}
let radius = radius.min(rect.size() * 0.5);
let contol_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE;
let control_point_offset = radius * QUARTER_ARC_CP_FROM_OUTSIDE;
let mut contour = Contour::with_capacity(8);
// upper left corner
{
let p0 = rect.origin();
let p1 = p0 + contol_point_offset;
let p1 = p0 + control_point_offset;
let p2 = p0 + radius;
contour.push_endpoint(vec2f(p0.x(), p2.y()));
contour.push_cubic(
@ -387,7 +387,7 @@ impl Contour {
// upper right
{
let p0 = rect.upper_right();
let p1 = p0 + contol_point_offset * vec2f(-1.0, 1.0);
let p1 = p0 + control_point_offset * vec2f(-1.0, 1.0);
let p2 = p0 + radius * vec2f(-1.0, 1.0);
contour.push_endpoint(vec2f(p2.x(), p0.y()));
contour.push_cubic(
@ -400,7 +400,7 @@ impl Contour {
// lower right
{
let p0 = rect.lower_right();
let p1 = p0 + contol_point_offset * vec2f(-1.0, -1.0);
let p1 = p0 + control_point_offset * vec2f(-1.0, -1.0);
let p2 = p0 + radius * vec2f(-1.0, -1.0);
contour.push_endpoint(vec2f(p0.x(), p2.y()));
contour.push_cubic(
@ -413,7 +413,7 @@ impl Contour {
// lower left
{
let p0 = rect.lower_left();
let p1 = p0 + contol_point_offset * vec2f(1.0, -1.0);
let p1 = p0 + control_point_offset * vec2f(1.0, -1.0);
let p2 = p0 + radius * vec2f(1.0, -1.0);
contour.push_endpoint(vec2f(p2.x(), p0.y()));
contour.push_cubic(

View File

@ -50,8 +50,8 @@ use std::path::PathBuf;
use std::thread;
use std::time::Duration;
use usvg::{Options as UsvgOptions, Tree as SvgTree};
use pdf::file::File as PdfFile;
use pdf_render::Cache as PdfRenderCache;
use pdf::file::{CachedFile, FileOptions};
use pdf_render::{Cache as PdfRenderCache, SceneBackend};
#[cfg(any(not(target_os = "macos"), feature = "pf-gl"))]
use pathfinder_gl::GLDevice as DeviceImpl;
@ -86,7 +86,7 @@ mod ui;
enum Content {
Svg(SvgTree),
Pdf {
file: PdfFile<Vec<u8>>,
file: CachedFile<Vec<u8>>,
cache: PdfRenderCache,
page_nr: u32
}
@ -773,8 +773,9 @@ impl Content {
}
Content::Pdf { ref file, ref mut cache, page_nr } => {
let page = file.get_page(page_nr).expect("no such page");
let (scene, _) = cache.render_page(file, &page, Transform2F::default()).unwrap();
(scene, String::new())
let mut backend = SceneBackend::new(cache);
pdf_render::render_page(&mut backend, &file.resolver(), &page, Transform2F::default()).unwrap();
(backend.finish(), String::new())
}
}
}
@ -791,7 +792,7 @@ fn load_scene(resource_loader: &dyn ResourceLoader,
if let Ok(tree) = SvgTree::from_data(&data, &UsvgOptions::default()) {
Content::Svg(tree)
} else if let Ok(file) = PdfFile::from_data(data) {
} else if let Ok(file) = FileOptions::cached().load(data) {
Content::Pdf { file, cache: PdfRenderCache::new(), page_nr: 0 }
} else {
panic!("can't load data");

View File

@ -25,6 +25,7 @@ use sdl2::keyboard::Keycode;
use sdl2::video::GLProfile;
use std::iter;
use std::sync::Arc;
use std::time::{Duration, Instant};
fn main() {
// Set up SDL2.
@ -34,7 +35,10 @@ fn main() {
// Make sure we have at least a GL 3.0 context. Pathfinder requires this.
let gl_attributes = video.gl_attr();
gl_attributes.set_context_profile(GLProfile::Core);
gl_attributes.set_context_version(3, 3);
gl_attributes.set_context_version(4, 1);
gl_attributes.set_context_flags()
.forward_compatible()
.set();
// Open a window.
let window_size = vec2i(640, 480);
@ -66,17 +70,32 @@ fn main() {
// Wait for a keypress.
let mut event_pump = sdl_context.event_pump().unwrap();
let mut n = 0;
let mut last_update = Instant::now();
let mut fps_buf = String::new();
loop {
match event_pump.wait_event() {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return,
Event::Window { win_event: WindowEvent::Exposed, .. } => {
match event_pump.poll_event() {
Some(Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. }) => return,
Some(Event::Window { win_event: WindowEvent::Exposed, .. }) | None => {
// Make a canvas.
let mut canvas = Canvas::new(window_size.to_f32()).get_context_2d(font_context.clone());
// Draw the text.
canvas.set_font("Overpass-Regular");
canvas.set_font("Overpass-Regular").unwrap();
canvas.set_font_size(32.0);
let now = Instant::now();
let elapsed = now.duration_since(last_update);
if elapsed >= Duration::from_millis(50) {
last_update = now;
let fps = (n as f64) * ((Duration::from_secs(1).as_micros() as f64) / (elapsed.as_micros() as f64));
fps_buf.clear();
fps_buf.push_str("FPS: ");
use std::fmt::Write;
write!(fps_buf, "{fps:.2}").unwrap();
n = 0;
}
canvas.fill_text("Hello Pathfinder!", vec2f(32.0, 48.0));
canvas.fill_text(&fps_buf, vec2f(32.0, 96.0));
canvas.set_text_align(TextAlign::Right);
canvas.stroke_text("Goodbye Pathfinder!", vec2f(608.0, 464.0));
@ -86,6 +105,8 @@ fn main() {
RayonExecutor);
scene.build_and_render(&mut renderer, BuildOptions::default());
window.gl_swap_window();
n += 1;
},
_ => {}
}

View File

@ -31,5 +31,5 @@ export SPIRVCROSS=spirv-cross.exe
Note: the Windows versions of `glslangValidator` and `spirv-cross` may change
the line endings of the generated output. Please take care to ensure that
unintended line ending changes aren't accidentally commited, for instance by
unintended line ending changes aren't accidentally committed, for instance by
[configuring Git to automatically handle line endings](https://docs.github.com/en/github/using-git/configuring-git-to-handle-line-endings#global-settings-for-line-endings).

View File

@ -1,6 +1,6 @@
[package]
name = "pathfinder_simd"
version = "0.5.2"
version = "0.5.3"
edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
build = "build.rs"

View File

@ -10,6 +10,7 @@
use std::arch::aarch64::{self, float32x2_t, float32x4_t, int32x2_t, int32x4_t};
use std::arch::aarch64::{uint32x2_t, uint32x4_t};
use std::intrinsics::simd::*;
use std::f32;
use std::fmt::{self, Debug, Formatter};
use std::mem;
@ -869,33 +870,6 @@ impl Index<usize> for U32x4 {
}
}
// Intrinsics
extern "platform-intrinsic" {
fn simd_add<T>(x: T, y: T) -> T;
fn simd_div<T>(x: T, y: T) -> T;
fn simd_mul<T>(x: T, y: T) -> T;
fn simd_sub<T>(x: T, y: T) -> T;
fn simd_shr<T>(x: T, y: T) -> T;
fn simd_and<T>(x: T, y: T) -> T;
fn simd_or<T>(x: T, y: T) -> T;
fn simd_xor<T>(x: T, y: T) -> T;
fn simd_fmin<T>(x: T, y: T) -> T;
fn simd_fmax<T>(x: T, y: T) -> T;
fn simd_eq<T, U>(x: T, y: T) -> U;
fn simd_gt<T, U>(x: T, y: T) -> U;
fn simd_le<T, U>(x: T, y: T) -> U;
fn simd_lt<T, U>(x: T, y: T) -> U;
fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
fn simd_cast<T, U>(x: T) -> U;
}
extern "C" {
#[link_name = "llvm.fabs.v2f32"]
fn fabs_v2f32(a: float32x2_t) -> float32x2_t;

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, platform_intrinsics))]
#![cfg_attr(all(target_arch = "aarch64", pf_rustc_nightly), feature(stdarch_arm_crc32))]
#![cfg_attr(pf_rustc_nightly, allow(internal_features))]
#![cfg_attr(pf_rustc_nightly, feature(link_llvm_intrinsics, core_intrinsics))]
#![cfg_attr(pf_rustc_nightly, feature(simd_ffi))]
//! A minimal SIMD abstraction, usable outside of Pathfinder.