Giter Site home page Giter Site logo

metal-rs's Introduction

Matrix room gfx-hal on crates.io Build Status
Getting Started | Documentation | Blog | Funding

gfx-rs

gfx-rs is a low-level, cross-platform graphics and compute abstraction library in Rust. It consists of the following components:

gfx-hal deprecation

As of the v0.9 release, gfx-hal is now in maintenance mode. gfx-hal development was mainly driven by wgpu, which has now switched to its own GPU abstraction called wgpu-hal. For this reason, gfx-hal development has switched to maintenance only, until the developers figure out the story for gfx-portability. Read more about the transition in #3768.

hal

  • gfx-hal which is gfx's hardware abstraction layer: a Vulkan-ic mostly unsafe API which translates to native graphics backends.
  • gfx-backend-* which contains graphics backends for various platforms:
  • gfx-warden which is a data-driven reference test framework, used to verify consistency across all graphics backends.

gfx-rs is hard to use, it's recommended for performance-sensitive libraries and engines. If that's not your domain, take a look at wgpu-rs for a safe and simple alternative.

Hardware Abstraction Layer

The Hardware Abstraction Layer (HAL), is a thin, low-level graphics and compute layer which translates API calls to various backends, which allows for cross-platform support. The API of this layer is based on the Vulkan API, adapted to be more Rust-friendly.

Hardware Abstraction Layer (HAL)

Currently HAL has backends for Vulkan, DirectX 12/11, Metal, and OpenGL/OpenGL ES/WebGL.

The HAL layer is consumed directly by user applications or libraries. HAL is also used in efforts such as gfx-portability.

See the Big Picture blog post for connections.

The old gfx crate (pre-ll)

This repository was originally home to the gfx crate, which is now deprecated. You can find the latest versions of the code for that crate in the pre-ll branch of this repository.

The master branch of this repository is now focused on developing gfx-hal and its associated backend and helper libraries, as described above. gfx-hal is a complete rewrite of gfx, but it is not necessarily the direct successor to gfx. Instead, it serves a different purpose than the original gfx crate, by being "lower level" than the original. Hence, the name of gfx-hal was originally ll, which stands for "lower level", and the original gfx is now referred to as pre-ll.

The spiritual successor to the original gfx is actually wgpu, which stands on a similar level of abstraction to the old gfx crate, but with a modernized API that is more fit for being used over Vulkan/DX12/Metal. If you want something similar to the old gfx crate that is being actively developed, wgpu is probably what you're looking for, rather than gfx-hal.

Contributing

We are actively looking for new contributors and aim to be welcoming and helpful to anyone that is interested! We know the code base can be a bit intimidating in size and depth at first, and to this end we have a label on the issue tracker which marks issues that are new contributor friendly and have some basic direction for completion in the issue comments. If you have any questions about any of these issues (or any other issues) you may want to work on, please comment on GitHub and/or drop a message in our Matrix chat!

License

This repository is licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

metal-rs's People

Contributors

abd45 avatar aclysma avatar adamnemecek avatar aleksijuvani avatar alexbool avatar armansito avatar bors[bot] avatar burtonageo avatar chinedufn avatar chyyran avatar crowlkats avatar cwfitzgerald avatar daxpedda avatar fkaa avatar fl33tw00d avatar flannyh avatar fornwall avatar grovesnl avatar jinleili avatar johncolanduoni avatar kvark avatar madsmtm avatar michael-lfx avatar mtak- avatar mxpv avatar repi avatar scoopr avatar waywardmonkeys avatar wumpf avatar xixixao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

metal-rs's Issues

Document memory behaviour of command buffers, buffers etc.

This issue may not be related specifically to metal-rs, but may be more of a metal/cocoa rust thing. I'm filing it here, because I'm running into some troubles getting memory deallocation of Metal buffers working, and I haven't been able to solve it using existing resources online.

Ask: It would be very helpful having some more advanced examples of how to manage buffer memory in more complicated scenarios.

Concretely I'm trying to implement a matrix and operations on matrices utilising Metal. The code is currently in a state where it seems to produce correct results, but the application memory seems to increase more or less linearly with the number of operations performed (currently most operations will allocate a new matrix).
In my code I've chosen to have the data of the matrices living solely on the GPU using the StorageModePrivate flag on the buffer, in hope that the data won't needed to be synchronised to the CPU all the time. When transferring data to/from the CPU, I allocate a temporary CPUCacheModeDefaultCache buffer and use the Metal API to copy between the two buffers (see https://github.com/kasper0406/neuralnetwork/blob/master/src/metalmatrixhandle.rs#L424). What I currently don't understand is how to properly deallocate the memory associated with both the private and the temporary buffer.

I am wrapping the entire application in a NSAutoreleasePool, however this only seems to actually free anything when the pool is released, which does not happen frequently enough when doing many matrix allocations.
The private matrix buffer should basically follow the lifetime of the MetalMatrixHandle object. These may not live in some well-defined scope in the code, making it hard to use additional NSAutoreleasePools to handle it.

I have tried calling retain/release directly on the buffers, but it doesn't really seem to do any deallocation (inspecting by looking at the memory consumption when debugging through Xcode), and also I'm unsure how this behaves when a buffer is queued up for use in a command buffer. I've tried testing the above using a loop allocating buffers that can basically be freed right after they are constructed https://github.com/kasper0406/neuralnetwork/blob/master/src/metalmatrixhandle.rs#L593.

Cannot compile on stable due to `msg_send`, "consider giving `result` a type"

I am currently going through the amethyst tutorial. Since I'm currently working on a MacBook Pro, I've been using metal (thanks for the great tool, btw!).

The amethyst demo compiled and ran fine (I think). However, when I started going through the tutorial, I wasn't able to compile due to an error when compiling metal.

If you think this should be reported to amethyst instead, let me know.

Cargo.toml:

[package]
name = "pong"
version = "0.1.0"
authors = []
edition = "2018"

[dependencies.amethyst]
version = "0.12.0"
features = ["metal"]

main.rs:

//! Pong tutorial Harrison McCullough

use amethyst::{
    prelude::*,
    renderer::{
        plugins::{RenderFlat2D, RenderToWindow},
        types::DefaultBackend,
        RenderingBundle,
    },
    utils::application_root_dir,
};

pub struct Pong;

impl SimpleState for Pong {}

fn main() -> amethyst::Result<()> {
    amethyst::start_logger(Default::default());

    let app_root = application_root_dir()?;
    let display_config_path = app_root.join("config").join("display.ron");

    let game_date = GameDataBuilder::default();

    let assets_dir = app_root.join("assets");
    let mut world = World::new();
    let mut game = Application::new(assets_dir, Pong, game_date);
    game.run();

    Ok(())
}

Output:

$ cargo build
   Compiling libc v0.2.66
   Compiling proc-macro2 v1.0.6
   Compiling unicode-xid v0.2.0
   ... <truncated> ...
   Compiling tokio-io v0.1.12
   Compiling tokio-threadpool v0.1.17
error[E0282]: type annotations needed
   --> /Users/harrisonmccullough/.cargo/registry/src/github.com-1ecc6299db9ec823/metal-0.15.0/src/lib.rs:125:13
    |
125 |             msg_send![self.0, release];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider giving `result` a type
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

   Compiling want v0.2.0
   Compiling glyph_brush v0.6.1
   Compiling font-kit v0.1.0
error: aborting due to previous error

For more information about this error, try `rustc --explain E0282`.
error: could not compile `metal`.
warning: build failed, waiting for other jobs to finish...
error: build failed

$ rustup override list
/Users/harrisonmccullough/git/pong      	stable-x86_64-apple-darwin

Determine supported functions

See gfx-rs/gfx#2058 (comment)

We need a way to determine whether certain functions are supported, which depends on the device OS and Metal version.

Ideally metal-rs could provide some way to query this information (i.e. fn supports_xyz() -> bool) or guard against these cases (i.e. return a certain Err type), instead of callers having to perform their own version checks and maintain feature tables for each version.

Vsync?

According to the documentation on Apple's webpage, you can try to achieve vsync with the following command:

https://developer.apple.com/documentation/metal/mtlcommandbuffer/2806849-present

See here for some extra info:

https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/FrameRate.html

However, changing

pub fn present_drawable<T>(&self, drawable: id<T>)

in commandbuffer.rs to take the additional afterMinimumDuration parameter, leads to a crash with the following error message:

2017-09-25 19:03:52.139 window[51292:591089] -[MTLIGAccelCommandBuffer presentDrawable:afterMinimumDuration:]: unrecognized selector sent to instance

Vsync is necessary for my work, so any ideas?

Unfortunately, I have no experience with Metal, Cocoa, AppKit, or the like, but willing to do whatever I can to help.

Best,
Rob

MTLPixelFormat has missing values

MTLPixelFormat has values which are missing (at least as of macOS 10.13).

There are also some formats which are available on iOS only which I'm assuming were omitted on purpose.

These are the missing formats (copied from MTLPixelFormat.h):

MTLPixelFormatBGR10A2Unorm  NS_AVAILABLE(10_13, 11_0) = 94,

MTLPixelFormatDepth16Unorm          NS_AVAILABLE_MAC(10_12) = 250,

MTLPixelFormatX32_Stencil8  NS_AVAILABLE(10_12, 10_0) = 261,
MTLPixelFormatX24_Stencil8  NS_AVAILABLE_MAC(10_12) = 262,

Automated code review for metal-rs

Hi!
I am a member of the team developing monocodus โ€” a service that performs automatic code review of GitHub pull requests to help organizations ensure a high quality of code.
Weโ€™ve developed some useful features to the moment, and now weโ€™re looking for early users and feedback to find out what we should improve and which features the community needs the most.

We ran monocodus on a pre-created fork of your repo on GitHub https://github.com/monocodus-demonstrations/metal-rs/pulls, and it found 15 formatting suggestions according to rustfmt. I hope that this information will be useful to you and would be happy to receive any feedback here or on my email [email protected]

We really love the Rust community, and we would love to hear from you on what automated checkers you might want to have. If there is something you cannot do with clippy, or cargo-fix, something you might have seen as a tool for some other language ecosystem, we can step forward and create it if you have any idea what you need!

If you want to try our service, feel free to follow the link: https://www.monocodus.com
The service is entirely free of charge for open source projects. Hope youโ€™ ll like it :)

Add documentation describing how to set up Xcode debugging

Iโ€™d like to add an example of taking a Metal app thatโ€™s completely written in Rust and debugging it in Xcode.

Iโ€™ve never actually done this - but I have some thoughts on how to approach it.

On mobile so might have typos

  1. Add an example that just imports one of the other examples (such as the textured quad example). So the imported example would have to expose a โ€œrunโ€ method. Use an environment variable to make the shader compilation include debug info. (So that when people copy paste the build script for their real project they arenโ€™t accidentally generating debug builds without realizing)

  2. Our Xcode debugging example would compile to a dylib that exposed a single method to run it

  3. Xcode example would have the smallest possible Xcode project that links to and runs the Rust generated dylib

  4. In the README of the example we include a screenshot or two of an Xcode debug session as well as any important notes / caveats if there end up being any

The nice part would be that the Xcode project would be immediately re-usable for any application since it does nothing but run a dylib.

One reason that I can think of against adding this example is that in general Xcode tends to feel bloaty (or at least that was my experience 6 or so years ago). I think that this is mitigated by having a project that does nothing more than run a linked library.

Another question might be - does this belong in metal-rs or a separate repo?

My thinking would be that being able to debug your shaders can be such a timesaver as well as such a cool demo as well as something you might not have thought of (I can still use Xcode tools with my entirely Rust app?!?!) that it belongs alongside the core examples.

Once people know how to run Xcode tools on their Rust app this means they now also know how to profile shaders, as well as anything else you might want to lean on Xcodeโ€™s user interface for (anything you want to visualize).

So this one example would unlock all Xcode tooling for the developer.

To repeat - Iโ€™ve never actually done this so it sounds good on paper but who knows what gotchas might exist.

But thatโ€™s the point of the example. We discover the solutions to those and present it in a nice tidy little example.

Let me know your thoughts and where you agree or disagree!

Byte data arguments

We are currently not consistent w.r.t. receiving &[u8] versus bare pointer + size. The former is a safer API but requires the user (sometimes) to convert whatever they have to a slice of u8. The former is tricky, since our methods are not marked as unsafe...

Remove core-graphics dependency

Right now core-graphics is used on these two lines (excluding in examples. I'm talking strictly metal-rs source)

metal-rs/src/lib.rs

Lines 27 to 28 in c17acf1

use core_graphics::base::CGFloat;
use core_graphics::geometry::CGSize;

Effectively we're using it to define type aliases for a couple of scalar types.

Given that the chances of these aliases ever changing is roughly 0%, I'm proposing that we ditch the core-graphics dependency and instead just copy-paste those two types inline in metal-rs.

The end result would be inlining the following code:

#[cfg(target_pointer_width = "64")]
type CGFloat = f64;
#[cfg(not(target_pointer_width = "64"))]
type CGFloat = f32;

#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct CGSize {
    pub width: CGFloat,
    pub height: CGFloat,
}

Am I missing anything here?

Apply `unsafe` more consistently

There are some functions like new_buffer_with_data which accept raw pointers, but not marked unsafe even though certain guarantees are necessary to safely use it. There are already many functions marked unsafe but we're not applying it consistently across the entire crate yet.

For new_buffer_with_data specifically we might consider accepting a slice (as mentioned in #42). But for other functions (especially any dealing with raw pointers) we should try to add unsafe and document any safety requirements.

Fix argument buffer example

Currently the argument buffer example fails (at least on nightly), but all other examples appear to work correctly:

metal-rs:master ฮป cargo run --example argument-buffer
    Finished dev [unoptimized + debuginfo] target(s) in 0.15s
     Running `target/debug/examples/argument-buffer`
<MTLEmulationIndirectArgumentEncoder: 0x7f867d5146a0>
<MTLIGSampler: 0x7f867d60f690>
    label = <none> 
    device = <null>
fish: 'cargo run --example argument-buโ€ฆ' terminated by signal SIGSEGV (Address boundary error)

Release 0.15.1

0.15.0 currently does not compile (#109). This commit fixed that, but it is only in 0.16: 032800f

Would it be possible to get a 0.15.1 release with the aforementioned commit included? That way, crates that depend on 0.15, such as Amethyst, can compile without having to downgrade the objc crate.

Make function parameter names and order consistent with Apple's documentation

In Apple's documentation, the order of function parameters might look like this:

func replace(region: MTLRegion, 
 mipmapLevel level: Int, 
   withBytes pixelBytes: UnsafeRawPointer, 
 bytesPerRow: Int)

whereas in metal-rs it might look like this

    pub fn replace_region(
        &self,
        region: MTLRegion,
        mipmap_level: NSUInteger,
        stride: NSUInteger,
        bytes: *const std::ffi::c_void,
    ) {
        // ...
    }

I found that the order differences (last two parameters swapped) and name differences (stride vs. bytes_per_row) made it difficult to cross reference Apple's Metal docs when working with metal-rs.

My understanding is that these were all written by hand over time (I'm just basing this assumption on the first few commits from 2016 https://github.com/gfx-rs/metal-rs/commits/master?after=09433e64682ffe4498988118c062e608a4971eb6+220)

Given that - it's probably quite a bit of manual work and breaking changes to get consistent (or at least to the degree possible) with the official metal APIs.

How does metal-rs typically think about breaking changes? Is this a no-go? Or could this fit in at some point in the future?

I could use some insight here.

Cheers!

Naming conventions

TLDR
Take Metal Objective C and Swift API and change names to Rust idiomatic names where applicable.

General

Rust bindings are based on Objective C protocol bindings.
Follow Objective C protocol definition to determine properties and methods.

Swift API adds some higher level stuff that is beyond the scope of Rust bindings.

Struct (Object) and Enum names

Same as Objective C/Swift API, e.g.

MTLDevice, MTLCommandBufferStatus, MTLCommandBuffer etc.

Enums

Swift

enum MTLCommandBufferStatus : UInt {
  case notEnqueued
  case enqueued
  case committed
  case scheduled
  case completed
  case error
}

Rust: change variant names following Rust conventions:
(basically capitalize first word)

pub enum MTLCommandBufferStatus {
  NotEnqueued,
  Enqueued,
  Committed,
  Scheduled,
  Completed,
  Error,
}

NOTE: Some enums contain Apple brand names that intentionally start with lowercase.
In those cases respect that, adding necessary #allow to keep Rust happy. For example:

#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum OS {
    iOS,
    tvOS,
    macOS,
}

Method names

Objective C

- (void)addCompletedHandler:(MTLCommandBufferHandler)block;

Swift

func addCompletedHandler(_ block: @escaping MTLCommandBufferHandler)

Rust: change to lowercase snake case:

pub fn add_completed_handler(&self, block: &CommandBufferHandler)

Special Case

Some methods create new objects (aka factory methods).

Objective C:

- (id<MTLComputeCommandEncoder>)computeCommandEncoderWithDescriptor:(MTLComputePassDescriptor *)computePassDescriptor;
- (id<MTLComputeCommandEncoder>)computeCommandEncoderWithDispatchType:(MTLDispatchType)dispatchType;
- (id<MTLComputeCommandEncoder>)computeCommandEncoder;

Swift:
NOTE: overloading

func makeComputeCommandEncoder(descriptor computePassDescriptor: MTLComputePassDescriptor) -> MTLComputeCommandEncoder?
func makeComputeCommandEncoder(dispatchType: MTLDispatchType) -> MTLComputeCommandEncoder?
func makeComputeCommandEncoder() -> MTLComputeCommandEncoder?

Rust:

  • use Objective C name (we don't want overloading)
  • change to lowercase snake case as usual
  • follow Swift way to emphasize the intention; change make to new, as we do in Rust:
pub fn new_compute_command_encoder_with_descriptor(desc: MTLComputePassDescriptor) -> &ComputeCommandEncoderRef {}
pub fn new_compute_command_encoder_with_dispatch_type(&self, ty: MTLDispatchType) -> &ComputeCommandEncoderRef {}
pub fn new_compute_command_encoder(&self) -> &ComputeCommandEncoderRef {}

Handling of `NSArray` for library function names

In 302d246 the dependency on objc-foundation was removed. Seems like it was mainly used for strings where an ad-hoc helper was used instead. However, at 302d246#diff-ae230649f72f8f72105a4ebc1edfb748L243 there was a usage of NSArray there was translated into an untyped object.

Before the change the following code worked:

    println!("Found the following functions in the Metal library:");
    let function_names = metal_matrix_lib.function_names().to_vec();
    for name in function_names {
        println!("{}", name.as_str());
    }

After the change however, the to_vec function does not exist.

What are your thoughts on this break? Would you consider re-introducing the dependency to support it, or possibly roll your own array/vec mapping?

I guess this specific call is not that useful in a production setting, but can be quite nifty for debugging during development.

Explicitly load Metal symbols

Similar to gfx-rs/d3d12-rs#19, we need to avoid implicit linking of Metal framework if we want to run (any application that uses metal-rs in some way) on macOS 10.10 and earlier.

One workaround that the clients could do is "-weak_framework Metal" instead of just "-framework". See https://phabricator.services.mozilla.com/D54946 for Gecko. They would still need to make sure that no entry points are used.

I think loading the libraries dynamically and explicitly by metal-rs is still better for the following reasons:

  • natural handling of Metal being unavailable (instead of checking the OS version separately)
  • explicit costs: we load symbols when metal-rs objects are created (or some kind of a Metal context is initialized) instead of dynamically checking for symbols on each and every call
  • consistency with d3d12-rs

Crash when running caps example

$ cargo run --example=caps
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/examples/caps`
Vendor: "Intel"
Family: "Iris Pro Graphics"
Max threads per threadgroup: MTLSize { width: 512, height: 512, depth: 512 }
Integrated GPU: true
Headless: false
D24S8: false
2017-09-14 02:48:20.562 caps[691:20772] -[MTLIGAccelDevice argumentBuffersSupport]: unrecognized selector sent to instance 0x7fc75f006e00
Segmentation fault: 11
$ cargo run --example=caps --release
    Finished release [optimized] target(s) in 0.0 secs
     Running `target/release/examples/caps`
Vendor: "Intel"
Family: "Iris Pro Graphics"
Max threads per threadgroup: MTLSize { width: 512, height: 512, depth: 512 }
Integrated GPU: true
Headless: false
D24S8: false
2017-09-14 02:50:18.811 caps[792:23178] -[MTLIGAccelDevice argumentBuffersSupport]: unrecognized selector sent to instance 0x7ff27881e800
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:335:20
note: Run with `RUST_BACKTRACE=1` for a backtrace.
fatal runtime error: failed to initiate panic, error 5
Abort trap: 6

metal-rs examples fail with SIGILL on recent nightlies, still works on stable

Running examples (from HEAD of this repository) fails:

alexbool@alexbool-osx ~/D/I/metal-rs> cargo run --example compute
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/examples/compute`
fatal runtime error: allocator memory exhausted
fish: 'cargo run --example compute' terminated by signal SIGILL (Illegal instruction)

alexbool@alexbool-osx ~/D/I/metal-rs> rust-lldb -- target/debug/examples/compute
(lldb) command source -s 0 '/tmp/rust-lldb-commands.9JfQTt'
Executing commands in '/tmp/rust-lldb-commands.9JfQTt'.
(lldb) command script import "/Users/alexbool/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/etc/lldb_rust_formatters.py"
(lldb) type summary add --no-value --python-function lldb_rust_formatters.print_val -x ".*" --category Rust
(lldb) type category enable Rust
(lldb) target create "target/debug/examples/compute"
Current executable set to 'target/debug/examples/compute' (x86_64).
(lldb) r
Process 4860 launched: '/Users/alexbool/Documents/IdeaProjects/metal-rs/target/debug/examples/compute' (x86_64)
fatal runtime error: allocator memory exhausted
compute was compiled with optimization - stepping may behave oddly; variables may not be available.
Process 4860 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x000000010004e6fa compute`alloc_system::platform::_$LT$impl$u20$core..heap..Alloc$u20$for$u20$$RF$$u27$a$u20$alloc_system..System$GT$::oom::haae5aa67e0537221 at lib.rs:215 [opt]
Target 0: (compute) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
  * frame #0: 0x000000010004e6fa compute`alloc_system::platform::_$LT$impl$u20$core..heap..Alloc$u20$for$u20$$RF$$u27$a$u20$alloc_system..System$GT$::oom::haae5aa67e0537221 at lib.rs:215 [opt]
    frame #1: 0x000000010004e698 compute`_$LT$alloc_system..System$u20$as$u20$core..heap..Alloc$GT$::oom::h6b14a7ed86d10e67 at lib.rs:78 [opt]
    frame #2: 0x000000010002800c compute`__rde_oom at lib.rs:124 [opt]
    frame #3: 0x000000010001aff9 compute`_$LT$alloc..heap..Heap$u20$as$u20$core..heap..Alloc$GT$::oom::h6fe185a73e220d75 at heap.rs:98 [opt]
    frame #4: 0x000000010001ae83 compute`_$LT$alloc..raw_vec..RawVec$LT$T$C$$u20$A$GT$$GT$::reserve::h31aa44fa05bc4469 at raw_vec.rs:558 [opt]
    frame #5: 0x000000010001582f compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a [inlined] _$LT$alloc..vec..Vec$LT$T$GT$$GT$::reserve::h68934e9fd0fc8180 at vec.rs:465 [opt]
    frame #6: 0x0000000100015823 compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a [inlined] _$LT$alloc..vec..Vec$LT$T$GT$$u20$as$u20$alloc..vec..SpecExtend$LT$$RF$$u27$a$u20$T$C$$u20$core..slice..Iter$LT$$u27$a$C$$u20$T$GT$$GT$$GT$::spec_extend::h126e6b75cdf416ca at vec.rs:1859 [opt]
    frame #7: 0x0000000100015823 compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a [inlined] _$LT$alloc..vec..Vec$LT$T$GT$$GT$::extend_from_slice::h7fec1563e64426ee at vec.rs:1346 [opt]
    frame #8: 0x0000000100015823 compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a [inlined] alloc::string::String::push_str::hd3e5f3c347641c54 at string.rs:805 [opt]
    frame #9: 0x0000000100015823 compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a [inlined] _$LT$alloc..string..String$u20$as$u20$core..fmt..Write$GT$::write_str::h3fb28a11f607cf9d at string.rs:2277 [opt]
    frame #10: 0x0000000100015823 compute`_$LT$core..fmt..Write..write_fmt..Adapter$LT$$u27$a$C$$u20$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::h5b108bba9b49131a at mod.rs:214 [opt]
    frame #11: 0x000000010000e172 compute`_$LT$alloc..string..String$u20$as$u20$core..fmt..Display$GT$::fmt::hc867ffd54fb6e644(self=&0x7ffeefbff0f0, f=&0x7ffeefbfef78) at string.rs:1860
    frame #12: 0x000000010000e798 compute`_$LT$objc..message..MessageError$u20$as$u20$core..fmt..Display$GT$::fmt::hdca7e778728ba39e(self=&0x7ffeefbff0f0, f=&0x7ffeefbfef78) at mod.rs:157
    frame #13: 0x0000000100051999 compute`core::fmt::write::hd6c4ef3dd62ed92b [inlined] core::fmt::Formatter::run::h1e9c4a7161cf2c85 at mod.rs:1100 [opt]
    frame #14: 0x0000000100051814 compute`core::fmt::write::hd6c4ef3dd62ed92b at mod.rs:1047 [opt]
    frame #15: 0x0000000100016dc4 compute`std::panicking::begin_panic_fmt::hccd237cdae61db17 [inlined] core::fmt::Write::write_fmt::h1f0dbd48320f1e1a at mod.rs:226 [opt]
    frame #16: 0x0000000100016d89 compute`std::panicking::begin_panic_fmt::hccd237cdae61db17 at panicking.rs:348 [opt]
    frame #17: 0x0000000100008211 compute`metal_rs::encoder::CommandEncoderRef::end_encoding::h7ba072b0c0038804(self=&0x100211440) at encoder.rs:135
    frame #18: 0x000000010000581b compute`compute::main::h3c95dc9e471369d8 at main.rs:78
    frame #19: 0x0000000100002e22 compute`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h07c3d44bb113f1a4 at rt.rs:74
    frame #20: 0x0000000100016d08 compute`std::panicking::try::do_call::h7faedbe63ef0ecf9 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::h73acc47e0a9ff971 at rt.rs:59 [opt]
    frame #21: 0x0000000100016cfc compute`std::panicking::try::do_call::h7faedbe63ef0ecf9 at panicking.rs:306 [opt]
    frame #22: 0x0000000100027b4f compute`__rust_maybe_catch_panic at lib.rs:102 [opt]
    frame #23: 0x0000000100014cf8 compute`std::rt::lang_start_internal::hbde0134cdd993de4 [inlined] std::panicking::try::h66d036c9b5e0ac3f at panicking.rs:285 [opt]
    frame #24: 0x0000000100014cc5 compute`std::rt::lang_start_internal::hbde0134cdd993de4 [inlined] std::panic::catch_unwind::hdc6db1d58a689477 at panic.rs:361 [opt]
    frame #25: 0x0000000100014cc5 compute`std::rt::lang_start_internal::hbde0134cdd993de4 at rt.rs:58 [opt]
    frame #26: 0x0000000100002e02 compute`std::rt::lang_start::he2ae847addd0cd4a(main=&0x100005050, argc=1, argv=&0x7ffeefbff8a0) at rt.rs:74
    frame #27: 0x0000000100005d25 compute`main + 37
    frame #28: 0x00007fff6fd39115 libdyld.dylib`start + 1
(lldb) ^D

alexbool@alexbool-osx ~/D/I/metal-rs> rustc -vV
rustc 1.27.0-nightly (fb44b4c0e 2018-04-04)
binary: rustc
commit-hash: fb44b4c0eb1d344f84f7bb2c90f28e31a8a180be
commit-date: 2018-04-04
host: x86_64-apple-darwin
release: 1.27.0-nightly
LLVM version: 6.0

Still works on stable (1.25.0). I think this is rust issue, but cannot figure it out.

Publish new version to be used by gfx-hal.

There's a leak in 0.15.0 in CommandBufferRef.rs under set_label() which is fixed in the current master branch. I tested wgpu-rs with patched metal-rs and it works fine without API breakage.

Fences and barriers?

I see that neither fences nor barriers are exposed by the rust API, and also I see that gfx-hal just uses a CPU sleep to emulate a fence.

Is that really equivalent to a GPU-side fence in metal, or am I missing something fundamental here?

Host documentation

Most of the project rely on docs.rs for documentation, however it only builds Linux at the moment. We need to find a good way of providing the documentation here.

cc @fkaa @JohnColanduoni

Undefined references _MTLCopyAllDevices and _MTLCreateSystemDefaultDevice

Gecko is cross-compiling with macOS SDK 10.11 from Linux, getting these errors:
undefined symbols for architecture x86_64:

[task 2019-10-30T20:17:30.236Z] 20:17:30 INFO - "_MTLCopyAllDevices", referenced from:
[task 2019-10-30T20:17:30.236Z] 20:17:30 INFO - __ZN5metal6device6Device3all17hcc249f5610afec5fE in libgkrust_gtest.a(metal-7ef41ee34b16f6d0.metal.97s9ik07-cgu.2.rcgu.o)
[task 2019-10-30T20:17:30.236Z] 20:17:30 INFO - "_MTLCreateSystemDefaultDevice", referenced from:
[task 2019-10-30T20:17:30.236Z] 20:17:30 INFO - __ZN5metal6device6Device14system_default17hbaf7fd9f5662bfcbE in libgkrust_gtest.a(metal-7ef41ee34b16f6d0.metal.97s9ik07-cgu.2.rcgu.o)
[task 2019-10-30T20:17:30.236Z] 20:17:30 INFO - ld: symbol(s) not found for architecture x86_64

True Array semantics

We should consider implementing Index + IndexMut on array-like objects (e.g. PipelineBufferDescriptorArray) instead of exposing object_at + set_object_at methods.

examples/window/shaders.metal is very wrong

the binary metallib checked into the repository works, but this .metal file cannot be compiled to produce that metallib.

This is closer:

// code: language=c++
#include <metal_stdlib>

using namespace metal;

typedef struct {
    float x, y, r, g, b;
} vertex_t;

static_assert(alignof(vertex_t) == 4, "vertex_t must match a rust array of f32");
static_assert(sizeof(vertex_t) == 4 * 5, "vertex_t must match a rust array of f32");

struct ColorInOut {
    float4 position [[position]];
    float4 color;
};

// vertex shader function
vertex ColorInOut triangle_vertex(device vertex_t* vertex_array [[ buffer(0) ]],
                                   uint32_t vid [[ vertex_id ]])
{
    ColorInOut out;
    
    auto device const &v = vertex_array[vid];
    out.position = float4(v.x, v.y, 0.0, 1.0);
    out.color = float4(v.r, v.g, v.b, 1.0);
    
    return out;
}

// fragment shader function
fragment float4 triangle_fragment(ColorInOut in [[stage_in]])
{
    return in.color;
}

I suspect the example should include a build.rs to compile the metallib from source to avoid this problem recurring.

Naming convention

Just noticed that our methods sometimes diverge from Metal:

    pub fn new_blit_command_encoder(&self) -> &BlitCommandEncoderRef {
        unsafe {
            msg_send![self, blitCommandEncoder]
        }
}

I think we should fix all of those diverging cases and follow Metal more strictly. That would be a breaking change.
cc @grovesNL

fatal assert when calling ArgumentDescriptor::set_access

I'm getting a very strange assertion with this program:

fn main() {
    let argument_descriptor = rafx::api::metal_rs::ArgumentDescriptor::new();
    println!("settings access");
    argument_descriptor.set_access(rafx::api::metal_rs::MTLArgumentAccess::ReadWrite);
    println!("has set access");

    let argument_descriptor = rafx::api::metal_rs::ArgumentDescriptor::new();
    println!("settings access");
    argument_descriptor.set_access(rafx::api::metal_rs::MTLArgumentAccess::ReadWrite);
    println!("has set access");

It prints

settings access
has set access
settings access
validateMTLArgumentAccess:27: failed assertion `access (4294967297) is not a valid MTLArgumentAccess.'

The bizarre thing is that I cannot reproduce this with an "empty" project. If I take the exact code and all the same dependencies and move them to another project, it works fine. The only difference I can think of at this point is the one that fails is an example of another crate and the in-theory identical project that doesn't crash links that same crate as a downstream binary.

The only thing I can think of that would cause a crash like this would be incorrect bindings or something happening before main() that causes undefined behavior. I use static variables and things like lazy_static extremely sparingly. The app runs fine if I use my vulkan backend instead of the metal backend and all other metal bindings seem to work. (The original project that is crashing calls quite a few metal APIs before reaching this point).

The only thing I saw that looks suspicious is that MTLArgumentAccess is repr(u32) and the docs point out that this is Uint, which would actually be u64 on most systems (i.e. usize)

I tried to find examples of this function actually being used but was unable to get the gfx-hal examples to call it and didn't see it used in the examples of this crate.

Just posting here hoping that someone has an idea!

Integrate auto-release pool into the type system

I find it rather obscure that we have no control over when something is released if it decides to use an auto-release pool. I wonder if we could encode this into the type system, so that a user-provided auto-release context is required in any operation that ends up using it implicitly. Something along these lines:

impl Foo {
    fn some_operation(&self, arc: &AutoReleaseContext) {..}
}

fn main() {
    autoreleasepool(|context| {
      foo.some_operation(context);
    })
}

is this feasible or totally unrealistic? @grovesNL @scoopr @SSheldon

MTLPixelFormat does not implement PartialEq

MTLPixelFormat should derive PartialEq, or really Eq, since it's just a plain enum.
Most of the time it's going to be used with match, but having it implement PartialEq lets us do useful things like

debug_assert_eq!(src.raw.pixel_format(), dst.raw.pixel_format());

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.