Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/metal/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

1776
vendor/metal/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

178
vendor/metal/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,178 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
name = "metal"
version = "0.31.0"
authors = ["gfx-rs developers"]
build = false
exclude = [
"guide/**/*",
"examples/texture/**/*",
"tests/**/*",
"Cargo.lock",
"target/**/*",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Rust bindings for Metal"
homepage = "https://github.com/gfx-rs/metal-rs"
documentation = "https://docs.rs/crate/metal"
readme = "README.md"
keywords = [
"metal",
"graphics",
"bindings",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/gfx-rs/metal-rs"
[package.metadata.docs.rs]
targets = [
"aarch64-apple-darwin",
"aarch64-apple-ios",
"aarch64-apple-ios-sim",
"x86_64-apple-darwin",
"x86_64-apple-ios",
]
[lib]
name = "metal"
path = "src/lib.rs"
[[example]]
name = "argument-buffer"
path = "examples/argument-buffer/main.rs"
[[example]]
name = "bind"
path = "examples/bind/main.rs"
[[example]]
name = "bindless"
path = "examples/bindless/main.rs"
[[example]]
name = "caps"
path = "examples/caps/main.rs"
[[example]]
name = "circle"
path = "examples/circle/main.rs"
[[example]]
name = "compute"
path = "examples/compute/main.rs"
[[example]]
name = "compute-argument-buffer"
path = "examples/compute/compute-argument-buffer.rs"
[[example]]
name = "embedded-lib"
path = "examples/compute/embedded-lib.rs"
[[example]]
name = "events"
path = "examples/events/main.rs"
required-features = ["dispatch"]
[[example]]
name = "fence"
path = "examples/fence/main.rs"
[[example]]
name = "headless-render"
path = "examples/headless-render/main.rs"
[[example]]
name = "library"
path = "examples/library/main.rs"
[[example]]
name = "mesh-shader"
path = "examples/mesh-shader/main.rs"
[[example]]
name = "mps"
path = "examples/mps/main.rs"
required-features = ["mps"]
[[example]]
name = "raytracing"
path = "examples/raytracing/main.rs"
[[example]]
name = "reflection"
path = "examples/reflection/main.rs"
[[example]]
name = "shader-dylib"
path = "examples/shader-dylib/main.rs"
[[example]]
name = "window"
path = "examples/window/main.rs"
[dependencies.bitflags]
version = "2"
[dependencies.block]
version = "0.1.6"
[dependencies.core-graphics-types]
version = "0.1.3"
default-features = false
[dependencies.dispatch]
version = "0.2"
optional = true
[dependencies.foreign-types]
version = "0.5"
[dependencies.log]
version = "0.4"
[dependencies.objc]
version = "0.2.4"
[dependencies.paste]
version = "1"
[dev-dependencies.cocoa]
version = "0.25.0"
[dev-dependencies.glam]
version = "0.27"
[dev-dependencies.png]
version = "0.17"
[dev-dependencies.rand]
version = "0.8"
[dev-dependencies.sema]
version = "0.1.4"
[dev-dependencies.winit]
version = "0.29"
[features]
cargo-clippy = []
default = ["link"]
link = ["core-graphics-types/link"]
mps = []
private = []

201
vendor/metal/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

25
vendor/metal/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2010 The Rust Project Developers
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.

16
vendor/metal/Makefile vendored Normal file
View File

@@ -0,0 +1,16 @@
compute:
xcrun -sdk macosx metal -c examples/compute/shaders.metal -o examples/compute/shaders.air
xcrun -sdk macosx metallib examples/compute/shaders.air -o examples/compute/shaders.metallib
window:
xcrun -sdk macosx metal -c examples/window/shaders.metal -o examples/window/shaders.air
xcrun -sdk macosx metallib examples/window/shaders.air -o examples/window/shaders.metallib
circle:
xcrun -sdk macosx metal -c examples/circle/shaders.metal -o examples/circle/shaders.air
xcrun -sdk macosx metallib examples/circle/shaders.air -o examples/circle/shaders.metallib
raytracing:
xcrun -sdk macosx metal -c -g examples/raytracing/shaders.metal -o examples/raytracing/shaders.air
xcrun -sdk macosx metallib examples/raytracing/shaders.air -o examples/raytracing/shaders.metallib

36
vendor/metal/README.md vendored Normal file
View File

@@ -0,0 +1,36 @@
# metal-rs
[![Actions Status](https://github.com/gfx-rs/metal-rs/workflows/ci/badge.svg)](https://github.com/gfx-rs/metal-rs/actions)
[![Crates.io](https://img.shields.io/crates/v/metal.svg?label=metal)](https://crates.io/crates/metal)
<p align="center">
<img width="150" height="150" src="./assets/metal.svg">
</p>
<p align="center">Unsafe Rust bindings for the Metal 3D Graphics API.</p>
## Examples
The [examples](/examples) directory highlights different ways of using the Metal graphics API for rendering
and computation.
Examples can be run using commands such as:
```
# Replace `window` with the name of the example that you would like to run
cargo run --example window
```
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
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.

15
vendor/metal/assets/metal.svg vendored Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="720px" height="720px" viewBox="0 0 720 720" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="limeGradient">
<stop stop-color="#0EFFDD" offset="0%"></stop>
<stop stop-color="#24FF74" offset="100%"></stop>
</linearGradient>
</defs>
<g>
<g>
<path d="M576,720 L144,720 C64.5,720 0,655.5 0,576 L0,144 C0,64.5 64.5,0 144,0 L576,0 C655.5,0 720,64.5 720,144 L720,576 C720,655.5 655.5,720 576,720 Z" id="app-backplate" fill="url(#limeGradient)"></path>
<polygon id="Path" fill="#000000" points="141 132 334 368 334 195 651 545 569 545 398 364 396 545 205 309 205 545 141 545"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 848 B

8
vendor/metal/bors.toml vendored Normal file
View File

@@ -0,0 +1,8 @@
status = [ "build (stable)" ]
# As of May 2020 we can expect CI to take roughly 3 minutes based on
# Based on https://github.com/chinedufn/metal-rs/actions/runs/94020785
#
# We round this up to a timeout of 5 minutes to account for any potential future
# inconsistencies in CI run times.
timeout-sec = 300

View File

@@ -0,0 +1,88 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
fn main() {
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
/*
// Build encoder for the following MSL argument buffer:
struct ArgumentBuffer {
texture2d<float> texture [[id(0)]];
sampler sampler [[id(1)]];
array<device float *, 2> buffers [[id(2)]];
}
*/
let desc1 = ArgumentDescriptor::new();
desc1.set_index(0);
desc1.set_data_type(MTLDataType::Texture);
desc1.set_texture_type(MTLTextureType::D2);
let desc2 = ArgumentDescriptor::new();
desc2.set_index(1);
desc2.set_data_type(MTLDataType::Sampler);
let desc3 = ArgumentDescriptor::new();
desc3.set_index(2);
desc3.set_data_type(MTLDataType::Pointer);
desc3.set_array_length(2);
let encoder = device.new_argument_encoder(Array::from_slice(&[desc1, desc2, desc3]));
println!("Encoder: {:?}", encoder);
let argument_buffer =
device.new_buffer(encoder.encoded_length(), MTLResourceOptions::empty());
encoder.set_argument_buffer(&argument_buffer, 0);
let sampler = {
let descriptor = SamplerDescriptor::new();
descriptor.set_support_argument_buffers(true);
device.new_sampler(&descriptor)
};
println!("{:?}", sampler);
let buffer1 = device.new_buffer(1024, MTLResourceOptions::empty());
println!("Buffer1: {:?}", buffer1);
let buffer2 = device.new_buffer(1024, MTLResourceOptions::empty());
println!("Buffer2: {:?}", buffer2);
encoder.set_sampler_state(1, &sampler);
encoder.set_buffer(2, &buffer1, 0);
encoder.set_buffer(3, &buffer2, 0);
// How to use argument buffer with render encoder.
let queue = device.new_command_queue();
let command_buffer = queue.new_command_buffer();
let render_pass_descriptor = RenderPassDescriptor::new();
let encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
// This method makes the array of resources resident for the selected stages of the render pass.
// Call this method before issuing any draw calls that may access the array of resources.
encoder.use_resources(
&[&buffer1, &buffer2],
MTLResourceUsage::Read,
MTLRenderStages::Vertex,
);
// Bind argument buffer to vertex stage.
encoder.set_vertex_buffer(0, Some(&argument_buffer), 0);
// Render pass here...
encoder.end_encoding();
println!("Encoder: {:?}", encoder);
command_buffer.commit();
});
}

34
vendor/metal/examples/bind/main.rs vendored Normal file
View File

@@ -0,0 +1,34 @@
// Copyright 2018 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
fn main() {
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
let buffer = device.new_buffer(4, MTLResourceOptions::empty());
let sampler = {
let descriptor = SamplerDescriptor::new();
device.new_sampler(&descriptor)
};
let queue = device.new_command_queue();
let cmd_buf = queue.new_command_buffer();
let encoder = cmd_buf.new_compute_command_encoder();
encoder.set_buffers(2, &[Some(&buffer), None], &[4, 0]);
encoder.set_sampler_states(1, &[Some(&sampler), None]);
encoder.end_encoding();
cmd_buf.commit();
println!("Everything is bound");
});
}

149
vendor/metal/examples/bindless/main.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
const BINDLESS_TEXTURE_COUNT: NSUInteger = 100_000; // ~25Mb
/// This example demonstrates:
/// - How to create a heap
/// - How to allocate textures from heap.
/// - How to create bindless resources via Metal's argument buffers.
/// - How to bind argument buffer to render encoder
fn main() {
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
/*
MSL
struct Textures {
texture2d<float> texture;
};
struct BindlessTextures {
device Textures *textures;
};
*/
// Tier 2 argument buffers are supported by macOS devices with a discrete GPU and by the A13 GPU.
// The maximum per-app resources available at any given time are:
// - 500,000 buffers or textures
// - 2048 unique samplers
let tier = device.argument_buffers_support();
println!("Argument buffer support: {:?}", tier);
assert_eq!(MTLArgumentBuffersTier::Tier2, tier);
let texture_descriptor = TextureDescriptor::new();
texture_descriptor.set_width(1);
texture_descriptor.set_height(1);
texture_descriptor.set_depth(1);
texture_descriptor.set_texture_type(MTLTextureType::D2);
texture_descriptor.set_pixel_format(MTLPixelFormat::R8Uint);
texture_descriptor.set_storage_mode(MTLStorageMode::Private); // GPU only.
println!("Texture descriptor: {:?}", texture_descriptor);
// Determine the size required for the heap for the given descriptor
let size_and_align = device.heap_texture_size_and_align(&texture_descriptor);
// Align the size so that more resources will fit in the heap after this texture
// See https://developer.apple.com/documentation/metal/buffers/using_argument_buffers_with_resource_heaps
let texture_size =
(size_and_align.size & (size_and_align.align - 1)) + size_and_align.align;
let heap_size = texture_size * BINDLESS_TEXTURE_COUNT;
let heap_descriptor = HeapDescriptor::new();
heap_descriptor.set_storage_mode(texture_descriptor.storage_mode()); // Must be compatible
heap_descriptor.set_size(heap_size);
println!("Heap descriptor: {:?}", heap_descriptor);
let heap = device.new_heap(&heap_descriptor);
println!("Heap: {:?}", heap);
// Allocate textures from heap
let textures = (0..BINDLESS_TEXTURE_COUNT)
.map(|i| {
heap.new_texture(&texture_descriptor)
.expect(&format!("Failed to allocate texture {}", i))
})
.collect::<Vec<_>>();
// Crate argument encoder that knows how to encode single texture
let descriptor = ArgumentDescriptor::new();
descriptor.set_index(0);
descriptor.set_data_type(MTLDataType::Texture);
descriptor.set_texture_type(MTLTextureType::D2);
descriptor.set_access(MTLArgumentAccess::ReadOnly);
println!("Argument descriptor: {:?}", descriptor);
let encoder = device.new_argument_encoder(Array::from_slice(&[descriptor]));
println!("Encoder: {:?}", encoder);
// Determinate argument buffer size to allocate.
// Size needed to encode one texture * total number of bindless textures.
let argument_buffer_size = encoder.encoded_length() * BINDLESS_TEXTURE_COUNT;
let argument_buffer = device.new_buffer(argument_buffer_size, MTLResourceOptions::empty());
// Encode textures to the argument buffer.
textures.iter().enumerate().for_each(|(index, texture)| {
// Offset encoder to a proper texture slot
let offset = index as NSUInteger * encoder.encoded_length();
encoder.set_argument_buffer(&argument_buffer, offset);
encoder.set_texture(0, texture);
});
// How to use bindless argument buffer when drawing
let queue = device.new_command_queue();
let command_buffer = queue.new_command_buffer();
let render_pass_descriptor = RenderPassDescriptor::new();
let encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
// Bind argument buffer.
encoder.set_fragment_buffer(0, Some(&argument_buffer), 0);
// Make sure all textures are available to the pass.
encoder.use_heap_at(&heap, MTLRenderStages::Fragment);
// Bind material buffer at index 1
// Draw
/*
// Now instead of binding individual textures each draw call,
// you can just bind material information instead:
MSL
struct Material {
int diffuse_texture_index;
int normal_texture_index;
// ...
}
fragment float4 pixel(
VertexOut v [[stage_in]],
constant const BindlessTextures * textures [[buffer(0)]],
constant Material * material [[buffer(1)]]
) {
if (material->base_color_texture_index != -1) {
textures[material->diffuse_texture_index].texture.sampler(...)
}
if (material->normal_texture_index != -1) {
...
}
...
}
*/
encoder.end_encoding();
command_buffer.commit();
});
}

33
vendor/metal/examples/caps/main.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
fn main() {
let device = Device::system_default().expect("no device found");
#[cfg(feature = "private")]
{
println!("Vendor: {:?}", unsafe { device.vendor() });
println!("Family: {:?}", unsafe { device.family_name() });
}
println!(
"Max threads per threadgroup: {:?}",
device.max_threads_per_threadgroup()
);
#[cfg(target_os = "macos")]
{
println!("Integrated GPU: {:?}", device.is_low_power());
println!("Headless: {:?}", device.is_headless());
println!("D24S8: {:?}", device.d24_s8_supported());
}
println!("maxBufferLength: {} Mb", device.max_buffer_length() >> 20);
println!(
"Indirect argument buffer: {:?}",
device.argument_buffers_support()
);
}

11
vendor/metal/examples/circle/README.md vendored Normal file
View File

@@ -0,0 +1,11 @@
## circle
Renders a circle in a window. As metal primitive types are only limited to point, line and triangle shape, this example shows how we can form complex structures out of primitive types.
![Screenshot of the final render](./screenshot.png)
## To Run
```
cargo run --example circle
```

386
vendor/metal/examples/circle/main.rs vendored Normal file
View File

@@ -0,0 +1,386 @@
use metal::*;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
raw_window_handle::{HasWindowHandle, RawWindowHandle},
};
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use objc::{rc::autoreleasepool, runtime::YES};
use std::mem;
// Declare the data structures needed to carry vertex layout to
// metal shading language(MSL) program. Use #[repr(C)], to make
// the data structure compatible with C++ type data structure
// for vertex defined in MSL program as MSL program is broadly
// based on C++
#[repr(C)]
#[derive(Debug)]
pub struct position(std::ffi::c_float, std::ffi::c_float);
#[repr(C)]
#[derive(Debug)]
pub struct color(std::ffi::c_float, std::ffi::c_float, std::ffi::c_float);
#[repr(C)]
#[derive(Debug)]
pub struct AAPLVertex {
p: position,
c: color,
}
fn main() {
// Create a window for viewing the content
let event_loop = EventLoop::new().unwrap();
let size = winit::dpi::LogicalSize::new(800, 600);
let window = winit::window::WindowBuilder::new()
.with_inner_size(size)
.with_title("Metal".to_string())
.build(&event_loop)
.unwrap();
// Set up the GPU device found in the system
let device = Device::system_default().expect("no device found");
println!("Your device is: {}", device.name(),);
// Scaffold required to sample the GPU and CPU timestamps
let mut cpu_start = 0;
let mut gpu_start = 0;
device.sample_timestamps(&mut cpu_start, &mut gpu_start);
let counter_sample_buffer = create_counter_sample_buffer(&device);
let destination_buffer = device.new_buffer(
(std::mem::size_of::<u64>() * 4 as usize) as u64,
MTLResourceOptions::StorageModeShared,
);
let counter_sampling_point = MTLCounterSamplingPoint::AtStageBoundary;
assert!(device.supports_counter_sampling(counter_sampling_point));
let binary_archive_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/circle/binary_archive.metallib");
let binary_archive_url =
URL::new_with_string(&format!("file://{}", binary_archive_path.display()));
let binary_archive_descriptor = BinaryArchiveDescriptor::new();
if binary_archive_path.exists() {
binary_archive_descriptor.set_url(&binary_archive_url);
}
// Set up a binary archive to cache compiled shaders.
let binary_archive = device
.new_binary_archive_with_descriptor(&binary_archive_descriptor)
.unwrap();
let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/circle/shaders.metallib");
// Use the metallib file generated out of .metal shader file
let library = device.new_library_with_file(library_path).unwrap();
// The render pipeline generated from the vertex and fragment shaders in the .metal shader file.
let pipeline_state = prepare_pipeline_state(&device, &library, &binary_archive);
// Serialize the binary archive to disk.
binary_archive
.serialize_to_url(&binary_archive_url)
.unwrap();
// Set the command queue used to pass commands to the device.
let command_queue = device.new_command_queue();
// Currently, MetalLayer is the only interface that provide
// layers to carry drawable texture from GPU rendaring through metal
// library to viewable windows.
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_presents_with_transaction(false);
unsafe {
if let Ok(RawWindowHandle::AppKit(rw)) = window.window_handle().map(|wh| wh.as_raw()) {
let view = rw.ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(mem::transmute(layer.as_ref()));
}
}
let draw_size = window.inner_size();
layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64));
let vbuf = {
let vertex_data = create_vertex_points_for_circle();
let vertex_data = vertex_data.as_slice();
device.new_buffer_with_data(
vertex_data.as_ptr() as *const _,
(vertex_data.len() * mem::size_of::<AAPLVertex>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged,
)
};
event_loop
.run(move |event, event_loop| {
autoreleasepool(|| {
// ControlFlow::Wait pauses the event loop if no events are available to process.
// This is ideal for non-game applications that only update in response to user
// input, and uses significantly less power/CPU time than ControlFlow::Poll.
event_loop.set_control_flow(ControlFlow::Wait);
match event {
Event::AboutToWait => window.request_redraw(),
Event::WindowEvent { event, .. } => {
match event {
WindowEvent::CloseRequested => {
println!("The close button was pressed; stopping");
event_loop.exit();
}
WindowEvent::RedrawRequested => {
// It's preferrable to render in this event rather than in MainEventsCleared, since
// rendering in here allows the program to gracefully handle redraws requested
// by the OS.
let drawable = match layer.next_drawable() {
Some(drawable) => drawable,
None => return,
};
// Create a new command buffer for each render pass to the current drawable
let command_buffer = command_queue.new_command_buffer();
// Obtain a renderPassDescriptor generated from the view's drawable textures.
let render_pass_descriptor = RenderPassDescriptor::new();
handle_render_pass_color_attachment(
&render_pass_descriptor,
drawable.texture(),
);
handle_render_pass_sample_buffer_attachment(
&render_pass_descriptor,
&counter_sample_buffer,
);
// Create a render command encoder.
let encoder = command_buffer
.new_render_command_encoder(&render_pass_descriptor);
encoder.set_render_pipeline_state(&pipeline_state);
// Pass in the parameter data.
encoder.set_vertex_buffer(0, Some(&vbuf), 0);
// Draw the triangles which will eventually form the circle.
encoder.draw_primitives(MTLPrimitiveType::TriangleStrip, 0, 1080);
encoder.end_encoding();
resolve_samples_into_buffer(
&command_buffer,
&counter_sample_buffer,
&destination_buffer,
);
// Schedule a present once the framebuffer is complete using the current drawable.
command_buffer.present_drawable(&drawable);
// Finalize rendering here & push the command buffer to the GPU.
command_buffer.commit();
command_buffer.wait_until_completed();
let mut cpu_end = 0;
let mut gpu_end = 0;
device.sample_timestamps(&mut cpu_end, &mut gpu_end);
handle_timestamps(
&destination_buffer,
cpu_start,
cpu_end,
gpu_start,
gpu_end,
);
}
_ => (),
}
}
_ => (),
}
});
})
.unwrap();
}
// If we want to draw a circle, we need to draw it out of the three primitive
// types available with metal framework. Triangle is used in this case to form
// the circle. If we consider a circle to be total of 360 degree at center, we
// can form small triangle with one point at origin and two points at the
// perimeter of the circle for each degree. Eventually, if we can take enough
// triangle virtices for total of 360 degree, the triangles together will
// form a circle. This function captures the triangle vertices for each degree
// and push the co-ordinates of the vertices to a rust vector
fn create_vertex_points_for_circle() -> Vec<AAPLVertex> {
let mut v: Vec<AAPLVertex> = Vec::new();
let origin_x: f32 = 0.0;
let origin_y: f32 = 0.0;
// Size of the circle
let circle_size = 0.8f32;
for i in 0..720 {
let y = i as f32;
// Get the X co-ordinate of each point on the perimeter of circle
let position_x: f32 = y.to_radians().cos() * 100.0;
let position_x: f32 = position_x.trunc() / 100.0;
// Set the size of the circle
let position_x: f32 = position_x * circle_size;
// Get the Y co-ordinate of each point on the perimeter of circle
let position_y: f32 = y.to_radians().sin() * 100.0;
let position_y: f32 = position_y.trunc() / 100.0;
// Set the size of the circle
let position_y: f32 = position_y * circle_size;
v.push(AAPLVertex {
p: position(position_x, position_y),
c: color(0.7, 0.3, 0.5),
});
if (i + 1) % 2 == 0 {
// For each two points on perimeter, push one point of origin
v.push(AAPLVertex {
p: position(origin_x, origin_y),
c: color(0.2, 0.7, 0.4),
});
}
}
v
}
fn handle_render_pass_sample_buffer_attachment(
descriptor: &RenderPassDescriptorRef,
counter_sample_buffer: &CounterSampleBufferRef,
) {
let sample_buffer_attachment_descriptor =
descriptor.sample_buffer_attachments().object_at(0).unwrap();
sample_buffer_attachment_descriptor.set_sample_buffer(&counter_sample_buffer);
sample_buffer_attachment_descriptor.set_start_of_vertex_sample_index(0 as NSUInteger);
sample_buffer_attachment_descriptor.set_end_of_vertex_sample_index(1 as NSUInteger);
sample_buffer_attachment_descriptor.set_start_of_fragment_sample_index(2 as NSUInteger);
sample_buffer_attachment_descriptor.set_end_of_fragment_sample_index(3 as NSUInteger);
}
fn handle_render_pass_color_attachment(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) {
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
color_attachment.set_texture(Some(texture));
color_attachment.set_load_action(MTLLoadAction::Clear);
// Setting a background color
color_attachment.set_clear_color(MTLClearColor::new(0.5, 0.5, 0.8, 1.0));
color_attachment.set_store_action(MTLStoreAction::Store);
}
fn prepare_pipeline_state(
device: &Device,
library: &Library,
binary_archive: &BinaryArchive,
) -> RenderPipelineState {
let vert = library.get_function("vs", None).unwrap();
let frag = library.get_function("ps", None).unwrap();
let pipeline_state_descriptor = RenderPipelineDescriptor::new();
pipeline_state_descriptor.set_vertex_function(Some(&vert));
pipeline_state_descriptor.set_fragment_function(Some(&frag));
pipeline_state_descriptor
.color_attachments()
.object_at(0)
.unwrap()
.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
// Set the binary archives to search for a cached pipeline in.
pipeline_state_descriptor.set_binary_archives(&[binary_archive]);
// Add the pipeline descriptor to the binary archive cache.
binary_archive
.add_render_pipeline_functions_with_descriptor(&pipeline_state_descriptor)
.unwrap();
device
.new_render_pipeline_state(&pipeline_state_descriptor)
.unwrap()
}
fn resolve_samples_into_buffer(
command_buffer: &CommandBufferRef,
counter_sample_buffer: &CounterSampleBufferRef,
destination_buffer: &BufferRef,
) {
let blit_encoder = command_buffer.new_blit_command_encoder();
blit_encoder.resolve_counters(
&counter_sample_buffer,
crate::NSRange::new(0_u64, 4),
&destination_buffer,
0_u64,
);
blit_encoder.end_encoding();
}
fn handle_timestamps(
resolved_sample_buffer: &BufferRef,
cpu_start: u64,
cpu_end: u64,
gpu_start: u64,
gpu_end: u64,
) {
let samples = unsafe {
std::slice::from_raw_parts(resolved_sample_buffer.contents() as *const u64, 4 as usize)
};
let vertex_pass_start = samples[0];
let vertex_pass_end = samples[1];
let fragment_pass_start = samples[2];
let fragment_pass_end = samples[3];
let cpu_time_span = cpu_end - cpu_start;
let gpu_time_span = gpu_end - gpu_start;
let vertex_micros = microseconds_between_begin(
vertex_pass_start,
vertex_pass_end,
gpu_time_span,
cpu_time_span,
);
let fragment_micros = microseconds_between_begin(
fragment_pass_start,
fragment_pass_end,
gpu_time_span,
cpu_time_span,
);
println!("Vertex pass duration: {:.2} µs", vertex_micros);
println!("Fragment pass duration: {:.2} µs\n", fragment_micros);
}
fn create_counter_sample_buffer(device: &Device) -> CounterSampleBuffer {
let counter_sample_buffer_desc = metal::CounterSampleBufferDescriptor::new();
counter_sample_buffer_desc.set_storage_mode(metal::MTLStorageMode::Shared);
counter_sample_buffer_desc.set_sample_count(4_u64);
counter_sample_buffer_desc.set_counter_set(&fetch_timestamp_counter_set(device));
device
.new_counter_sample_buffer_with_descriptor(&counter_sample_buffer_desc)
.unwrap()
}
fn fetch_timestamp_counter_set(device: &Device) -> metal::CounterSet {
let counter_sets = device.counter_sets();
let mut timestamp_counter = None;
for cs in counter_sets.iter() {
if cs.name() == "timestamp" {
timestamp_counter = Some(cs);
break;
}
}
timestamp_counter
.expect("No timestamp counter found")
.clone()
}
/// <https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/converting_gpu_timestamps_into_cpu_time>
fn microseconds_between_begin(begin: u64, end: u64, gpu_time_span: u64, cpu_time_span: u64) -> f64 {
let time_span = (end as f64) - (begin as f64);
let nanoseconds = time_span / (gpu_time_span as f64) * (cpu_time_span as f64);
let microseconds = nanoseconds / 1000.0;
return microseconds;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

View File

@@ -0,0 +1,39 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
typedef struct {
float x;
float y;
}position;
typedef struct {
float r;
float g;
float b;
}color;
typedef struct {
position p;
color c;
}AAPLVertex;
struct ColorInOut {
float4 position[[position]];
float4 color;
};
vertex ColorInOut vs(constant AAPLVertex * vertex_array[[buffer(0)]], unsigned int vid[[vertex_id]]) {
ColorInOut out;
out.position = float4(float2(vertex_array[vid].p.x, vertex_array[vid].p.y), 0.0, 1.0);
out.color = float4(float3(vertex_array[vid].c.r, vertex_array[vid].c.g, vertex_array[vid].c.b), 1.0);
return out;
}
fragment float4 ps(ColorInOut in [[stage_in]]) {
return in.color;
}

Binary file not shown.

View File

@@ -0,0 +1,14 @@
#include <metal_stdlib>
using namespace metal;
struct SumInput {
device uint *data;
volatile device atomic_uint *sum;
};
kernel void sum(device SumInput& input [[ buffer(0) ]],
uint gid [[ thread_position_in_grid ]])
{
atomic_fetch_add_explicit(input.sum, input.data[gid], memory_order_relaxed);
}

View File

@@ -0,0 +1,95 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
use std::mem;
static LIBRARY_SRC: &str = include_str!("compute-argument-buffer.metal");
fn main() {
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
let command_queue = device.new_command_queue();
let data = [
1u32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30,
];
let buffer = device.new_buffer_with_data(
unsafe { mem::transmute(data.as_ptr()) },
(data.len() * mem::size_of::<u32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache,
);
let sum = {
let data = [0u32];
device.new_buffer_with_data(
unsafe { mem::transmute(data.as_ptr()) },
(data.len() * mem::size_of::<u32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache,
)
};
let command_buffer = command_queue.new_command_buffer();
let encoder = command_buffer.new_compute_command_encoder();
let library = device
.new_library_with_source(LIBRARY_SRC, &CompileOptions::new())
.unwrap();
let kernel = library.get_function("sum", None).unwrap();
let argument_encoder = kernel.new_argument_encoder(0);
let arg_buffer = device.new_buffer(
argument_encoder.encoded_length(),
MTLResourceOptions::empty(),
);
argument_encoder.set_argument_buffer(&arg_buffer, 0);
argument_encoder.set_buffer(0, &buffer, 0);
argument_encoder.set_buffer(1, &sum, 0);
let pipeline_state_descriptor = ComputePipelineDescriptor::new();
pipeline_state_descriptor.set_compute_function(Some(&kernel));
let pipeline_state = device
.new_compute_pipeline_state_with_function(
pipeline_state_descriptor.compute_function().unwrap(),
)
.unwrap();
encoder.set_compute_pipeline_state(&pipeline_state);
encoder.set_buffer(0, Some(&arg_buffer), 0);
encoder.use_resource(&buffer, MTLResourceUsage::Read);
encoder.use_resource(&sum, MTLResourceUsage::Write);
let width = 16;
let thread_group_count = MTLSize {
width,
height: 1,
depth: 1,
};
let thread_group_size = MTLSize {
width: (data.len() as u64 + width) / width,
height: 1,
depth: 1,
};
encoder.dispatch_thread_groups(thread_group_count, thread_group_size);
encoder.end_encoding();
command_buffer.commit();
command_buffer.wait_until_completed();
let ptr = sum.contents() as *mut u32;
unsafe {
assert_eq!(465, *ptr);
}
});
}

View File

@@ -0,0 +1,24 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
fn main() {
let library_data = include_bytes!("shaders.metallib");
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
let library = device.new_library_with_data(&library_data[..]).unwrap();
let kernel = library.get_function("sum", None).unwrap();
println!("Function name: {}", kernel.name());
println!("Function type: {:?}", kernel.function_type());
println!("OK");
});
}

194
vendor/metal/examples/compute/main.rs vendored Normal file
View File

@@ -0,0 +1,194 @@
use metal::*;
use objc::rc::autoreleasepool;
use std::path::PathBuf;
const NUM_SAMPLES: u64 = 2;
fn main() {
let num_elements = std::env::args()
.nth(1)
.map(|s| s.parse::<u32>().unwrap())
.unwrap_or(64 * 64);
autoreleasepool(|| {
let device = Device::system_default().expect("No device found");
let mut cpu_start = 0;
let mut gpu_start = 0;
device.sample_timestamps(&mut cpu_start, &mut gpu_start);
let counter_sample_buffer = create_counter_sample_buffer(&device);
let destination_buffer = device.new_buffer(
(std::mem::size_of::<u64>() * NUM_SAMPLES as usize) as u64,
MTLResourceOptions::StorageModeShared,
);
let counter_sampling_point = MTLCounterSamplingPoint::AtStageBoundary;
assert!(device.supports_counter_sampling(counter_sampling_point));
let command_queue = device.new_command_queue();
let command_buffer = command_queue.new_command_buffer();
let compute_pass_descriptor = ComputePassDescriptor::new();
handle_compute_pass_sample_buffer_attachment(
compute_pass_descriptor,
&counter_sample_buffer,
);
let encoder =
command_buffer.compute_command_encoder_with_descriptor(compute_pass_descriptor);
let pipeline_state = create_pipeline_state(&device);
encoder.set_compute_pipeline_state(&pipeline_state);
let (buffer, sum) = create_input_and_output_buffers(&device, num_elements);
encoder.set_buffer(0, Some(&buffer), 0);
encoder.set_buffer(1, Some(&sum), 0);
let num_threads = pipeline_state.thread_execution_width();
let thread_group_count = MTLSize {
width: ((num_elements as NSUInteger + num_threads) / num_threads),
height: 1,
depth: 1,
};
let thread_group_size = MTLSize {
width: num_threads,
height: 1,
depth: 1,
};
encoder.dispatch_thread_groups(thread_group_count, thread_group_size);
encoder.end_encoding();
resolve_samples_into_buffer(command_buffer, &counter_sample_buffer, &destination_buffer);
command_buffer.commit();
command_buffer.wait_until_completed();
let mut cpu_end = 0;
let mut gpu_end = 0;
device.sample_timestamps(&mut cpu_end, &mut gpu_end);
let ptr = sum.contents() as *mut u32;
println!("Compute shader sum: {}", unsafe { *ptr });
unsafe {
assert_eq!(num_elements, *ptr);
}
handle_timestamps(&destination_buffer, cpu_start, cpu_end, gpu_start, gpu_end);
});
}
fn create_pipeline_state(device: &Device) -> ComputePipelineState {
let library_path =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/compute/shaders.metallib");
let library = device.new_library_with_file(library_path).unwrap();
let kernel = library.get_function("sum", None).unwrap();
let pipeline_state_descriptor = ComputePipelineDescriptor::new();
pipeline_state_descriptor.set_compute_function(Some(&kernel));
device
.new_compute_pipeline_state_with_function(
pipeline_state_descriptor.compute_function().unwrap(),
)
.unwrap()
}
fn handle_compute_pass_sample_buffer_attachment(
compute_pass_descriptor: &ComputePassDescriptorRef,
counter_sample_buffer: &CounterSampleBufferRef,
) {
let sample_buffer_attachment_descriptor = compute_pass_descriptor
.sample_buffer_attachments()
.object_at(0)
.unwrap();
sample_buffer_attachment_descriptor.set_sample_buffer(counter_sample_buffer);
sample_buffer_attachment_descriptor.set_start_of_encoder_sample_index(0);
sample_buffer_attachment_descriptor.set_end_of_encoder_sample_index(1);
}
fn resolve_samples_into_buffer(
command_buffer: &CommandBufferRef,
counter_sample_buffer: &CounterSampleBufferRef,
destination_buffer: &BufferRef,
) {
let blit_encoder = command_buffer.new_blit_command_encoder();
blit_encoder.resolve_counters(
counter_sample_buffer,
crate::NSRange::new(0_u64, NUM_SAMPLES),
destination_buffer,
0_u64,
);
blit_encoder.end_encoding();
}
fn handle_timestamps(
resolved_sample_buffer: &BufferRef,
cpu_start: u64,
cpu_end: u64,
gpu_start: u64,
gpu_end: u64,
) {
let samples = unsafe {
std::slice::from_raw_parts(
resolved_sample_buffer.contents() as *const u64,
NUM_SAMPLES as usize,
)
};
let pass_start = samples[0];
let pass_end = samples[1];
let cpu_time_span = cpu_end - cpu_start;
let gpu_time_span = gpu_end - gpu_start;
let micros = microseconds_between_begin(pass_start, pass_end, gpu_time_span, cpu_time_span);
println!("Compute pass duration: {} µs", micros);
}
fn create_counter_sample_buffer(device: &Device) -> CounterSampleBuffer {
let counter_sample_buffer_desc = metal::CounterSampleBufferDescriptor::new();
counter_sample_buffer_desc.set_storage_mode(metal::MTLStorageMode::Shared);
counter_sample_buffer_desc.set_sample_count(NUM_SAMPLES);
let counter_sets = device.counter_sets();
let timestamp_counter = counter_sets.iter().find(|cs| cs.name() == "timestamp");
counter_sample_buffer_desc
.set_counter_set(timestamp_counter.expect("No timestamp counter found"));
device
.new_counter_sample_buffer_with_descriptor(&counter_sample_buffer_desc)
.unwrap()
}
fn create_input_and_output_buffers(
device: &Device,
num_elements: u32,
) -> (metal::Buffer, metal::Buffer) {
let data = vec![1u32; num_elements as usize];
let buffer = device.new_buffer_with_data(
unsafe { std::mem::transmute(data.as_ptr()) },
(data.len() * std::mem::size_of::<u32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache,
);
let sum = {
let data = [0u32];
device.new_buffer_with_data(
unsafe { std::mem::transmute(data.as_ptr()) },
(data.len() * std::mem::size_of::<u32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache,
)
};
(buffer, sum)
}
/// <https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/converting_gpu_timestamps_into_cpu_time>
fn microseconds_between_begin(begin: u64, end: u64, gpu_time_span: u64, cpu_time_span: u64) -> f64 {
let time_span = (end as f64) - (begin as f64);
let nanoseconds = time_span / (gpu_time_span as f64) * (cpu_time_span as f64);
nanoseconds / 1000.0
}

View File

@@ -0,0 +1,10 @@
#include <metal_stdlib>
using namespace metal;
kernel void sum(device uint *data [[ buffer(0) ]],
volatile device atomic_uint *sum [[ buffer(1) ]],
uint gid [[ thread_position_in_grid ]])
{
atomic_fetch_add_explicit(sum, data[gid], memory_order_relaxed);
}

Binary file not shown.

50
vendor/metal/examples/events/main.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
// Copyright 2020 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use dispatch::{Queue, QueueAttribute};
use metal::*;
/// This example replicates `Synchronizing Events Between a GPU and the CPU` article.
/// See https://developer.apple.com/documentation/metal/synchronization/synchronizing_events_between_a_gpu_and_the_cpu
fn main() {
let device = Device::system_default().expect("No device found");
let command_queue = device.new_command_queue();
let command_buffer = command_queue.new_command_buffer();
// Shareable event
let shared_event = device.new_shared_event();
// Shareable event listener
let my_queue = Queue::create(
"com.example.apple-samplecode.MyQueue",
QueueAttribute::Serial,
);
// Enable `dispatch` feature to use dispatch queues,
// otherwise unsafe `from_queue_handle` is available for use with native APIs.
let shared_event_listener = SharedEventListener::from_queue(&my_queue);
// Register CPU work
let notify_block = block::ConcreteBlock::new(move |evt: &SharedEventRef, val: u64| {
println!("Got notification from GPU: {}", val);
evt.set_signaled_value(3);
});
shared_event.notify(&shared_event_listener, 2, notify_block.copy());
// Encode GPU work
command_buffer.encode_signal_event(&shared_event, 1);
command_buffer.encode_signal_event(&shared_event, 2);
command_buffer.encode_wait_for_event(&shared_event, 3);
command_buffer.commit();
command_buffer.wait_until_completed();
println!("Done");
}

30
vendor/metal/examples/fence/main.rs vendored Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2020 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
fn main() {
let device = Device::system_default().expect("No device found");
let command_queue = device.new_command_queue();
let command_buffer = command_queue.new_command_buffer();
let fence = device.new_fence();
let blit_encoder = command_buffer.new_blit_command_encoder();
blit_encoder.update_fence(&fence);
blit_encoder.end_encoding();
let compute_encoder = command_buffer.new_compute_command_encoder();
compute_encoder.wait_for_fence(&fence);
compute_encoder.end_encoding();
command_buffer.commit();
command_buffer.wait_until_completed();
println!("Done");
}

View File

@@ -0,0 +1,11 @@
## headless-render
Renders the triangle from the [window example](../window) headlessly and then writes it to a PNG file.
![Screenshot of the final render](./screenshot.png)
## To Run
```
cargo run --example headless-render
```

View File

@@ -0,0 +1,159 @@
use std::mem;
use std::path::PathBuf;
use std::fs::File;
use std::io::BufWriter;
use metal::{
Buffer, Device, DeviceRef, LibraryRef, MTLClearColor, MTLLoadAction, MTLOrigin, MTLPixelFormat,
MTLPrimitiveType, MTLRegion, MTLResourceOptions, MTLSize, MTLStoreAction, RenderPassDescriptor,
RenderPassDescriptorRef, RenderPipelineDescriptor, RenderPipelineState, Texture,
TextureDescriptor, TextureRef,
};
use png::ColorType;
const VIEW_WIDTH: u64 = 512;
const VIEW_HEIGHT: u64 = 512;
const TOTAL_BYTES: usize = (VIEW_WIDTH * VIEW_HEIGHT * 4) as usize;
const VERTEX_SHADER: &'static str = "triangle_vertex";
const FRAGMENT_SHADER: &'static str = "triangle_fragment";
// [2 bytes position, 3 bytes color] * 3
#[rustfmt::skip]
const VERTEX_ATTRIBS: [f32; 15] = [
0.0, 0.5, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.0, 1.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0,
];
/// This example shows how to render headlessly by:
///
/// 1. Rendering a triangle to an MtlDrawable
///
/// 2. Waiting for the render to complete and the color texture to be synchronized with the CPU
/// by using a blit command encoder
///
/// 3. Reading the texture bytes from the MtlTexture
///
/// 4. Saving the texture to a PNG file
fn main() {
let device = Device::system_default().expect("No device found");
let texture = create_texture(&device);
let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/window/shaders.metallib");
let library = device.new_library_with_file(library_path).unwrap();
let pipeline_state = prepare_pipeline_state(&device, &library);
let command_queue = device.new_command_queue();
let vertex_buffer = create_vertex_buffer(&device);
let render_pass_descriptor = RenderPassDescriptor::new();
initialize_color_attachment(&render_pass_descriptor, &texture);
let command_buffer = command_queue.new_command_buffer();
let rc_encoder = command_buffer.new_render_command_encoder(&render_pass_descriptor);
rc_encoder.set_render_pipeline_state(&pipeline_state);
rc_encoder.set_vertex_buffer(0, Some(&vertex_buffer), 0);
rc_encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 3);
rc_encoder.end_encoding();
render_pass_descriptor
.color_attachments()
.object_at(0)
.unwrap()
.set_load_action(MTLLoadAction::DontCare);
let blit_encoder = command_buffer.new_blit_command_encoder();
blit_encoder.synchronize_resource(&texture);
blit_encoder.end_encoding();
command_buffer.commit();
command_buffer.wait_until_completed();
save_image(&texture);
}
fn save_image(texture: &TextureRef) {
let mut image = vec![0; TOTAL_BYTES];
texture.get_bytes(
image.as_mut_ptr() as *mut std::ffi::c_void,
VIEW_WIDTH * 4,
MTLRegion {
origin: MTLOrigin { x: 0, y: 0, z: 0 },
size: MTLSize {
width: VIEW_WIDTH,
height: VIEW_HEIGHT,
depth: 1,
},
},
0,
);
let out_file =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/headless-render/out.png");
let file = File::create(&out_file).unwrap();
let ref mut w = BufWriter::new(file);
let mut encoder = png::Encoder::new(w, VIEW_WIDTH as u32, VIEW_HEIGHT as u32);
encoder.set_color(ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header().unwrap();
writer.write_image_data(&image).unwrap();
println!("Image saved to {:?}", out_file);
}
fn create_texture(device: &Device) -> Texture {
let texture = TextureDescriptor::new();
texture.set_width(VIEW_WIDTH);
texture.set_height(VIEW_HEIGHT);
texture.set_pixel_format(MTLPixelFormat::RGBA8Unorm);
device.new_texture(&texture)
}
fn prepare_pipeline_state(device: &DeviceRef, library: &LibraryRef) -> RenderPipelineState {
let vert = library.get_function(VERTEX_SHADER, None).unwrap();
let frag = library.get_function(FRAGMENT_SHADER, None).unwrap();
let pipeline_state_descriptor = RenderPipelineDescriptor::new();
pipeline_state_descriptor.set_vertex_function(Some(&vert));
pipeline_state_descriptor.set_fragment_function(Some(&frag));
pipeline_state_descriptor
.color_attachments()
.object_at(0)
.unwrap()
.set_pixel_format(MTLPixelFormat::RGBA8Unorm);
device
.new_render_pipeline_state(&pipeline_state_descriptor)
.unwrap()
}
fn create_vertex_buffer(device: &DeviceRef) -> Buffer {
device.new_buffer_with_data(
VERTEX_ATTRIBS.as_ptr() as *const _,
(VERTEX_ATTRIBS.len() * mem::size_of::<f32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged,
)
}
fn initialize_color_attachment(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) {
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
color_attachment.set_texture(Some(texture));
color_attachment.set_load_action(MTLLoadAction::Clear);
color_attachment.set_clear_color(MTLClearColor::new(0.5, 0.2, 0.2, 1.0));
color_attachment.set_store_action(MTLStoreAction::Store);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

17
vendor/metal/examples/library/main.rs vendored Normal file
View File

@@ -0,0 +1,17 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
const PROGRAM: &'static str = "";
fn main() {
let device = Device::system_default().expect("no device found");
let options = CompileOptions::new();
let _library = device.new_library_with_source(PROGRAM, &options);
}

View File

@@ -0,0 +1,128 @@
extern crate objc;
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use metal::*;
use objc::{rc::autoreleasepool, runtime::YES};
use std::mem;
use winit::{
event::{Event, WindowEvent},
event_loop::ControlFlow,
raw_window_handle::{HasWindowHandle, RawWindowHandle},
};
fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) {
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
color_attachment.set_texture(Some(texture));
color_attachment.set_load_action(MTLLoadAction::Clear);
color_attachment.set_clear_color(MTLClearColor::new(0.2, 0.2, 0.25, 1.0));
color_attachment.set_store_action(MTLStoreAction::Store);
}
fn main() {
let event_loop = winit::event_loop::EventLoop::new().unwrap();
let size = winit::dpi::LogicalSize::new(800, 600);
let window = winit::window::WindowBuilder::new()
.with_inner_size(size)
.with_title("Metal Mesh Shader Example".to_string())
.build(&event_loop)
.unwrap();
let device = Device::system_default().expect("no device found");
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_presents_with_transaction(false);
unsafe {
if let Ok(RawWindowHandle::AppKit(rw)) = window.window_handle().map(|wh| wh.as_raw()) {
let view = rw.ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(mem::transmute(layer.as_ref()));
}
}
let draw_size = window.inner_size();
layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64));
let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/mesh-shader/shaders.metallib");
let library = device.new_library_with_file(library_path).unwrap();
let mesh = library.get_function("mesh_function", None).unwrap();
let frag = library.get_function("fragment_function", None).unwrap();
let pipeline_state_desc = MeshRenderPipelineDescriptor::new();
pipeline_state_desc
.color_attachments()
.object_at(0)
.unwrap()
.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
pipeline_state_desc.set_mesh_function(Some(&mesh));
pipeline_state_desc.set_fragment_function(Some(&frag));
let pipeline_state = device
.new_mesh_render_pipeline_state(&pipeline_state_desc)
.unwrap();
let command_queue = device.new_command_queue();
event_loop
.run(move |event, event_loop| {
autoreleasepool(|| {
event_loop.set_control_flow(ControlFlow::Poll);
match event {
Event::AboutToWait => {
window.request_redraw();
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::Resized(size) => {
layer.set_drawable_size(CGSize::new(
size.width as f64,
size.height as f64,
));
}
WindowEvent::RedrawRequested => {
let drawable = match layer.next_drawable() {
Some(drawable) => drawable,
None => return,
};
let render_pass_descriptor = RenderPassDescriptor::new();
prepare_render_pass_descriptor(
&render_pass_descriptor,
drawable.texture(),
);
let command_buffer = command_queue.new_command_buffer();
let encoder =
command_buffer.new_render_command_encoder(&render_pass_descriptor);
encoder.set_render_pipeline_state(&pipeline_state);
encoder.draw_mesh_threads(
MTLSize::new(1, 1, 1),
MTLSize::new(1, 1, 1),
MTLSize::new(1, 1, 1),
);
encoder.end_encoding();
command_buffer.present_drawable(&drawable);
command_buffer.commit();
}
_ => (),
},
_ => {}
}
});
})
.unwrap();
}

View File

@@ -0,0 +1,30 @@
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
};
using mesh_t = mesh<VertexOut, void, 3, 1, topology::triangle>;
[[mesh]] void mesh_function(mesh_t m) {
VertexOut v;
v.position = float4(-1.0, -1.0, 0.0, 1.0);
m.set_primitive_count(1);
m.set_vertex(0, v);
v.position = float4(0.0, 1.0, 0.0, 1.0);
m.set_vertex(1, v);
v.position = float4(1.0, -1.0, 0.0, 1.0);
m.set_vertex(2, v);
m.set_index(0, 0);
m.set_index(1, 1);
m.set_index(2, 2);
}
fragment half4 fragment_function() {
return half4(0.1, 1.0, 0.1, 1.0);
}

Binary file not shown.

148
vendor/metal/examples/mps/main.rs vendored Normal file
View File

@@ -0,0 +1,148 @@
use metal::*;
use std::ffi::c_void;
use std::mem;
#[repr(C)]
struct Vertex {
xyz: [f32; 3],
}
type Ray = mps::MPSRayOriginMinDistanceDirectionMaxDistance;
type Intersection = mps::MPSIntersectionDistancePrimitiveIndexCoordinates;
// Original example taken from https://sergeyreznik.github.io/metal-ray-tracer/part-1/index.html
fn main() {
let device = Device::system_default().expect("No device found");
let library_path =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/mps/shaders.metallib");
let library = device
.new_library_with_file(library_path)
.expect("Failed to load shader library");
let generate_rays_pipeline = create_pipeline("generateRays", &library, &device);
let queue = device.new_command_queue();
let command_buffer = queue.new_command_buffer();
// Simple vertex/index buffer data
let vertices: [Vertex; 3] = [
Vertex {
xyz: [0.25, 0.25, 0.0],
},
Vertex {
xyz: [0.75, 0.25, 0.0],
},
Vertex {
xyz: [0.50, 0.75, 0.0],
},
];
let vertex_stride = mem::size_of::<Vertex>();
let indices: [u32; 3] = [0, 1, 2];
// Vertex data should be stored in private or managed buffers on discrete GPU systems (AMD, NVIDIA).
// Private buffers are stored entirely in GPU memory and cannot be accessed by the CPU. Managed
// buffers maintain a copy in CPU memory and a copy in GPU memory.
let buffer_opts = MTLResourceOptions::StorageModeManaged;
let vertex_buffer = device.new_buffer_with_data(
vertices.as_ptr() as *const c_void,
(vertex_stride * vertices.len()) as u64,
buffer_opts,
);
let index_buffer = device.new_buffer_with_data(
indices.as_ptr() as *const c_void,
(mem::size_of::<u32>() * indices.len()) as u64,
buffer_opts,
);
// Build an acceleration structure using our vertex and index buffers containing the single triangle.
let acceleration_structure = mps::TriangleAccelerationStructure::from_device(&device)
.expect("Failed to create acceleration structure");
acceleration_structure.set_vertex_buffer(Some(&vertex_buffer));
acceleration_structure.set_vertex_stride(vertex_stride as u64);
acceleration_structure.set_index_buffer(Some(&index_buffer));
acceleration_structure.set_index_type(mps::MPSDataType::UInt32);
acceleration_structure.set_triangle_count(1);
acceleration_structure.set_usage(mps::MPSAccelerationStructureUsage::None);
acceleration_structure.rebuild();
let ray_intersector =
mps::RayIntersector::from_device(&device).expect("Failed to create ray intersector");
ray_intersector.set_ray_stride(mem::size_of::<Ray>() as u64);
ray_intersector.set_ray_data_type(mps::MPSRayDataType::OriginMinDistanceDirectionMaxDistance);
ray_intersector.set_intersection_stride(mem::size_of::<Intersection>() as u64);
ray_intersector.set_intersection_data_type(
mps::MPSIntersectionDataType::DistancePrimitiveIndexCoordinates,
);
// Create a buffer to hold generated rays and intersection results
let ray_count = 1024;
let ray_buffer = device.new_buffer(
(mem::size_of::<Ray>() * ray_count) as u64,
MTLResourceOptions::StorageModePrivate,
);
let intersection_buffer = device.new_buffer(
(mem::size_of::<Intersection>() * ray_count) as u64,
MTLResourceOptions::StorageModePrivate,
);
// Run the compute shader to generate rays
let encoder = command_buffer.new_compute_command_encoder();
encoder.set_buffer(0, Some(&ray_buffer), 0);
encoder.set_compute_pipeline_state(&generate_rays_pipeline);
encoder.dispatch_thread_groups(
MTLSize {
width: 4,
height: 4,
depth: 1,
},
MTLSize {
width: 8,
height: 8,
depth: 1,
},
);
encoder.end_encoding();
// Intersect rays with triangles inside acceleration structure
ray_intersector.encode_intersection_to_command_buffer(
&command_buffer,
mps::MPSIntersectionType::Nearest,
&ray_buffer,
0,
&intersection_buffer,
0,
ray_count as u64,
&acceleration_structure,
);
command_buffer.commit();
command_buffer.wait_until_completed();
println!("Done");
}
fn create_pipeline(func: &str, library: &LibraryRef, device: &DeviceRef) -> ComputePipelineState {
// Create compute pipelines will will execute code on the GPU
let compute_descriptor = ComputePipelineDescriptor::new();
// Set to YES to allow compiler to make certain optimizations
compute_descriptor.set_thread_group_size_is_multiple_of_thread_execution_width(true);
let function = library.get_function(func, None).unwrap();
compute_descriptor.set_compute_function(Some(&function));
let pipeline = device
.new_compute_pipeline_state(&compute_descriptor)
.unwrap();
pipeline
}

26
vendor/metal/examples/mps/shaders.metal vendored Normal file
View File

@@ -0,0 +1,26 @@
//
// Created by Sergey Reznik on 9/15/18.
// Copyright © 2018 Serhii Rieznik. All rights reserved.
//
// Taken from https://github.com/sergeyreznik/metal-ray-tracer/tree/part-1/source/Shaders
// MIT License https://github.com/sergeyreznik/metal-ray-tracer/blob/part-1/LICENSE
#include <MetalPerformanceShaders/MetalPerformanceShaders.h>
using Ray = MPSRayOriginMinDistanceDirectionMaxDistance;
using Intersection = MPSIntersectionDistancePrimitiveIndexCoordinates;
kernel void generateRays(
device Ray* rays [[buffer(0)]],
uint2 coordinates [[thread_position_in_grid]],
uint2 size [[threads_per_grid]])
{
float2 uv = float2(coordinates) / float2(size - 1);
uint rayIndex = coordinates.x + coordinates.y * size.x;
rays[rayIndex].origin = MPSPackedFloat3(uv.x, uv.y, -1.0);
rays[rayIndex].direction = MPSPackedFloat3(0.0, 0.0, 1.0);
rays[rayIndex].minDistance = 0.0f;
rays[rayIndex].maxDistance = 2.0f;
}

Binary file not shown.

View File

@@ -0,0 +1,11 @@
## Raytracing
A good showcase of Metal 3 raytracing features.
![Screenshot of the final render](./screenshot.png)
## To Run
```
cargo run --example raytracing
```

View File

@@ -0,0 +1,20 @@
use glam::f32::Vec4;
#[repr(C)]
pub struct Camera {
pub position: Vec4,
pub right: Vec4,
pub up: Vec4,
pub forward: Vec4,
}
impl Camera {
pub fn new() -> Self {
Self {
position: Vec4::new(0.0, 3.0, 10.0, 0.0),
right: Vec4::new(1.0, 0.0, 0.0, 0.0),
up: Vec4::new(0.0, 1.0, 0.0, 0.0),
forward: Vec4::new(0.0, 0.0, -1.0, 0.0),
}
}
}

View File

@@ -0,0 +1,448 @@
use std::{
mem::{size_of, transmute},
sync::Arc,
};
use glam::{
f32::{Mat4, Vec3, Vec4},
Vec4Swizzles,
};
use metal::*;
pub const GEOMETRY_MASK_TRIANGLE: u32 = 1;
pub const GEOMETRY_MASK_SPHERE: u32 = 2;
pub const GEOMETRY_MASK_LIGHT: u32 = 4;
pub const FACE_MASK_NONE: u16 = 0;
pub const FACE_MASK_NEGATIVE_X: u16 = 1 << 0;
pub const FACE_MASK_POSITIVE_X: u16 = 1 << 1;
pub const FACE_MASK_NEGATIVE_Y: u16 = 1 << 2;
pub const FACE_MASK_POSITIVE_Y: u16 = 1 << 3;
pub const FACE_MASK_NEGATIVE_Z: u16 = 1 << 4;
pub const FACE_MASK_POSITIVE_Z: u16 = 1 << 5;
pub const FACE_MASK_ALL: u16 = (1 << 6) - 1;
pub trait Geometry {
fn upload_to_buffers(&mut self) {
todo!()
}
fn clear(&mut self) {
todo!()
}
fn get_geometry_descriptor(&self) -> AccelerationStructureGeometryDescriptor {
todo!()
}
fn get_resources(&self) -> Vec<Resource> {
todo!()
}
fn get_intersection_function_name(&self) -> Option<&str> {
None
}
}
pub fn compute_triangle_normal(v0: &Vec3, v1: &Vec3, v2: &Vec3) -> Vec3 {
let e1 = Vec3::normalize(*v1 - *v0);
let e2 = Vec3::normalize(*v2 - *v0);
return Vec3::cross(e1, e2);
}
#[derive(Default)]
#[repr(C)]
pub struct Triangle {
pub normals: [Vec4; 3],
pub colours: [Vec4; 3],
}
pub fn get_managed_buffer_storage_mode() -> MTLResourceOptions {
return MTLResourceOptions::StorageModeManaged;
}
pub struct TriangleGeometry {
pub device: Device,
pub name: String,
pub index_buffer: Option<Buffer>,
pub vertex_position_buffer: Option<Buffer>,
pub vertex_normal_buffer: Option<Buffer>,
pub vertex_colour_buffer: Option<Buffer>,
pub per_primitive_data_buffer: Option<Buffer>,
pub indices: Vec<u16>,
pub vertices: Vec<Vec4>,
pub normals: Vec<Vec4>,
pub colours: Vec<Vec4>,
pub triangles: Vec<Triangle>,
}
impl TriangleGeometry {
pub fn new(device: Device, name: String) -> Self {
Self {
device,
name,
index_buffer: None,
vertex_position_buffer: None,
vertex_normal_buffer: None,
vertex_colour_buffer: None,
per_primitive_data_buffer: None,
indices: Vec::new(),
vertices: Vec::new(),
normals: Vec::new(),
colours: Vec::new(),
triangles: Vec::new(),
}
}
pub fn add_cube_face_with_cube_vertices(
&mut self,
cube_vertices: &[Vec3],
colour: Vec3,
i0: u16,
i1: u16,
i2: u16,
i3: u16,
inward_normals: bool,
) {
let v0 = cube_vertices[i0 as usize];
let v1 = cube_vertices[i1 as usize];
let v2 = cube_vertices[i2 as usize];
let v3 = cube_vertices[i3 as usize];
let n0 = compute_triangle_normal(&v0, &v1, &v2) * if inward_normals { -1f32 } else { 1f32 };
let n1 = compute_triangle_normal(&v0, &v2, &v3) * if inward_normals { -1f32 } else { 1f32 };
let first_index = self.indices.len();
let base_index = self.vertices.len() as u16;
self.indices.push(base_index + 0);
self.indices.push(base_index + 1);
self.indices.push(base_index + 2);
self.indices.push(base_index + 0);
self.indices.push(base_index + 2);
self.indices.push(base_index + 3);
self.vertices.push(From::from((v0, 0.0)));
self.vertices.push(From::from((v1, 0.0)));
self.vertices.push(From::from((v2, 0.0)));
self.vertices.push(From::from((v3, 0.0)));
self.normals
.push(From::from((Vec3::normalize(n0 + n1), 0.0)));
self.normals.push(From::from((n0, 0.0)));
self.normals
.push(From::from((Vec3::normalize(n0 + n1), 0.0)));
self.normals.push(From::from((n1, 0.0)));
for _ in 0..4 {
self.colours.push(From::from((colour, 0.0)));
}
for triangle_index in 0..2 {
let mut triangle = Triangle::default();
for i in 0..3 {
let index = self.indices[first_index + triangle_index * 3 + i];
triangle.normals[i] = self.normals[index as usize];
triangle.colours[i] = self.colours[index as usize];
}
self.triangles.push(triangle);
}
}
pub fn add_cube_with_faces(
&mut self,
face_mask: u16,
colour: Vec3,
transform: Mat4,
inward_normals: bool,
) {
let mut cube_vertices = [
Vec3::new(-0.5, -0.5, -0.5),
Vec3::new(0.5, -0.5, -0.5),
Vec3::new(-0.5, 0.5, -0.5),
Vec3::new(0.5, 0.5, -0.5),
Vec3::new(-0.5, -0.5, 0.5),
Vec3::new(0.5, -0.5, 0.5),
Vec3::new(-0.5, 0.5, 0.5),
Vec3::new(0.5, 0.5, 0.5),
];
for i in 0..8 {
let transformed_vertex = Vec4::from((cube_vertices[i], 1.0));
let transformed_vertex = transform * transformed_vertex;
cube_vertices[i] = transformed_vertex.xyz();
}
const CUBE_INDICES: [[u16; 4]; 6] = [
[0, 4, 6, 2],
[1, 3, 7, 5],
[0, 1, 5, 4],
[2, 6, 7, 3],
[0, 2, 3, 1],
[4, 5, 7, 6],
];
for face in 0..6 {
if face_mask & (1 << face) != 0 {
self.add_cube_face_with_cube_vertices(
&cube_vertices,
colour,
CUBE_INDICES[face][0],
CUBE_INDICES[face][1],
CUBE_INDICES[face][2],
CUBE_INDICES[face][3],
inward_normals,
);
}
}
}
}
impl Geometry for TriangleGeometry {
fn upload_to_buffers(&mut self) {
self.index_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.indices.as_ptr()),
(self.indices.len() * size_of::<u16>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.vertex_position_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.vertices.as_ptr()),
(self.vertices.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.vertex_normal_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.normals.as_ptr()),
(self.normals.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.vertex_colour_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.colours.as_ptr()),
(self.colours.len() * size_of::<Vec4>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.per_primitive_data_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.triangles.as_ptr()),
(self.triangles.len() * size_of::<Triangle>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.index_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.index_buffer.as_ref().unwrap().length(),
));
self.vertex_position_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.vertex_position_buffer.as_ref().unwrap().length(),
));
self.vertex_normal_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.vertex_normal_buffer.as_ref().unwrap().length(),
));
self.vertex_colour_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.vertex_colour_buffer.as_ref().unwrap().length(),
));
self.per_primitive_data_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.per_primitive_data_buffer.as_ref().unwrap().length(),
));
self.index_buffer
.as_ref()
.unwrap()
.set_label(&format!("index buffer of {}", self.name));
self.vertex_position_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex position buffer of {}", self.name));
self.vertex_normal_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex normal buffer of {}", self.name));
self.vertex_colour_buffer
.as_ref()
.unwrap()
.set_label(&format!("vertex colour buffer of {}", self.name));
self.per_primitive_data_buffer
.as_ref()
.unwrap()
.set_label(&format!("per primitive data buffer of {}", self.name));
}
fn clear(&mut self) {
self.indices.clear();
self.vertices.clear();
self.normals.clear();
self.colours.clear();
self.triangles.clear();
}
fn get_geometry_descriptor(&self) -> AccelerationStructureGeometryDescriptor {
let descriptor = AccelerationStructureTriangleGeometryDescriptor::descriptor();
descriptor.set_index_buffer(Some(self.index_buffer.as_ref().unwrap()));
descriptor.set_index_type(MTLIndexType::UInt16);
descriptor.set_vertex_buffer(Some(self.vertex_position_buffer.as_ref().unwrap()));
descriptor.set_vertex_stride(size_of::<Vec4>() as NSUInteger);
descriptor.set_triangle_count((self.indices.len() / 3) as NSUInteger);
descriptor
.set_primitive_data_buffer(Some(self.per_primitive_data_buffer.as_ref().unwrap()));
descriptor.set_primitive_data_stride(size_of::<Triangle>() as NSUInteger);
descriptor.set_primitive_data_element_size(size_of::<Triangle>() as NSUInteger);
From::from(descriptor)
}
fn get_resources(&self) -> Vec<Resource> {
vec![
From::from(self.index_buffer.as_ref().unwrap().clone()),
From::from(self.vertex_normal_buffer.as_ref().unwrap().clone()),
From::from(self.vertex_colour_buffer.as_ref().unwrap().clone()),
]
}
}
#[repr(C)]
pub struct BoundingBox {
pub min: Vec3,
pub max: Vec3,
}
#[repr(C)]
pub struct Sphere {
pub origin_radius_squared: Vec4,
pub colour_radius: Vec4,
}
pub struct SphereGeometry {
pub device: Device,
pub sphere_buffer: Option<Buffer>,
pub bounding_box_buffer: Option<Buffer>,
pub per_primitive_data_buffer: Option<Buffer>,
pub spheres: Vec<Sphere>,
}
impl SphereGeometry {
pub fn new(device: Device) -> Self {
Self {
device,
sphere_buffer: None,
bounding_box_buffer: None,
per_primitive_data_buffer: None,
spheres: Vec::new(),
}
}
pub fn add_sphere_with_origin(&mut self, origin: Vec3, radius: f32, colour: Vec3) {
self.spheres.push(Sphere {
origin_radius_squared: Vec4::from((origin, radius * radius)),
colour_radius: Vec4::from((colour, radius)),
});
}
}
impl Geometry for SphereGeometry {
fn upload_to_buffers(&mut self) {
self.sphere_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(self.spheres.as_ptr()),
(self.spheres.len() * size_of::<Sphere>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.sphere_buffer
.as_ref()
.unwrap()
.set_label("sphere buffer");
let mut bounding_boxes = Vec::new();
for sphere in &self.spheres {
bounding_boxes.push(BoundingBox {
min: sphere.origin_radius_squared.xyz() - sphere.colour_radius.w,
max: sphere.origin_radius_squared.xyz() + sphere.colour_radius.w,
});
}
self.bounding_box_buffer = Some(unsafe {
self.device.new_buffer_with_data(
transmute(bounding_boxes.as_ptr()),
(bounding_boxes.len() * size_of::<BoundingBox>()) as NSUInteger,
get_managed_buffer_storage_mode(),
)
});
self.bounding_box_buffer
.as_ref()
.unwrap()
.set_label("bounding box buffer");
self.sphere_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.sphere_buffer.as_ref().unwrap().length(),
));
self.bounding_box_buffer
.as_ref()
.unwrap()
.did_modify_range(NSRange::new(
0,
self.bounding_box_buffer.as_ref().unwrap().length(),
));
}
fn clear(&mut self) {
self.spheres.clear();
}
fn get_geometry_descriptor(&self) -> AccelerationStructureGeometryDescriptor {
let descriptor = AccelerationStructureBoundingBoxGeometryDescriptor::descriptor();
descriptor.set_bounding_box_buffer(Some(self.bounding_box_buffer.as_ref().unwrap()));
descriptor.set_bounding_box_count(self.spheres.len() as NSUInteger);
descriptor.set_primitive_data_buffer(Some(&self.sphere_buffer.as_ref().unwrap()));
descriptor.set_primitive_data_stride(size_of::<Sphere>() as NSUInteger);
descriptor.set_primitive_data_element_size(size_of::<Sphere>() as NSUInteger);
From::from(descriptor)
}
fn get_resources(&self) -> Vec<Resource> {
return vec![From::from(self.sphere_buffer.as_ref().unwrap().clone())];
}
fn get_intersection_function_name(&self) -> Option<&str> {
Some("sphereIntersectionFunction")
}
}
pub struct GeometryInstance {
pub geometry: Arc<dyn Geometry>,
pub transform: Mat4,
pub mask: u32,
pub index_in_scene: NSUInteger,
}
#[repr(C)]
pub struct AreaLight {
pub position: Vec4,
pub forward: Vec4,
pub right: Vec4,
pub up: Vec4,
pub colour: Vec4,
}

View File

@@ -0,0 +1,89 @@
extern crate objc;
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use metal::*;
use objc::{rc::autoreleasepool, runtime::YES};
use std::mem;
use winit::{
event::{Event, WindowEvent},
event_loop::ControlFlow,
raw_window_handle::{HasWindowHandle, RawWindowHandle},
};
pub mod camera;
pub mod geometry;
pub mod renderer;
pub mod scene;
fn find_raytracing_supporting_device() -> Device {
for device in Device::all() {
if !device.supports_raytracing() {
continue;
}
if device.is_low_power() {
continue;
}
return device;
}
panic!("No device in this machine supports raytracing!")
}
fn main() {
let event_loop = winit::event_loop::EventLoop::new().unwrap();
let size = winit::dpi::LogicalSize::new(800, 600);
let window = winit::window::WindowBuilder::new()
.with_inner_size(size)
.with_title("Metal Raytracing Example".to_string())
.build(&event_loop)
.unwrap();
let device = find_raytracing_supporting_device();
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::RGBA16Float);
layer.set_presents_with_transaction(false);
unsafe {
if let Ok(RawWindowHandle::AppKit(rw)) = window.window_handle().map(|wh| wh.as_raw()) {
let view = rw.ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(mem::transmute(layer.as_ref()));
}
}
let draw_size = window.inner_size();
let cg_size = CGSize::new(draw_size.width as f64, draw_size.height as f64);
layer.set_drawable_size(cg_size);
let mut renderer = renderer::Renderer::new(device);
renderer.window_resized(cg_size);
event_loop
.run(move |event, event_loop| {
autoreleasepool(|| {
event_loop.set_control_flow(ControlFlow::Poll);
match event {
Event::AboutToWait => window.request_redraw(),
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::Resized(size) => {
let size = CGSize::new(size.width as f64, size.height as f64);
layer.set_drawable_size(size);
renderer.window_resized(size);
}
WindowEvent::RedrawRequested => {
renderer.draw(&layer);
}
_ => (),
},
_ => {}
}
});
})
.unwrap();
}

View File

@@ -0,0 +1,512 @@
use core_graphics_types::{base::CGFloat, geometry::CGSize};
use std::{
collections::BTreeMap,
ffi::c_void,
mem::{size_of, transmute},
ops::Index,
sync::{Arc, Condvar, Mutex},
};
use glam::{Vec3, Vec4, Vec4Swizzles};
use rand::{thread_rng, RngCore};
use metal::{foreign_types::ForeignType, *};
use crate::{camera::Camera, geometry::get_managed_buffer_storage_mode, scene::Scene};
#[repr(C)]
struct Uniforms {
pub width: u32,
pub height: u32,
pub frame_index: u32,
pub light_count: u32,
pub camera: Camera,
}
pub const MAX_FRAMES_IN_FLIGHT: NSUInteger = 3;
pub const ALIGNED_UNIFORMS_SIZE: NSUInteger = (size_of::<Uniforms>() as NSUInteger + 255) & !255;
pub const UNIFORM_BUFFER_SIZE: NSUInteger = MAX_FRAMES_IN_FLIGHT * ALIGNED_UNIFORMS_SIZE;
#[derive(Clone)]
struct Semaphore {
data: Arc<(Mutex<usize>, Condvar)>,
}
impl Semaphore {
fn new(capacity: usize) -> Self {
Self {
data: Arc::new((Mutex::new(capacity), Condvar::new())),
}
}
fn acquire(&self) {
let mut value = self.data.0.lock().unwrap();
while *value == 0 {
value = self.data.1.wait(value).unwrap();
}
*value -= 1;
}
fn release(&self) {
let mut value = self.data.0.lock().unwrap();
*value += 1;
self.data.1.notify_one();
}
}
pub struct Renderer {
pub device: Device,
pub scene: Scene,
pub uniform_buffer: Buffer,
pub resource_buffer: Buffer,
pub instance_acceleration_structure: AccelerationStructure,
pub accumulation_targets: [Texture; 2],
pub random_texture: Texture,
pub frame_index: NSUInteger,
pub uniform_buffer_index: NSUInteger,
pub uniform_buffer_offset: NSUInteger,
pub size: CGSize,
semaphore: Semaphore,
pub queue: CommandQueue,
instance_buffer: Buffer,
intersection_function_table: IntersectionFunctionTable,
primitive_acceleration_structures: Vec<AccelerationStructure>,
raytracing_pipeline: ComputePipelineState,
copy_pipeline: RenderPipelineState,
}
impl Renderer {
pub fn new(device: Device) -> Self {
let scene = Scene::new(device.clone());
let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/raytracing/shaders.metallib");
let library = device.new_library_with_file(library_path).unwrap();
let queue = device.new_command_queue();
let buffer_data = [0u8; UNIFORM_BUFFER_SIZE as usize];
let uniform_buffer = device.new_buffer_with_data(
buffer_data.as_ptr() as *const c_void,
UNIFORM_BUFFER_SIZE,
get_managed_buffer_storage_mode(),
);
uniform_buffer.set_label("uniform buffer");
let resources_stride = {
let mut max = 0;
for geometry in &scene.geometries {
let s = geometry.get_resources().len();
if s > max {
max = s;
}
}
max
};
let mut resource_buffer_data = vec![0u64; resources_stride * scene.geometries.len()];
for geometry_index in 0..scene.geometries.len() {
let geometry = scene.geometries[geometry_index].as_ref();
let resource_buffer_begin_index = resources_stride * geometry_index;
let resources = geometry.get_resources();
for argument_index in 0..resources.len() {
let resource_buffer_index = resource_buffer_begin_index + argument_index;
let resource = resources[argument_index].clone();
resource_buffer_data[resource_buffer_index] =
if resource.conforms_to_protocol::<MTLBuffer>().unwrap() {
let buffer = unsafe { Buffer::from_ptr(transmute(resource.into_ptr())) };
buffer.gpu_address()
} else if resource.conforms_to_protocol::<MTLTexture>().unwrap() {
let texture = unsafe { Texture::from_ptr(transmute(resource.into_ptr())) };
texture.gpu_resource_id()._impl
} else {
panic!("Unexpected resource!")
}
}
}
let resource_buffer = device.new_buffer_with_data(
resource_buffer_data.as_ptr() as *const c_void,
(resource_buffer_data.len() * size_of::<u64>()) as NSUInteger,
get_managed_buffer_storage_mode(),
);
resource_buffer.set_label("resource buffer");
resource_buffer.did_modify_range(NSRange::new(0, resource_buffer.length()));
let mut primitive_acceleration_structures = Vec::new();
for i in 0..scene.geometries.len() {
let mesh = scene.geometries[i].as_ref();
let geometry_descriptor = mesh.get_geometry_descriptor();
geometry_descriptor.set_intersection_function_table_offset(i as NSUInteger);
let geometry_descriptors = Array::from_owned_slice(&[geometry_descriptor]);
let accel_descriptor = PrimitiveAccelerationStructureDescriptor::descriptor();
accel_descriptor.set_geometry_descriptors(&geometry_descriptors);
let accel_descriptor: AccelerationStructureDescriptor = From::from(accel_descriptor);
primitive_acceleration_structures.push(
Self::new_acceleration_structure_with_descriptor(
&device,
&queue,
&accel_descriptor,
),
);
}
let mut instance_descriptors = vec![
MTLAccelerationStructureInstanceDescriptor::default();
scene.geometry_instances.len()
];
for instance_index in 0..scene.geometry_instances.len() {
let instance = scene.geometry_instances[instance_index].as_ref();
let geometry_index = instance.index_in_scene;
instance_descriptors[instance_index].acceleration_structure_index =
geometry_index as u32;
instance_descriptors[instance_index].options =
if instance.geometry.get_intersection_function_name().is_none() {
MTLAccelerationStructureInstanceOptions::Opaque
} else {
MTLAccelerationStructureInstanceOptions::None
};
instance_descriptors[instance_index].intersection_function_table_offset = 0;
instance_descriptors[instance_index].mask = instance.mask as u32;
for column in 0..4 {
for row in 0..3 {
instance_descriptors[instance_index].transformation_matrix[column][row] =
*instance.transform.col(column).index(row);
}
}
}
let instance_buffer = device.new_buffer_with_data(
instance_descriptors.as_ptr() as *const c_void,
(size_of::<MTLAccelerationStructureInstanceDescriptor>()
* scene.geometry_instances.len()) as NSUInteger,
get_managed_buffer_storage_mode(),
);
instance_buffer.set_label("instance buffer");
instance_buffer.did_modify_range(NSRange::new(0, instance_buffer.length()));
let accel_descriptor = InstanceAccelerationStructureDescriptor::descriptor();
accel_descriptor.set_instanced_acceleration_structures(&Array::from_owned_slice(
&primitive_acceleration_structures,
));
accel_descriptor.set_instance_count(scene.geometry_instances.len() as NSUInteger);
accel_descriptor.set_instance_descriptor_buffer(&instance_buffer);
let accel_descriptor: AccelerationStructureDescriptor = From::from(accel_descriptor);
let instance_acceleration_structure =
Self::new_acceleration_structure_with_descriptor(&device, &queue, &accel_descriptor);
let mut intersection_functions = BTreeMap::<String, Function>::new();
for geometry in &scene.geometries {
if let Some(name) = geometry.get_intersection_function_name() {
if !intersection_functions.contains_key(name) {
let intersection_function = Self::new_specialised_function_with_name(
&library,
resources_stride as u32,
name,
);
intersection_functions.insert(name.to_string(), intersection_function);
}
}
}
let raytracing_function = Self::new_specialised_function_with_name(
&library,
resources_stride as u32,
"raytracingKernel",
);
let intersection_function_array: Vec<&FunctionRef> = intersection_functions
.values()
.map(|f| -> &FunctionRef { f })
.collect();
let raytracing_pipeline = Self::new_compute_pipeline_state_with_function(
&device,
&raytracing_function,
&intersection_function_array,
);
let intersection_function_table_descriptor = IntersectionFunctionTableDescriptor::new();
intersection_function_table_descriptor
.set_function_count(scene.geometries.len() as NSUInteger);
let intersection_function_table = raytracing_pipeline
.new_intersection_function_table_with_descriptor(
&intersection_function_table_descriptor,
);
for geometry_index in 0..scene.geometries.len() {
let geometry = scene.geometries[geometry_index].as_ref();
if let Some(intersection_function_name) = geometry.get_intersection_function_name() {
let intersection_function = &intersection_functions[intersection_function_name];
let handle = raytracing_pipeline
.function_handle_with_function(intersection_function)
.unwrap();
intersection_function_table.set_function(handle, geometry_index as NSUInteger);
}
}
let render_descriptor = RenderPipelineDescriptor::new();
render_descriptor
.set_vertex_function(Some(&library.get_function("copyVertex", None).unwrap()));
render_descriptor
.set_fragment_function(Some(&library.get_function("copyFragment", None).unwrap()));
render_descriptor
.color_attachments()
.object_at(0)
.unwrap()
.set_pixel_format(MTLPixelFormat::RGBA16Float);
let copy_pipeline = device
.new_render_pipeline_state(&render_descriptor)
.unwrap();
let texture_descriptor = Self::create_target_descriptor(1024, 1024);
let accumulation_targets = [
device.new_texture(&texture_descriptor),
device.new_texture(&texture_descriptor),
];
let random_texture = device.new_texture(&texture_descriptor);
Self {
device,
scene,
uniform_buffer,
resource_buffer,
instance_acceleration_structure,
accumulation_targets,
random_texture,
frame_index: 0,
uniform_buffer_index: 0,
uniform_buffer_offset: 0,
size: CGSize::new(1024 as CGFloat, 1024 as CGFloat),
semaphore: Semaphore::new((MAX_FRAMES_IN_FLIGHT - 2) as usize),
instance_buffer,
queue,
intersection_function_table,
primitive_acceleration_structures,
raytracing_pipeline,
copy_pipeline,
}
}
fn create_target_descriptor(width: NSUInteger, height: NSUInteger) -> TextureDescriptor {
let texture_descriptor = TextureDescriptor::new();
texture_descriptor.set_pixel_format(MTLPixelFormat::RGBA32Float);
texture_descriptor.set_texture_type(MTLTextureType::D2);
texture_descriptor.set_width(width);
texture_descriptor.set_height(height);
texture_descriptor.set_storage_mode(MTLStorageMode::Private);
texture_descriptor.set_usage(MTLTextureUsage::ShaderRead | MTLTextureUsage::ShaderWrite);
texture_descriptor
}
pub fn window_resized(&mut self, size: CGSize) {
self.size = size;
let texture_descriptor =
Self::create_target_descriptor(size.width as NSUInteger, size.height as NSUInteger);
self.accumulation_targets[0] = self.device.new_texture(&texture_descriptor);
self.accumulation_targets[1] = self.device.new_texture(&texture_descriptor);
texture_descriptor.set_pixel_format(MTLPixelFormat::R32Uint);
texture_descriptor.set_usage(MTLTextureUsage::ShaderRead);
texture_descriptor.set_storage_mode(MTLStorageMode::Managed);
self.random_texture = self.device.new_texture(&texture_descriptor);
let mut rng = thread_rng();
let mut random_values = vec![0u32; (size.width * size.height) as usize];
for v in &mut random_values {
*v = rng.next_u32();
}
self.random_texture.replace_region(
MTLRegion::new_2d(0, 0, size.width as NSUInteger, size.height as NSUInteger),
0,
random_values.as_ptr() as *const c_void,
size_of::<u32>() as NSUInteger * size.width as NSUInteger,
);
self.frame_index = 0;
}
fn update_uniforms(&mut self) {
self.uniform_buffer_offset = ALIGNED_UNIFORMS_SIZE * self.uniform_buffer_index;
let uniforms = unsafe {
&mut *((self.uniform_buffer.contents() as *mut u8)
.add(self.uniform_buffer_offset as usize) as *mut Uniforms)
};
let position = self.scene.camera.position;
let target = self.scene.camera.forward;
let up = self.scene.camera.up;
let forward = Vec3::normalize(target.xyz() - position.xyz());
let right = Vec3::normalize(Vec3::cross(forward, up.xyz()));
let up = Vec3::normalize(Vec3::cross(right, forward));
uniforms.camera.position = position;
uniforms.camera.forward = Vec4::from((forward, 0.0));
uniforms.camera.right = Vec4::from((right, 0.0));
uniforms.camera.up = Vec4::from((up, 0.0));
let field_of_view = 45.0 * (std::f32::consts::PI / 180.0);
let aspect_ratio = self.size.width as f32 / self.size.height as f32;
let image_plane_height = f32::tan(field_of_view / 2.0);
let image_plane_width = aspect_ratio * image_plane_height;
uniforms.camera.right *= image_plane_width;
uniforms.camera.up *= image_plane_height;
uniforms.width = self.size.width as u32;
uniforms.height = self.size.height as u32;
uniforms.frame_index = self.frame_index as u32;
self.frame_index += 1;
uniforms.light_count = self.scene.lights.len() as u32;
self.uniform_buffer.did_modify_range(NSRange {
location: self.uniform_buffer_offset,
length: ALIGNED_UNIFORMS_SIZE,
});
self.uniform_buffer_index = (self.uniform_buffer_index + 1) % MAX_FRAMES_IN_FLIGHT;
}
pub fn draw(&mut self, layer: &MetalLayer) {
self.semaphore.acquire();
self.update_uniforms();
let command_buffer = self.queue.new_command_buffer();
let sem = self.semaphore.clone();
let block = block::ConcreteBlock::new(move |_| {
sem.release();
})
.copy();
command_buffer.add_completed_handler(&block);
let width = self.size.width as NSUInteger;
let height = self.size.height as NSUInteger;
let threads_per_thread_group = MTLSize::new(8, 8, 1);
let thread_groups = MTLSize::new(
(width + threads_per_thread_group.width - 1) / threads_per_thread_group.width,
(height + threads_per_thread_group.height - 1) / threads_per_thread_group.height,
1,
);
let compute_encoder = command_buffer.new_compute_command_encoder();
compute_encoder.set_buffer(0, Some(&self.uniform_buffer), self.uniform_buffer_offset);
compute_encoder.set_buffer(2, Some(&self.instance_buffer), 0);
compute_encoder.set_buffer(3, Some(&self.scene.lights_buffer), 0);
compute_encoder.set_acceleration_structure(4, Some(&self.instance_acceleration_structure));
compute_encoder.set_intersection_function_table(5, Some(&self.intersection_function_table));
compute_encoder.set_texture(0, Some(&self.random_texture));
compute_encoder.set_texture(1, Some(&self.accumulation_targets[0]));
compute_encoder.set_texture(2, Some(&self.accumulation_targets[1]));
for geometry in &self.scene.geometries {
for resource in geometry.get_resources() {
compute_encoder.use_resource(&resource, MTLResourceUsage::Read);
}
}
for primitive_acceleration_structure in &self.primitive_acceleration_structures {
let resource: Resource = From::from(primitive_acceleration_structure.clone());
compute_encoder.use_resource(&resource, MTLResourceUsage::Read);
}
compute_encoder.set_compute_pipeline_state(&self.raytracing_pipeline);
compute_encoder.dispatch_thread_groups(thread_groups, threads_per_thread_group);
compute_encoder.end_encoding();
(self.accumulation_targets[0], self.accumulation_targets[1]) = (
self.accumulation_targets[1].clone(),
self.accumulation_targets[0].clone(),
);
if let Some(drawable) = layer.next_drawable() {
let render_pass_descriptor = RenderPassDescriptor::new();
let colour_attachment = render_pass_descriptor
.color_attachments()
.object_at(0)
.unwrap();
colour_attachment.set_texture(Some(drawable.texture()));
colour_attachment.set_load_action(MTLLoadAction::Clear);
colour_attachment.set_clear_color(MTLClearColor::new(0.0, 0.0, 0.0, 1.0));
let render_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
render_encoder.set_render_pipeline_state(&self.copy_pipeline);
render_encoder.set_fragment_texture(0, Some(&self.accumulation_targets[0]));
render_encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 6);
render_encoder.end_encoding();
command_buffer.present_drawable(&drawable);
}
command_buffer.commit();
}
fn new_acceleration_structure_with_descriptor(
device: &Device,
queue: &CommandQueue,
descriptor: &AccelerationStructureDescriptorRef,
) -> AccelerationStructure {
let accel_sizes = device.acceleration_structure_sizes_with_descriptor(descriptor);
let acceleration_structure =
device.new_acceleration_structure_with_size(accel_sizes.acceleration_structure_size);
let scratch_buffer = device.new_buffer(
accel_sizes.build_scratch_buffer_size,
MTLResourceOptions::StorageModePrivate,
);
let command_buffer = queue.new_command_buffer();
let command_encoder = command_buffer.new_acceleration_structure_command_encoder();
let compacted_size_buffer = device.new_buffer(
size_of::<u32>() as NSUInteger,
MTLResourceOptions::StorageModeShared,
);
command_encoder.build_acceleration_structure(
&acceleration_structure,
&descriptor,
&scratch_buffer,
0,
);
command_encoder.write_compacted_acceleration_structure_size(
&acceleration_structure,
&compacted_size_buffer,
0,
);
command_encoder.end_encoding();
command_buffer.commit();
command_buffer.wait_until_completed();
let compacted_size: *const u32 = unsafe { transmute(compacted_size_buffer.contents()) };
let compacted_size = unsafe { *compacted_size } as NSUInteger;
let compacted_acceleration_structure =
device.new_acceleration_structure_with_size(compacted_size);
let command_buffer = queue.new_command_buffer();
let command_encoder = command_buffer.new_acceleration_structure_command_encoder();
command_encoder.copy_and_compact_acceleration_structure(
&acceleration_structure,
&compacted_acceleration_structure,
);
command_encoder.end_encoding();
command_buffer.commit();
compacted_acceleration_structure
}
fn new_specialised_function_with_name(
library: &Library,
resources_stride: u32,
name: &str,
) -> Function {
let constants = FunctionConstantValues::new();
let resources_stride = resources_stride * size_of::<u64>() as u32;
constants.set_constant_value_at_index(
&resources_stride as *const u32 as *const c_void,
MTLDataType::UInt,
0,
);
let v = true;
constants.set_constant_value_at_index(
&v as *const bool as *const c_void,
MTLDataType::Bool,
1,
);
constants.set_constant_value_at_index(
&v as *const bool as *const c_void,
MTLDataType::Bool,
2,
);
library.get_function(name, Some(constants)).unwrap()
}
fn new_compute_pipeline_state_with_function(
device: &Device,
function: &Function,
linked_functions: &[&FunctionRef],
) -> ComputePipelineState {
let linked_functions = {
let lf = LinkedFunctions::new();
lf.set_functions(linked_functions);
lf
};
let descriptor = ComputePipelineDescriptor::new();
descriptor.set_compute_function(Some(function));
descriptor.set_linked_functions(linked_functions.as_ref());
descriptor.set_thread_group_size_is_multiple_of_thread_execution_width(true);
device.new_compute_pipeline_state(&descriptor).unwrap()
}
}

View File

@@ -0,0 +1,135 @@
use std::{ffi::c_void, mem::size_of, sync::Arc};
use glam::{Mat4, Vec3, Vec4};
use rand::{thread_rng, Rng};
use metal::{Buffer, Device, NSRange, NSUInteger};
use super::{camera::Camera, geometry::*};
pub struct Scene {
pub device: Device,
pub camera: Camera,
pub geometries: Vec<Arc<dyn Geometry>>,
pub geometry_instances: Vec<Arc<GeometryInstance>>,
pub lights: Vec<AreaLight>,
pub lights_buffer: Buffer,
}
impl Scene {
pub fn new(device: Device) -> Self {
let mut geometries = Vec::<Arc<dyn Geometry>>::new();
let mut light_mesh = TriangleGeometry::new(device.clone(), "light".to_string());
let transform = Mat4::from_translation(Vec3::new(0.0, 1.0, 0.0))
* Mat4::from_scale(Vec3::new(0.5, 1.98, 0.5));
light_mesh.add_cube_with_faces(
FACE_MASK_POSITIVE_Y,
Vec3::new(1.0, 1.0, 1.0),
transform,
true,
);
light_mesh.upload_to_buffers();
let light_mesh = Arc::new(light_mesh);
geometries.push(light_mesh.clone());
let mut geometry_mesh = TriangleGeometry::new(device.clone(), "geometry".to_string());
let transform = Mat4::from_translation(Vec3::new(0.0, 1.0, 0.0))
* Mat4::from_scale(Vec3::new(2.0, 2.0, 2.0));
geometry_mesh.add_cube_with_faces(
FACE_MASK_NEGATIVE_Y | FACE_MASK_POSITIVE_Y | FACE_MASK_NEGATIVE_Z,
Vec3::new(0.725, 0.71, 0.68),
transform,
true,
);
geometry_mesh.add_cube_with_faces(
FACE_MASK_NEGATIVE_X,
Vec3::new(0.63, 0.065, 0.05),
transform,
true,
);
geometry_mesh.add_cube_with_faces(
FACE_MASK_POSITIVE_X,
Vec3::new(0.14, 0.45, 0.091),
transform,
true,
);
let transform = Mat4::from_translation(Vec3::new(-0.335, 0.6, -0.29))
* Mat4::from_rotation_y(0.3)
* Mat4::from_scale(Vec3::new(0.6, 1.2, 0.6));
geometry_mesh.add_cube_with_faces(
FACE_MASK_ALL,
Vec3::new(0.725, 0.71, 0.68),
transform,
false,
);
geometry_mesh.upload_to_buffers();
let geometry_mesh = Arc::new(geometry_mesh);
geometries.push(geometry_mesh.clone());
let mut sphere_geometry = SphereGeometry::new(device.clone());
sphere_geometry.add_sphere_with_origin(
Vec3::new(0.3275, 0.3, 0.3725),
0.3,
Vec3::new(0.725, 0.71, 0.68),
);
sphere_geometry.upload_to_buffers();
let sphere_geometry = Arc::new(sphere_geometry);
geometries.push(sphere_geometry.clone());
let mut rng = thread_rng();
let mut geometry_instances = Vec::new();
let mut lights = Vec::new();
for y in -1..2 {
for x in -1..2 {
let transform =
Mat4::from_translation(Vec3::new(x as f32 * 2.5, y as f32 * 2.5, 0.0));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: light_mesh.clone(),
transform,
mask: GEOMETRY_MASK_LIGHT,
index_in_scene: 0,
}));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: geometry_mesh.clone(),
transform,
mask: GEOMETRY_MASK_TRIANGLE,
index_in_scene: 1,
}));
geometry_instances.push(Arc::new(GeometryInstance {
geometry: sphere_geometry.clone(),
transform,
mask: GEOMETRY_MASK_SPHERE,
index_in_scene: 2,
}));
lights.push(AreaLight {
position: Vec4::new(x as f32 * 2.5, y as f32 * 2.5 + 1.98, 0.0, 0.0),
forward: Vec4::new(0.0, -1.0, 0.0, 0.0),
right: Vec4::new(0.25, 0.0, 0.0, 0.0),
up: Vec4::new(0.0, 0.0, 0.25, 0.0),
colour: Vec4::new(
rng.gen_range(0f32..=1.0),
rng.gen_range(0f32..=1.0),
rng.gen_range(0f32..=1.0),
0.0,
),
});
}
}
let lights_buffer = device.new_buffer_with_data(
lights.as_ptr() as *const c_void,
(lights.len() * size_of::<AreaLight>()) as NSUInteger,
get_managed_buffer_storage_mode(),
);
lights_buffer.did_modify_range(NSRange::new(0, lights_buffer.length()));
lights_buffer.set_label("lights buffer");
Self {
device,
camera: Camera::new(),
geometries,
geometry_instances,
lights,
lights_buffer,
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -0,0 +1,598 @@
/*
See LICENSE folder for this samples licensing information.
Abstract:
The Metal shaders used for this sample.
*/
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
using namespace raytracing;
#define GEOMETRY_MASK_TRIANGLE 1
#define GEOMETRY_MASK_SPHERE 2
#define GEOMETRY_MASK_LIGHT 4
#define GEOMETRY_MASK_GEOMETRY (GEOMETRY_MASK_TRIANGLE | GEOMETRY_MASK_SPHERE)
#define RAY_MASK_PRIMARY (GEOMETRY_MASK_GEOMETRY | GEOMETRY_MASK_LIGHT)
#define RAY_MASK_SHADOW GEOMETRY_MASK_GEOMETRY
#define RAY_MASK_SECONDARY GEOMETRY_MASK_GEOMETRY
struct Camera {
vector_float3 position;
vector_float3 right;
vector_float3 up;
vector_float3 forward;
};
struct AreaLight {
vector_float3 position;
vector_float3 forward;
vector_float3 right;
vector_float3 up;
vector_float3 color;
};
struct Uniforms {
unsigned int width;
unsigned int height;
unsigned int frameIndex;
unsigned int lightCount;
Camera camera;
};
struct Sphere {
packed_float3 origin;
float radiusSquared;
packed_float3 color;
float radius;
};
struct Triangle {
vector_float3 normals[3];
vector_float3 colors[3];
};
constant unsigned int resourcesStride [[function_constant(0)]];
constant bool useIntersectionFunctions [[function_constant(1)]];
constant bool usePerPrimitiveData [[function_constant(2)]];
constant bool useResourcesBuffer = !usePerPrimitiveData;
constant unsigned int primes[] = {
2, 3, 5, 7,
11, 13, 17, 19,
23, 29, 31, 37,
41, 43, 47, 53,
59, 61, 67, 71,
73, 79, 83, 89
};
// Returns the i'th element of the Halton sequence using the d'th prime number as a
// base. The Halton sequence is a low discrepency sequence: the values appear
// random, but are more evenly distributed than a purely random sequence. Each random
// value used to render the image uses a different independent dimension, `d`,
// and each sample (frame) uses a different index `i`. To decorrelate each pixel,
// you can apply a random offset to `i`.
float halton(unsigned int i, unsigned int d) {
unsigned int b = primes[d];
float f = 1.0f;
float invB = 1.0f / b;
float r = 0;
while (i > 0) {
f = f * invB;
r = r + f * (i % b);
i = i / b;
}
return r;
}
// Interpolates the vertex attribute of an arbitrary type across the surface of a triangle
// given the barycentric coordinates and triangle index in an intersection structure.
template<typename T, typename IndexType>
inline T interpolateVertexAttribute(device T *attributes,
IndexType i0,
IndexType i1,
IndexType i2,
float2 uv) {
// Look up value for each vertex.
const T T0 = attributes[i0];
const T T1 = attributes[i1];
const T T2 = attributes[i2];
// Compute the sum of the vertex attributes weighted by the barycentric coordinates.
// The barycentric coordinates sum to one.
return (1.0f - uv.x - uv.y) * T0 + uv.x * T1 + uv.y * T2;
}
template<typename T>
inline T interpolateVertexAttribute(thread T *attributes, float2 uv) {
// Look up the value for each vertex.
const T T0 = attributes[0];
const T T1 = attributes[1];
const T T2 = attributes[2];
// Compute the sum of the vertex attributes weighted by the barycentric coordinates.
// The barycentric coordinates sum to one.
return (1.0f - uv.x - uv.y) * T0 + uv.x * T1 + uv.y * T2;
}
// Uses the inversion method to map two uniformly random numbers to a 3D
// unit hemisphere, where the probability of a given sample is proportional to the cosine
// of the angle between the sample direction and the "up" direction (0, 1, 0).
inline float3 sampleCosineWeightedHemisphere(float2 u) {
float phi = 2.0f * M_PI_F * u.x;
float cos_phi;
float sin_phi = sincos(phi, cos_phi);
float cos_theta = sqrt(u.y);
float sin_theta = sqrt(1.0f - cos_theta * cos_theta);
return float3(sin_theta * cos_phi, cos_theta, sin_theta * sin_phi);
}
// Maps two uniformly random numbers to the surface of a 2D area light
// source and returns the direction to this point, the amount of light that travels
// between the intersection point and the sample point on the light source, as well
// as the distance between these two points.
inline void sampleAreaLight(constant AreaLight & light,
float2 u,
float3 position,
thread float3 & lightDirection,
thread float3 & lightColor,
thread float & lightDistance)
{
// Map to -1..1
u = u * 2.0f - 1.0f;
// Transform into the light's coordinate system.
float3 samplePosition = light.position +
light.right * u.x +
light.up * u.y;
// Compute the vector from sample point on the light source to intersection point.
lightDirection = samplePosition - position;
lightDistance = length(lightDirection);
float inverseLightDistance = 1.0f / max(lightDistance, 1e-3f);
// Normalize the light direction.
lightDirection *= inverseLightDistance;
// Start with the light's color.
lightColor = light.color;
// Light falls off with the inverse square of the distance to the intersection point.
lightColor *= (inverseLightDistance * inverseLightDistance);
// Light also falls off with the cosine of the angle between the intersection point
// and the light source.
lightColor *= saturate(dot(-lightDirection, light.forward));
}
// Aligns a direction on the unit hemisphere such that the hemisphere's "up" direction
// (0, 1, 0) maps to the given surface normal direction.
inline float3 alignHemisphereWithNormal(float3 sample, float3 normal) {
// Set the "up" vector to the normal
float3 up = normal;
// Find an arbitrary direction perpendicular to the normal, which becomes the
// "right" vector.
float3 right = normalize(cross(normal, float3(0.0072f, 1.0f, 0.0034f)));
// Find a third vector perpendicular to the previous two, which becomes the
// "forward" vector.
float3 forward = cross(right, up);
// Map the direction on the unit hemisphere to the coordinate system aligned
// with the normal.
return sample.x * right + sample.y * up + sample.z * forward;
}
// Return the type for a bounding box intersection function.
struct BoundingBoxIntersection {
bool accept [[accept_intersection]]; // Whether to accept or reject the intersection.
float distance [[distance]]; // Distance from the ray origin to the intersection point.
};
// Resources for a piece of triangle geometry.
struct TriangleResources {
device uint16_t *indices;
device float3 *vertexNormals;
device float3 *vertexColors;
};
// Resources for a piece of sphere geometry.
struct SphereResources {
device Sphere *spheres;
};
/*
Custom sphere intersection function. The [[intersection]] keyword marks this as an intersection
function. The [[bounding_box]] keyword means that this intersection function handles intersecting rays
with bounding box primitives. To create sphere primitives, the sample creates bounding boxes that
enclose the sphere primitives.
The [[triangle_data]] and [[instancing]] keywords indicate that the intersector that calls this
intersection function returns barycentric coordinates for triangle intersections and traverses
an instance acceleration structure. These keywords must match between the intersection functions,
intersection function table, intersector, and intersection result to ensure that Metal propagates
data correctly between stages. Using fewer tags when possible may result in better performance,
as Metal may need to store less data and pass less data between stages. For example, if you do not
need barycentric coordinates, omitting [[triangle_data]] means Metal can avoid computing and storing
them.
The arguments to the intersection function contain information about the ray, primitive to be
tested, and so on. The ray intersector provides this datas when it calls the intersection function.
Metal provides other built-in arguments, but this sample doesn't use them.
*/
[[intersection(bounding_box, triangle_data, instancing)]]
BoundingBoxIntersection sphereIntersectionFunction(// Ray parameters passed to the ray intersector below
float3 origin [[origin]],
float3 direction [[direction]],
float minDistance [[min_distance]],
float maxDistance [[max_distance]],
// Information about the primitive.
unsigned int primitiveIndex [[primitive_id]],
unsigned int geometryIndex [[geometry_intersection_function_table_offset]],
// Custom resources bound to the intersection function table.
device void *resources [[buffer(0), function_constant(useResourcesBuffer)]]
,const device void* perPrimitiveData [[primitive_data]])
{
Sphere sphere;
// Look up the resources for this piece of sphere geometry.
if (usePerPrimitiveData) {
// Per-primitive data points to data from the specified buffer as was configured in the MTLAccelerationStructureBoundingBoxGeometryDescriptor.
sphere = *(const device Sphere*)perPrimitiveData;
} else
{
device SphereResources& sphereResources = *(device SphereResources *)((device char *)resources + resourcesStride * geometryIndex);
// Get the actual sphere enclosed in this bounding box.
sphere = sphereResources.spheres[primitiveIndex];
}
// Check for intersection between the ray and sphere mathematically.
float3 oc = origin - sphere.origin;
float a = dot(direction, direction);
float b = 2 * dot(oc, direction);
float c = dot(oc, oc) - sphere.radiusSquared;
float disc = b * b - 4 * a * c;
BoundingBoxIntersection ret;
if (disc <= 0.0f) {
// If the ray missed the sphere, return false.
ret.accept = false;
}
else {
// Otherwise, compute the intersection distance.
ret.distance = (-b - sqrt(disc)) / (2 * a);
// The intersection function must also check whether the intersection distance is
// within the acceptable range. Intersection functions do not run in any particular order,
// so the maximum distance may be different from the one passed into the ray intersector.
ret.accept = ret.distance >= minDistance && ret.distance <= maxDistance;
}
return ret;
}
__attribute__((always_inline))
float3 transformPoint(float3 p, float4x4 transform) {
return (transform * float4(p.x, p.y, p.z, 1.0f)).xyz;
}
__attribute__((always_inline))
float3 transformDirection(float3 p, float4x4 transform) {
return (transform * float4(p.x, p.y, p.z, 0.0f)).xyz;
}
// Main ray tracing kernel.
kernel void raytracingKernel(
uint2 tid [[thread_position_in_grid]],
constant Uniforms & uniforms [[buffer(0)]],
texture2d<unsigned int> randomTex [[texture(0)]],
texture2d<float> prevTex [[texture(1)]],
texture2d<float, access::write> dstTex [[texture(2)]],
device void *resources [[buffer(1), function_constant(useResourcesBuffer)]],
constant MTLAccelerationStructureInstanceDescriptor *instances [[buffer(2)]],
constant AreaLight *areaLights [[buffer(3)]],
instance_acceleration_structure accelerationStructure [[buffer(4)]],
intersection_function_table<triangle_data, instancing> intersectionFunctionTable [[buffer(5)]]
)
{
// The sample aligns the thread count to the threadgroup size, which means the thread count
// may be different than the bounds of the texture. Test to make sure this thread
// is referencing a pixel within the bounds of the texture.
if (tid.x >= uniforms.width || tid.y >= uniforms.height) return;
// The ray to cast.
ray ray;
// Pixel coordinates for this thread.
float2 pixel = (float2)tid;
// Apply a random offset to the random number index to decorrelate pixels.
unsigned int offset = randomTex.read(tid).x;
// Add a random offset to the pixel coordinates for antialiasing.
float2 r = float2(halton(offset + uniforms.frameIndex, 0),
halton(offset + uniforms.frameIndex, 1));
pixel += r;
// Map pixel coordinates to -1..1.
float2 uv = (float2)pixel / float2(uniforms.width, uniforms.height);
uv = uv * 2.0f - 1.0f;
constant Camera & camera = uniforms.camera;
// Rays start at the camera position.
ray.origin = camera.position;
// Map normalized pixel coordinates into camera's coordinate system.
ray.direction = normalize(uv.x * camera.right +
uv.y * camera.up +
camera.forward);
// Don't limit intersection distance.
ray.max_distance = INFINITY;
// Start with a fully white color. The kernel scales the light each time the
// ray bounces off of a surface, based on how much of each light component
// the surface absorbs.
float3 color = float3(1.0f, 1.0f, 1.0f);
float3 accumulatedColor = float3(0.0f, 0.0f, 0.0f);
// Create an intersector to test for intersection between the ray and the geometry in the scene.
intersector<triangle_data, instancing> i;
// If the sample isn't using intersection functions, provide some hints to Metal for
// better performance.
if (!useIntersectionFunctions) {
i.assume_geometry_type(geometry_type::triangle);
i.force_opacity(forced_opacity::opaque);
}
typename intersector<triangle_data, instancing>::result_type intersection;
// Simulate up to three ray bounces. Each bounce propagates light backward along the
// ray's path toward the camera.
for (int bounce = 0; bounce < 3; bounce++) {
// Get the closest intersection, not the first intersection. This is the default, but
// the sample adjusts this property below when it casts shadow rays.
i.accept_any_intersection(false);
// Check for intersection between the ray and the acceleration structure. If the sample
// isn't using intersection functions, it doesn't need to include one.
if (useIntersectionFunctions)
intersection = i.intersect(ray, accelerationStructure, bounce == 0 ? RAY_MASK_PRIMARY : RAY_MASK_SECONDARY, intersectionFunctionTable);
else
intersection = i.intersect(ray, accelerationStructure, bounce == 0 ? RAY_MASK_PRIMARY : RAY_MASK_SECONDARY);
// Stop if the ray didn't hit anything and has bounced out of the scene.
if (intersection.type == intersection_type::none)
break;
unsigned int instanceIndex = intersection.instance_id;
// Look up the mask for this instance, which indicates what type of geometry the ray hit.
unsigned int mask = instances[instanceIndex].mask;
// If the ray hit a light source, set the color to white, and stop immediately.
if (mask == GEOMETRY_MASK_LIGHT) {
accumulatedColor = float3(1.0f, 1.0f, 1.0f);
break;
}
// The ray hit something. Look up the transformation matrix for this instance.
float4x4 objectToWorldSpaceTransform(1.0f);
for (int column = 0; column < 4; column++)
for (int row = 0; row < 3; row++)
objectToWorldSpaceTransform[column][row] = instances[instanceIndex].transformationMatrix[column][row];
// Compute the intersection point in world space.
float3 worldSpaceIntersectionPoint = ray.origin + ray.direction * intersection.distance;
unsigned primitiveIndex = intersection.primitive_id;
unsigned int geometryIndex = instances[instanceIndex].accelerationStructureIndex;
float2 barycentric_coords = intersection.triangle_barycentric_coord;
float3 worldSpaceSurfaceNormal = 0.0f;
float3 surfaceColor = 0.0f;
if (mask & GEOMETRY_MASK_TRIANGLE) {
Triangle triangle;
float3 objectSpaceSurfaceNormal;
if (usePerPrimitiveData) {
// Per-primitive data points to data from the specified buffer as was configured in the MTLAccelerationStructureTriangleGeometryDescriptor.
triangle = *(const device Triangle*)intersection.primitive_data;
} else
{
// The ray hit a triangle. Look up the corresponding geometry's normal and UV buffers.
device TriangleResources & triangleResources = *(device TriangleResources *)((device char *)resources + resourcesStride * geometryIndex);
triangle.normals[0] = triangleResources.vertexNormals[triangleResources.indices[primitiveIndex * 3 + 0]];
triangle.normals[1] = triangleResources.vertexNormals[triangleResources.indices[primitiveIndex * 3 + 1]];
triangle.normals[2] = triangleResources.vertexNormals[triangleResources.indices[primitiveIndex * 3 + 2]];
triangle.colors[0] = triangleResources.vertexColors[triangleResources.indices[primitiveIndex * 3 + 0]];
triangle.colors[1] = triangleResources.vertexColors[triangleResources.indices[primitiveIndex * 3 + 1]];
triangle.colors[2] = triangleResources.vertexColors[triangleResources.indices[primitiveIndex * 3 + 2]];
}
// Interpolate the vertex normal at the intersection point.
objectSpaceSurfaceNormal = interpolateVertexAttribute(triangle.normals, barycentric_coords);
// Interpolate the vertex color at the intersection point.
surfaceColor = interpolateVertexAttribute(triangle.colors, barycentric_coords);
// Transform the normal from object to world space.
worldSpaceSurfaceNormal = normalize(transformDirection(objectSpaceSurfaceNormal, objectToWorldSpaceTransform));
}
else if (mask & GEOMETRY_MASK_SPHERE) {
Sphere sphere;
if (usePerPrimitiveData) {
// Per-primitive data points to data from the specified buffer as was configured in the MTLAccelerationStructureBoundingBoxGeometryDescriptor.
sphere = *(const device Sphere*)intersection.primitive_data;
} else
{
// The ray hit a sphere. Look up the corresponding sphere buffer.
device SphereResources & sphereResources = *(device SphereResources *)((device char *)resources + resourcesStride * geometryIndex);
sphere = sphereResources.spheres[primitiveIndex];
}
// Transform the sphere's origin from object space to world space.
float3 worldSpaceOrigin = transformPoint(sphere.origin, objectToWorldSpaceTransform);
// Compute the surface normal directly in world space.
worldSpaceSurfaceNormal = normalize(worldSpaceIntersectionPoint - worldSpaceOrigin);
// The sphere is a uniform color, so you don't need to interpolate the color across the surface.
surfaceColor = sphere.color;
}
dstTex.write(float4(accumulatedColor, 1.0f), tid);
// Choose a random light source to sample.
float lightSample = halton(offset + uniforms.frameIndex, 2 + bounce * 5 + 0);
unsigned int lightIndex = min((unsigned int)(lightSample * uniforms.lightCount), uniforms.lightCount - 1);
// Choose a random point to sample on the light source.
float2 r = float2(halton(offset + uniforms.frameIndex, 2 + bounce * 5 + 1),
halton(offset + uniforms.frameIndex, 2 + bounce * 5 + 2));
float3 worldSpaceLightDirection;
float3 lightColor;
float lightDistance;
// Sample the lighting between the intersection point and the point on the area light.
sampleAreaLight(areaLights[lightIndex], r, worldSpaceIntersectionPoint, worldSpaceLightDirection,
lightColor, lightDistance);
// Scale the light color by the cosine of the angle between the light direction and
// surface normal.
lightColor *= saturate(dot(worldSpaceSurfaceNormal, worldSpaceLightDirection));
// Scale the light color by the number of lights to compensate for the fact that
// the sample samples only one light source at random.
lightColor *= uniforms.lightCount;
// Scale the ray color by the color of the surface to simulate the surface absorbing light.
color *= surfaceColor;
// Compute the shadow ray. The shadow ray checks whether the sample position on the
// light source is visible from the current intersection point.
// If it is, the kernel adds lighting to the output image.
struct ray shadowRay;
// Add a small offset to the intersection point to avoid intersecting the same
// triangle again.
shadowRay.origin = worldSpaceIntersectionPoint + worldSpaceSurfaceNormal * 1e-3f;
// Travel toward the light source.
shadowRay.direction = worldSpaceLightDirection;
// Don't overshoot the light source.
shadowRay.max_distance = lightDistance - 1e-3f;
// Shadow rays check only whether there is an object between the intersection point
// and the light source. Tell Metal to return after finding any intersection.
i.accept_any_intersection(true);
if (useIntersectionFunctions)
intersection = i.intersect(shadowRay, accelerationStructure, RAY_MASK_SHADOW, intersectionFunctionTable);
else
intersection = i.intersect(shadowRay, accelerationStructure, RAY_MASK_SHADOW);
// If there was no intersection, then the light source is visible from the original
// intersection point. Add the light's contribution to the image.
if (intersection.type == intersection_type::none)
accumulatedColor += lightColor * color;
// Choose a random direction to continue the path of the ray. This causes light to
// bounce between surfaces. An app might evaluate a more complicated equation to
// calculate the amount of light that reflects between intersection points. However,
// all the math in this kernel cancels out because this app assumes a simple diffuse
// BRDF and samples the rays with a cosine distribution over the hemisphere (importance
// sampling). This requires that the kernel only multiply the colors together. This
// sampling strategy also reduces the amount of noise in the output image.
r = float2(halton(offset + uniforms.frameIndex, 2 + bounce * 5 + 3),
halton(offset + uniforms.frameIndex, 2 + bounce * 5 + 4));
float3 worldSpaceSampleDirection = sampleCosineWeightedHemisphere(r);
worldSpaceSampleDirection = alignHemisphereWithNormal(worldSpaceSampleDirection, worldSpaceSurfaceNormal);
ray.origin = worldSpaceIntersectionPoint + worldSpaceSurfaceNormal * 1e-3f;
ray.direction = worldSpaceSampleDirection;
}
// Average this frame's sample with all of the previous frames.
if (uniforms.frameIndex > 0) {
float3 prevColor = prevTex.read(tid).xyz;
prevColor *= uniforms.frameIndex;
accumulatedColor += prevColor;
accumulatedColor /= (uniforms.frameIndex + 1);
}
dstTex.write(float4(accumulatedColor, 1.0f), tid);
}
// Screen filling quad in normalized device coordinates.
constant float2 quadVertices[] = {
float2(-1, -1),
float2(-1, 1),
float2( 1, 1),
float2(-1, -1),
float2( 1, 1),
float2( 1, -1)
};
struct CopyVertexOut {
float4 position [[position]];
float2 uv;
};
// Simple vertex shader that passes through NDC quad positions.
vertex CopyVertexOut copyVertex(unsigned short vid [[vertex_id]]) {
float2 position = quadVertices[vid];
CopyVertexOut out;
out.position = float4(position, 0, 1);
out.uv = position * 0.5f + 0.5f;
return out;
}
// Simple fragment shader that copies a texture and applies a simple tonemapping function.
fragment float4 copyFragment(CopyVertexOut in [[stage_in]],
texture2d<float> tex)
{
constexpr sampler sam(min_filter::nearest, mag_filter::nearest, mip_filter::none);
float3 color = tex.sample(sam, in.uv).xyz;
// Apply a simple tonemapping function to reduce the dynamic range of the
// input image into a range which the screen can display.
color = color / (1.0f + color);
return float4(color, 1.0f);
}

Binary file not shown.

View File

@@ -0,0 +1,75 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use metal::*;
use objc::rc::autoreleasepool;
const PROGRAM: &'static str = r"
#include <metal_stdlib>
using namespace metal;
typedef struct {
float2 position;
float3 color;
} vertex_t;
struct ColorInOut {
float4 position [[position]];
float4 color;
};
vertex ColorInOut vs(device vertex_t* vertex_array [[ buffer(0) ]],
unsigned int vid [[ vertex_id ]])
{
ColorInOut out;
out.position = float4(float2(vertex_array[vid].position), 0.0, 1.0);
out.color = float4(float3(vertex_array[vid].color), 1.0);
return out;
}
fragment float4 ps(ColorInOut in [[stage_in]])
{
return in.color;
};
";
fn main() {
autoreleasepool(|| {
let device = Device::system_default().expect("no device found");
let options = CompileOptions::new();
let library = device.new_library_with_source(PROGRAM, &options).unwrap();
let (vs, ps) = (
library.get_function("vs", None).unwrap(),
library.get_function("ps", None).unwrap(),
);
let vertex_desc = VertexDescriptor::new();
let desc = RenderPipelineDescriptor::new();
desc.set_vertex_function(Some(&vs));
desc.set_fragment_function(Some(&ps));
desc.set_vertex_descriptor(Some(vertex_desc));
println!("{:?}", desc);
let reflect_options = MTLPipelineOption::ArgumentInfo | MTLPipelineOption::BufferTypeInfo;
let (_, reflection) = device
.new_render_pipeline_state_with_reflection(&desc, reflect_options)
.unwrap();
println!("Vertex arguments: ");
let vertex_arguments = reflection.vertex_arguments();
for index in 0..vertex_arguments.count() {
let argument = vertex_arguments.object_at(index).unwrap();
println!("{:?}", argument);
}
});
}

View File

@@ -0,0 +1,179 @@
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use metal::*;
use objc::{rc::autoreleasepool, runtime::YES};
use winit::{
event::{Event, WindowEvent},
event_loop::ControlFlow,
raw_window_handle::{HasWindowHandle, RawWindowHandle},
};
use std::mem;
struct App {
pub _device: Device,
pub command_queue: CommandQueue,
pub layer: MetalLayer,
pub image_fill_cps: ComputePipelineState,
pub width: u32,
pub height: u32,
}
fn select_device() -> Option<Device> {
let devices = Device::all();
for device in devices {
if device.supports_dynamic_libraries() {
return Some(device);
}
}
None
}
impl App {
fn new(window: &winit::window::Window) -> Self {
let device = select_device().expect("no device found that supports dynamic libraries");
let command_queue = device.new_command_queue();
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_presents_with_transaction(false);
layer.set_framebuffer_only(false);
unsafe {
if let Ok(RawWindowHandle::AppKit(rw)) = window.window_handle().map(|wh| wh.as_raw()) {
let view = rw.ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(mem::transmute(layer.as_ref()));
}
}
let draw_size = window.inner_size();
layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64));
// compile dynamic lib shader
let dylib_src_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/shader-dylib/test_dylib.metal");
let install_path =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target/test_dylib.metallib");
let dylib_src = std::fs::read_to_string(dylib_src_path).expect("bad shit");
let opts = metal::CompileOptions::new();
opts.set_library_type(MTLLibraryType::Dynamic);
opts.set_install_name(install_path.to_str().unwrap());
let lib = device
.new_library_with_source(dylib_src.as_str(), &opts)
.unwrap();
// create dylib
let dylib = device.new_dynamic_library(&lib).unwrap();
dylib.set_label("test_dylib");
// optional: serialize binary blob that can be loaded later
let blob_url = String::from("file://") + install_path.to_str().unwrap();
let url = URL::new_with_string(&blob_url);
dylib.serialize_to_url(&url).unwrap();
// create shader that links with dylib
let shader_src_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/shader-dylib/test_shader.metal");
let shader_src = std::fs::read_to_string(shader_src_path).expect("bad shit");
let opts = metal::CompileOptions::new();
// add dynamic library to link with
let libraries = [dylib.as_ref()];
opts.set_libraries(&libraries);
// compile
let shader_lib = device
.new_library_with_source(shader_src.as_str(), &opts)
.unwrap();
let func = shader_lib.get_function("test_kernel", None).unwrap();
// create pipeline state
// linking occurs here
let image_fill_cps = device
.new_compute_pipeline_state_with_function(&func)
.unwrap();
Self {
_device: device,
command_queue,
layer,
image_fill_cps,
width: draw_size.width,
height: draw_size.height,
}
}
fn resize(&mut self, width: u32, height: u32) {
self.layer
.set_drawable_size(CGSize::new(width as f64, height as f64));
self.width = width;
self.height = height;
}
fn draw(&self) {
let drawable = match self.layer.next_drawable() {
Some(drawable) => drawable,
None => return,
};
let w = self.image_fill_cps.thread_execution_width();
let h = self.image_fill_cps.max_total_threads_per_threadgroup() / w;
let threads_per_threadgroup = MTLSize::new(w, h, 1);
let threads_per_grid = MTLSize::new(self.width as _, self.height as _, 1);
let command_buffer = self.command_queue.new_command_buffer();
{
let encoder = command_buffer.new_compute_command_encoder();
encoder.set_compute_pipeline_state(&self.image_fill_cps);
encoder.set_texture(0, Some(&drawable.texture()));
encoder.dispatch_threads(threads_per_grid, threads_per_threadgroup);
encoder.end_encoding();
}
command_buffer.present_drawable(&drawable);
command_buffer.commit();
}
}
fn main() {
let event_loop = winit::event_loop::EventLoop::new().unwrap();
let size = winit::dpi::LogicalSize::new(800, 600);
let window = winit::window::WindowBuilder::new()
.with_inner_size(size)
.with_title("Metal Shader Dylib Example".to_string())
.build(&event_loop)
.unwrap();
let mut app = App::new(&window);
event_loop
.run(move |event, event_loop| {
autoreleasepool(|| {
event_loop.set_control_flow(ControlFlow::Poll);
match event {
Event::AboutToWait => window.request_redraw(),
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::Resized(size) => {
app.resize(size.width, size.height);
}
WindowEvent::RedrawRequested => {
app.draw();
}
_ => (),
},
_ => {}
}
});
})
.unwrap();
}

View File

@@ -0,0 +1,8 @@
#include <metal_stdlib>
using namespace metal;
float4 get_color_test(float4 inColor)
{
return float4(inColor.r, inColor.g, inColor.b, 0);
}

View File

@@ -0,0 +1,14 @@
#include <metal_stdlib>
using namespace metal;
extern float4 get_color_test(float4 inColor);
kernel void test_kernel(
texture2d<float, access::write> image [[texture(0)]],
uint2 coordinates [[thread_position_in_grid]],
uint2 size [[threads_per_grid]])
{
float2 uv = float2(coordinates) / float2(size - 1);
image.write(get_color_test(float4(uv, 0.0, 1.0)), coordinates);
}

11
vendor/metal/examples/window/README.md vendored Normal file
View File

@@ -0,0 +1,11 @@
## window
Renders a spinning triangle to a [winit](https://github.com/rust-windowing/winit) window.
![Screenshot of the final render](./screenshot.png)
## To Run
```
cargo run --example window
```

269
vendor/metal/examples/window/main.rs vendored Normal file
View File

@@ -0,0 +1,269 @@
// Copyright 2016 metal-rs developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
extern crate objc;
use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use metal::*;
use objc::{rc::autoreleasepool, runtime::YES};
use std::mem;
use winit::{
event::{Event, WindowEvent},
event_loop::ControlFlow,
raw_window_handle::{HasWindowHandle, RawWindowHandle},
};
#[repr(C)]
struct Rect {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
}
#[repr(C)]
struct Color {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
#[repr(C)]
struct ClearRect {
pub rect: Rect,
pub color: Color,
}
fn prepare_pipeline_state<'a>(
device: &DeviceRef,
library: &LibraryRef,
vertex_shader: &str,
fragment_shader: &str,
) -> RenderPipelineState {
let vert = library.get_function(vertex_shader, None).unwrap();
let frag = library.get_function(fragment_shader, None).unwrap();
let pipeline_state_descriptor = RenderPipelineDescriptor::new();
pipeline_state_descriptor.set_vertex_function(Some(&vert));
pipeline_state_descriptor.set_fragment_function(Some(&frag));
let attachment = pipeline_state_descriptor
.color_attachments()
.object_at(0)
.unwrap();
attachment.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
attachment.set_blending_enabled(true);
attachment.set_rgb_blend_operation(metal::MTLBlendOperation::Add);
attachment.set_alpha_blend_operation(metal::MTLBlendOperation::Add);
attachment.set_source_rgb_blend_factor(metal::MTLBlendFactor::SourceAlpha);
attachment.set_source_alpha_blend_factor(metal::MTLBlendFactor::SourceAlpha);
attachment.set_destination_rgb_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
attachment.set_destination_alpha_blend_factor(metal::MTLBlendFactor::OneMinusSourceAlpha);
device
.new_render_pipeline_state(&pipeline_state_descriptor)
.unwrap()
}
fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: &TextureRef) {
//descriptor.color_attachments().set_object_at(0, MTLRenderPassColorAttachmentDescriptor::alloc());
//let color_attachment: MTLRenderPassColorAttachmentDescriptor = unsafe { msg_send![descriptor.color_attachments().0, _descriptorAtIndex:0] };//descriptor.color_attachments().object_at(0);
let color_attachment = descriptor.color_attachments().object_at(0).unwrap();
color_attachment.set_texture(Some(texture));
color_attachment.set_load_action(MTLLoadAction::Clear);
color_attachment.set_clear_color(MTLClearColor::new(0.2, 0.2, 0.25, 1.0));
color_attachment.set_store_action(MTLStoreAction::Store);
}
fn main() {
let event_loop = winit::event_loop::EventLoop::new().unwrap();
let size = winit::dpi::LogicalSize::new(800, 600);
let window = winit::window::WindowBuilder::new()
.with_inner_size(size)
.with_title("Metal Window Example".to_string())
.build(&event_loop)
.unwrap();
let device = Device::system_default().expect("no device found");
let layer = MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_presents_with_transaction(false);
unsafe {
if let Ok(RawWindowHandle::AppKit(rw)) = window.window_handle().map(|wh| wh.as_raw()) {
let view = rw.ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(mem::transmute(layer.as_ref()));
}
}
let draw_size = window.inner_size();
layer.set_drawable_size(CGSize::new(draw_size.width as f64, draw_size.height as f64));
let library_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples/window/shaders.metallib");
let library = device.new_library_with_file(library_path).unwrap();
let triangle_pipeline_state =
prepare_pipeline_state(&device, &library, "triangle_vertex", "triangle_fragment");
let clear_rect_pipeline_state = prepare_pipeline_state(
&device,
&library,
"clear_rect_vertex",
"clear_rect_fragment",
);
let command_queue = device.new_command_queue();
//let nc: () = msg_send![command_queue.0, setExecutionEnabled:true];
let vbuf = {
let vertex_data = [
0.0f32, 0.5, 1.0, 0.0, 0.0, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, 0.5, 0.0, 0.0, 1.0,
];
device.new_buffer_with_data(
vertex_data.as_ptr() as *const _,
(vertex_data.len() * mem::size_of::<f32>()) as u64,
MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged,
)
};
let mut r = 0.0f32;
let clear_rect = vec![ClearRect {
rect: Rect {
x: -1.0,
y: -1.0,
w: 2.0,
h: 2.0,
},
color: Color {
r: 0.5,
g: 0.8,
b: 0.5,
a: 1.0,
},
}];
let clear_rect_buffer = device.new_buffer_with_data(
clear_rect.as_ptr() as *const _,
mem::size_of::<ClearRect>() as u64,
MTLResourceOptions::CPUCacheModeDefaultCache | MTLResourceOptions::StorageModeManaged,
);
event_loop
.run(move |event, event_loop| {
autoreleasepool(|| {
event_loop.set_control_flow(ControlFlow::Poll);
match event {
Event::AboutToWait => window.request_redraw(),
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::Resized(size) => {
layer.set_drawable_size(CGSize::new(
size.width as f64,
size.height as f64,
));
}
WindowEvent::RedrawRequested => {
let p = vbuf.contents();
let vertex_data = [
0.0f32,
0.5,
1.0,
0.0,
0.0,
-0.5 + (r.cos() / 2. + 0.5),
-0.5,
0.0,
1.0,
0.0,
0.5 - (r.cos() / 2. + 0.5),
-0.5,
0.0,
0.0,
1.0,
];
unsafe {
std::ptr::copy(
vertex_data.as_ptr(),
p as *mut f32,
(vertex_data.len() * mem::size_of::<f32>()) as usize,
);
}
vbuf.did_modify_range(crate::NSRange::new(
0 as u64,
(vertex_data.len() * mem::size_of::<f32>()) as u64,
));
let drawable = match layer.next_drawable() {
Some(drawable) => drawable,
None => return,
};
let render_pass_descriptor = RenderPassDescriptor::new();
prepare_render_pass_descriptor(
&render_pass_descriptor,
drawable.texture(),
);
let command_buffer = command_queue.new_command_buffer();
let encoder =
command_buffer.new_render_command_encoder(&render_pass_descriptor);
encoder.set_scissor_rect(MTLScissorRect {
x: 20,
y: 20,
width: 100,
height: 100,
});
encoder.set_render_pipeline_state(&clear_rect_pipeline_state);
encoder.set_vertex_buffer(0, Some(&clear_rect_buffer), 0);
encoder.draw_primitives_instanced(
metal::MTLPrimitiveType::TriangleStrip,
0,
4,
1,
);
let physical_size = window.inner_size();
encoder.set_scissor_rect(MTLScissorRect {
x: 0,
y: 0,
width: physical_size.width as _,
height: physical_size.height as _,
});
encoder.set_render_pipeline_state(&triangle_pipeline_state);
encoder.set_vertex_buffer(0, Some(&vbuf), 0);
encoder.draw_primitives(MTLPrimitiveType::Triangle, 0, 3);
encoder.end_encoding();
command_buffer.present_drawable(&drawable);
command_buffer.commit();
r += 0.01f32;
}
_ => (),
},
_ => {}
}
});
})
.unwrap();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,97 @@
#include <metal_stdlib>
using namespace metal;
typedef struct {
packed_float2 position;
packed_float3 color;
} vertex_t;
struct ColorInOut {
float4 position [[position]];
float4 color;
};
// vertex shader function
vertex ColorInOut triangle_vertex(const device vertex_t* vertex_array [[ buffer(0) ]],
unsigned int vid [[ vertex_id ]])
{
ColorInOut out;
auto device const &v = vertex_array[vid];
out.position = float4(v.position.x, v.position.y, 0.0, 1.0);
out.color = float4(v.color.x, v.color.y, v.color.z, 0.2);
return out;
}
// fragment shader function
fragment float4 triangle_fragment(ColorInOut in [[stage_in]])
{
return in.color;
};
struct Rect {
float x;
float y;
float w;
float h;
};
struct Color {
float r;
float g;
float b;
float a;
};
struct ClearRect {
Rect rect;
Color color;
};
float2 rect_vert(
Rect rect,
uint vid
) {
float2 pos;
float left = rect.x;
float right = rect.x + rect.w;
float bottom = rect.y;
float top = rect.y + rect.h;
switch (vid) {
case 0:
pos = float2(right, top);
break;
case 1:
pos = float2(left, top);
break;
case 2:
pos = float2(right, bottom);
break;
case 3:
pos = float2(left, bottom);
break;
}
return pos;
}
vertex ColorInOut clear_rect_vertex(
const device ClearRect *clear_rect [[ buffer(0) ]],
unsigned int vid [[ vertex_id ]]
) {
ColorInOut out;
float4 pos = float4(rect_vert(clear_rect->rect, vid), 0, 1);
auto col = clear_rect->color;
out.position = pos;
out.color = float4(col.r, col.g, col.b, col.a);
return out;
}
fragment float4 clear_rect_fragment(ColorInOut in [[stage_in]])
{
return in.color;
};

Binary file not shown.

View File

@@ -0,0 +1,667 @@
// Copyright 2023 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
bitflags::bitflags! {
#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLAccelerationStructureInstanceOptions: u32 {
const None = 0;
const DisableTriangleCulling = (1 << 0);
const TriangleFrontFacingWindingCounterClockwise = (1 << 1);
const Opaque = (1 << 2);
const NonOpaque = (1 << 3);
}
}
/// See <https://developer.apple.com/documentation/metal/mtlaccelerationstructureinstancedescriptortype>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum MTLAccelerationStructureInstanceDescriptorType {
Default = 0,
UserID = 1,
Motion = 2,
Indirect = 3,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
#[repr(C)]
pub struct MTLAccelerationStructureInstanceDescriptor {
pub transformation_matrix: [[f32; 3]; 4],
pub options: MTLAccelerationStructureInstanceOptions,
pub mask: u32,
pub intersection_function_table_offset: u32,
pub acceleration_structure_index: u32,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
#[repr(C)]
pub struct MTLAccelerationStructureUserIDInstanceDescriptor {
pub transformation_matrix: [[f32; 3]; 4],
pub options: MTLAccelerationStructureInstanceOptions,
pub mask: u32,
pub intersection_function_table_offset: u32,
pub acceleration_structure_index: u32,
pub user_id: u32,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
#[repr(C)]
pub struct MTLIndirectAccelerationStructureInstanceDescriptor {
pub transformation_matrix: [[f32; 3]; 4],
pub options: MTLAccelerationStructureInstanceOptions,
pub mask: u32,
pub intersection_function_table_offset: u32,
pub user_id: u32,
pub acceleration_structure_id: u64,
}
pub enum MTLAccelerationStructureDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructureDescriptor;
pub struct AccelerationStructureDescriptor;
type ParentType = NsObject;
}
pub enum MTLPrimitiveAccelerationStructureDescriptor {}
foreign_obj_type! {
type CType = MTLPrimitiveAccelerationStructureDescriptor;
pub struct PrimitiveAccelerationStructureDescriptor;
type ParentType = AccelerationStructureDescriptor;
}
impl PrimitiveAccelerationStructureDescriptor {
pub fn descriptor() -> Self {
unsafe {
let class = class!(MTLPrimitiveAccelerationStructureDescriptor);
let ptr: *mut Object = msg_send![class, descriptor];
let ptr: *mut Object = msg_send![ptr, retain];
Self::from_ptr(ptr as _)
}
}
}
impl PrimitiveAccelerationStructureDescriptorRef {
pub fn set_geometry_descriptors(
&self,
descriptors: &ArrayRef<AccelerationStructureGeometryDescriptor>,
) {
unsafe { msg_send![self, setGeometryDescriptors: descriptors] }
}
}
pub enum MTLAccelerationStructure {}
foreign_obj_type! {
type CType = MTLAccelerationStructure;
pub struct AccelerationStructure;
type ParentType = Resource;
}
impl AccelerationStructureRef {
pub fn gpu_resource_id(&self) -> MTLResourceID {
unsafe { msg_send![self, gpuResourceID] }
}
}
pub enum MTLAccelerationStructureGeometryDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructureGeometryDescriptor;
pub struct AccelerationStructureGeometryDescriptor;
type ParentType = NsObject;
}
impl AccelerationStructureGeometryDescriptorRef {
pub fn set_opaque(&self, opaque: bool) {
unsafe { msg_send![self, setOpaque: opaque] }
}
pub fn set_primitive_data_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setPrimitiveDataBuffer: buffer] }
}
pub fn set_primitive_data_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setPrimitiveDataStride: stride] }
}
pub fn set_primitive_data_element_size(&self, size: NSUInteger) {
unsafe { msg_send![self, setPrimitiveDataElementSize: size] }
}
pub fn set_intersection_function_table_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setIntersectionFunctionTableOffset: offset] }
}
}
pub enum MTLAccelerationStructureTriangleGeometryDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructureTriangleGeometryDescriptor;
pub struct AccelerationStructureTriangleGeometryDescriptor;
type ParentType = AccelerationStructureGeometryDescriptor;
}
impl AccelerationStructureTriangleGeometryDescriptor {
pub fn descriptor() -> Self {
unsafe {
let class = class!(MTLAccelerationStructureTriangleGeometryDescriptor);
let ptr: *mut Object = msg_send![class, descriptor];
let ptr: *mut Object = msg_send![ptr, retain];
Self::from_ptr(ptr as _)
}
}
}
impl AccelerationStructureTriangleGeometryDescriptorRef {
pub fn set_index_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setIndexBuffer: buffer] }
}
pub fn set_index_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setIndexBufferOffset: offset] }
}
pub fn set_index_type(&self, t: MTLIndexType) {
unsafe { msg_send![self, setIndexType: t] }
}
pub fn set_vertex_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setVertexBuffer: buffer] }
}
pub fn set_vertex_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setVertexBufferOffset: offset] }
}
pub fn set_vertex_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setVertexStride: stride] }
}
pub fn set_triangle_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setTriangleCount: count] }
}
pub fn set_vertex_format(&self, format: MTLAttributeFormat) {
unsafe { msg_send![self, setVertexFormat: format] }
}
pub fn set_transformation_matrix_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setTransformationMatrixBuffer: buffer] }
}
pub fn set_transformation_matrix_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setTransformationMatrixBufferOffset: offset] }
}
}
pub enum MTLAccelerationStructureBoundingBoxGeometryDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructureBoundingBoxGeometryDescriptor;
pub struct AccelerationStructureBoundingBoxGeometryDescriptor;
type ParentType = AccelerationStructureGeometryDescriptor;
}
impl AccelerationStructureBoundingBoxGeometryDescriptor {
pub fn descriptor() -> Self {
unsafe {
let class = class!(MTLAccelerationStructureBoundingBoxGeometryDescriptor);
let ptr: *mut Object = msg_send![class, descriptor];
let ptr: *mut Object = msg_send![ptr, retain];
Self::from_ptr(ptr as _)
}
}
}
impl AccelerationStructureBoundingBoxGeometryDescriptorRef {
pub fn set_bounding_box_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setBoundingBoxBuffer: buffer] }
}
pub fn set_bounding_box_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setBoundingBoxCount: count] }
}
pub fn set_bounding_box_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setBoundingBoxStride: stride] }
}
pub fn set_bounding_box_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setBoundingBoxBufferOffset: offset] }
}
}
pub enum MTLInstanceAccelerationStructureDescriptor {}
foreign_obj_type! {
type CType = MTLInstanceAccelerationStructureDescriptor;
pub struct InstanceAccelerationStructureDescriptor;
type ParentType = AccelerationStructureDescriptor;
}
impl InstanceAccelerationStructureDescriptor {
pub fn descriptor() -> Self {
unsafe {
let class = class!(MTLInstanceAccelerationStructureDescriptor);
let ptr: *mut Object = msg_send![class, descriptor];
let ptr: *mut Object = msg_send![ptr, retain];
Self::from_ptr(ptr as _)
}
}
}
impl InstanceAccelerationStructureDescriptorRef {
pub fn set_instance_descriptor_type(&self, ty: MTLAccelerationStructureInstanceDescriptorType) {
unsafe { msg_send![self, setInstanceDescriptorType: ty] }
}
pub fn set_instanced_acceleration_structures(
&self,
instances: &ArrayRef<AccelerationStructure>,
) {
unsafe { msg_send![self, setInstancedAccelerationStructures: instances] }
}
pub fn set_instance_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setInstanceCount: count] }
}
pub fn set_instance_descriptor_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setInstanceDescriptorBuffer: buffer] }
}
pub fn set_instance_descriptor_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setInstanceDescriptorBufferOffset: offset] }
}
pub fn set_instance_descriptor_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setInstanceDescriptorStride: stride] }
}
}
pub enum MTLIndirectInstanceAccelerationStructureDescriptor {}
foreign_obj_type! {
type CType = MTLIndirectInstanceAccelerationStructureDescriptor;
pub struct IndirectInstanceAccelerationStructureDescriptor;
type ParentType = AccelerationStructureDescriptor;
}
impl IndirectInstanceAccelerationStructureDescriptor {
pub fn descriptor() -> Self {
unsafe {
let class = class!(MTLIndirectInstanceAccelerationStructureDescriptor);
let ptr: *mut Object = msg_send![class, descriptor];
let ptr: *mut Object = msg_send![ptr, retain];
Self::from_ptr(ptr as _)
}
}
}
impl IndirectInstanceAccelerationStructureDescriptorRef {
pub fn set_instance_descriptor_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setInstanceDescriptorBuffer: buffer] }
}
pub fn set_instance_descriptor_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setInstanceDescriptorBufferOffset: offset] }
}
pub fn set_instance_descriptor_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setInstanceDescriptorStride: stride] }
}
pub fn set_max_instance_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxInstanceCount: count] }
}
pub fn set_instance_count_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setInstanceCountBuffer: buffer] }
}
pub fn set_instance_count_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setInstanceCountBufferOffset: offset] }
}
pub fn set_instance_descriptor_type(&self, ty: MTLAccelerationStructureInstanceDescriptorType) {
unsafe { msg_send![self, setInstanceDescriptorType: ty] }
}
pub fn set_motion_transform_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setMotionTransformBuffer: buffer] }
}
pub fn set_motion_transform_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setMotionTransformBufferOffset: offset] }
}
pub fn set_max_motion_transform_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxMotionTransformCount: count] }
}
pub fn set_motion_transform_count_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setMotionTransformCountBuffer: buffer] }
}
pub fn set_motion_transform_count_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setMotionTransformCountBufferOffset: offset] }
}
}
pub enum MTLAccelerationStructureCommandEncoder {}
foreign_obj_type! {
type CType = MTLAccelerationStructureCommandEncoder;
pub struct AccelerationStructureCommandEncoder;
type ParentType = CommandEncoder;
}
impl AccelerationStructureCommandEncoderRef {
pub fn build_acceleration_structure(
&self,
acceleration_structure: &self::AccelerationStructureRef,
descriptor: &self::AccelerationStructureDescriptorRef,
scratch_buffer: &BufferRef,
scratch_buffer_offset: NSUInteger,
) {
unsafe {
msg_send![
self,
buildAccelerationStructure: acceleration_structure
descriptor: descriptor
scratchBuffer: scratch_buffer
scratchBufferOffset: scratch_buffer_offset
]
}
}
pub fn copy_acceleration_structure(
&self,
source_acceleration_structure: &AccelerationStructureRef,
destination_acceleration_structure: &AccelerationStructureRef,
) {
unsafe {
msg_send![
self,
copyAccelerationStructure: source_acceleration_structure
toAccelerationStructure: destination_acceleration_structure
]
}
}
pub fn write_compacted_acceleration_structure_size(
&self,
acceleration_structure: &AccelerationStructureRef,
to_buffer: &BufferRef,
offset: NSUInteger,
) {
unsafe {
msg_send![
self,
writeCompactedAccelerationStructureSize: acceleration_structure
toBuffer: to_buffer
offset: offset
]
}
}
pub fn write_compacted_acceleration_structure_size_with_type(
&self,
acceleration_structure: &AccelerationStructureRef,
to_buffer: &BufferRef,
offset: NSUInteger,
size_data_type: MTLDataType,
) {
unsafe {
msg_send![
self,
writeCompactedAccelerationStructureSize: acceleration_structure
toBuffer: to_buffer
offset: offset
sizeDataType: size_data_type
]
}
}
pub fn copy_and_compact_acceleration_structure(
&self,
source: &AccelerationStructureRef,
destination: &AccelerationStructureRef,
) {
unsafe {
msg_send![
self,
copyAndCompactAccelerationStructure: source
toAccelerationStructure: destination
]
}
}
pub fn refit_acceleration_structure(
&self,
source_acceleration_structure: &AccelerationStructureRef,
descriptor: &self::AccelerationStructureDescriptorRef,
destination_acceleration_structure: Option<&AccelerationStructureRef>,
scratch_buffer: &BufferRef,
scratch_buffer_offset: NSUInteger,
) {
unsafe {
msg_send![
self,
refitAccelerationStructure: source_acceleration_structure
descriptor: descriptor
destination: destination_acceleration_structure
scratchBuffer: scratch_buffer
scratchBufferOffset: scratch_buffer_offset
]
}
}
pub fn update_fence(&self, fence: &FenceRef) {
unsafe { msg_send![self, updateFence: fence] }
}
pub fn wait_for_fence(&self, fence: &FenceRef) {
unsafe { msg_send![self, waitForFence: fence] }
}
pub fn use_heap(&self, heap: &HeapRef) {
unsafe { msg_send![self, useHeap: heap] }
}
pub fn use_heaps(&self, heaps: &[&HeapRef]) {
unsafe {
msg_send![self,
useHeaps: heaps.as_ptr()
count: heaps.len() as NSUInteger
]
}
}
pub fn use_resource(&self, resource: &ResourceRef, usage: MTLResourceUsage) {
unsafe {
msg_send![self,
useResource: resource
usage: usage
]
}
}
pub fn use_resources(&self, resources: &[&ResourceRef], usage: MTLResourceUsage) {
unsafe {
msg_send![self,
useResources: resources.as_ptr()
count: resources.len() as NSUInteger
usage: usage
]
}
}
pub fn sample_counters_in_buffer(
&self,
sample_buffer: &CounterSampleBufferRef,
sample_index: NSUInteger,
with_barrier: bool,
) {
unsafe {
msg_send![self,
sampleCountersInBuffer: sample_buffer
atSampleIndex: sample_index
withBarrier: with_barrier
]
}
}
}
pub enum MTLIntersectionFunctionTableDescriptor {}
foreign_obj_type! {
type CType = MTLIntersectionFunctionTableDescriptor;
pub struct IntersectionFunctionTableDescriptor;
type ParentType = NsObject;
}
impl IntersectionFunctionTableDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLIntersectionFunctionTableDescriptor);
let this: *mut <Self as ForeignType>::CType = msg_send![class, alloc];
msg_send![this, init]
}
}
}
impl IntersectionFunctionTableDescriptorRef {
pub fn set_function_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setFunctionCount: count] }
}
}
pub enum MTLIntersectionFunctionTable {}
foreign_obj_type! {
type CType = MTLIntersectionFunctionTable;
pub struct IntersectionFunctionTable;
type ParentType = Resource;
}
impl IntersectionFunctionTableRef {
pub fn set_function(&self, function: &FunctionHandleRef, index: NSUInteger) {
unsafe { msg_send![self, setFunction: function atIndex: index] }
}
pub fn set_functions(&self, functions: &[&FunctionHandleRef], start_index: NSUInteger) {
unsafe {
msg_send![self, setFunctions: functions.as_ptr() withRange: NSRange { location: start_index, length: functions.len() as _ }]
}
}
pub fn set_buffer(&self, index: NSUInteger, buffer: Option<&BufferRef>, offset: NSUInteger) {
unsafe { msg_send![self, setBuffer:buffer offset:offset atIndex:index] }
}
pub fn set_buffers(
&self,
start_index: NSUInteger,
data: &[Option<&BufferRef>],
offsets: &[NSUInteger],
) {
debug_assert_eq!(offsets.len(), data.len());
unsafe {
msg_send![self,
setBuffers: data.as_ptr()
offsets: offsets.as_ptr()
withRange: NSRange {
location: start_index,
length: data.len() as _,
}
]
}
}
pub fn set_visible_function_table(
&self,
buffer_index: NSUInteger,
visible_function_table: Option<&VisibleFunctionTableRef>,
) {
unsafe {
msg_send![self,
setVisibleFunctionTable:visible_function_table
atBufferIndex:buffer_index]
}
}
pub fn set_visible_function_tables(
&self,
buffer_start_index: NSUInteger,
visible_function_tables: &[&VisibleFunctionTableRef],
) {
unsafe {
msg_send![self,
setVisibleFunctionTables:visible_function_tables.as_ptr()
withBufferRange: NSRange {
location: buffer_start_index,
length: visible_function_tables.len() as _,
}]
}
}
pub fn gpu_resource_id(&self) -> MTLResourceID {
unsafe { msg_send![self, gpuResourceID] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvisiblefunctiontabledescriptor>
pub enum MTLVisibleFunctionTableDescriptor {}
foreign_obj_type! {
type CType = MTLVisibleFunctionTableDescriptor;
pub struct VisibleFunctionTableDescriptor;
type ParentType = NsObject;
}
impl VisibleFunctionTableDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLVisibleFunctionTableDescriptor);
msg_send![class, new]
}
}
}
impl VisibleFunctionTableDescriptorRef {
pub fn set_function_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setFunctionCount: count] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvisiblefunctiontable>
pub enum MTLVisibleFunctionTable {}
foreign_obj_type! {
type CType = MTLVisibleFunctionTable;
pub struct VisibleFunctionTable;
type ParentType = Resource;
}
impl VisibleFunctionTableRef {
pub fn set_functions(&self, functions: &[&FunctionRef]) {
let ns_array = Array::<Function>::from_slice(functions);
unsafe { msg_send![self, setFunctions: ns_array] }
}
pub fn set_function(&self, index: NSUInteger, function: &FunctionHandleRef) {
unsafe { msg_send![self, setFunction: function atIndex: index] }
}
pub fn gpu_resource_id(&self) -> MTLResourceID {
unsafe { msg_send![self, gpuResourceID] }
}
}

View File

@@ -0,0 +1,108 @@
use super::{CounterSampleBufferRef, NSUInteger};
/// See <https://developer.apple.com/documentation/metal/mtlaccelerationstructurepassdescriptor>
pub enum MTLAccelerationStructurePassDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructurePassDescriptor;
pub struct AccelerationStructurePassDescriptor;
}
impl AccelerationStructurePassDescriptor {
/// Creates a default compute pass descriptor with no attachments.
pub fn new<'a>() -> &'a AccelerationStructurePassDescriptorRef {
unsafe {
msg_send![
class!(MTLAccelerationStructurePassDescriptor),
accelerationStructurePassDescriptor
]
}
}
}
impl AccelerationStructurePassDescriptorRef {
pub fn sample_buffer_attachments(
&self,
) -> &AccelerationStructurePassSampleBufferAttachmentDescriptorArrayRef {
unsafe { msg_send![self, sampleBufferAttachments] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlaccelerationstructurepasssamplebufferattachmentdescriptorarray>
pub enum MTLAccelerationStructurePassSampleBufferAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLAccelerationStructurePassSampleBufferAttachmentDescriptorArray;
pub struct AccelerationStructurePassSampleBufferAttachmentDescriptorArray;
}
impl AccelerationStructurePassSampleBufferAttachmentDescriptorArrayRef {
pub fn object_at(
&self,
index: NSUInteger,
) -> Option<&AccelerationStructurePassSampleBufferAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&AccelerationStructurePassSampleBufferAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlaccelerationstructurepasssamplebufferattachmentdescriptor>
pub enum MTLAccelerationStructurePassSampleBufferAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLAccelerationStructurePassSampleBufferAttachmentDescriptor;
pub struct AccelerationStructurePassSampleBufferAttachmentDescriptor;
}
impl AccelerationStructurePassSampleBufferAttachmentDescriptor {
pub fn new() -> Self {
let class = class!(MTLAccelerationStructurePassSampleBufferAttachmentDescriptor);
unsafe { msg_send![class, new] }
}
}
impl AccelerationStructurePassSampleBufferAttachmentDescriptorRef {
pub fn sample_buffer(&self) -> Option<&CounterSampleBufferRef> {
unsafe { msg_send![self, sampleBuffer] }
}
pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) {
unsafe { msg_send![self, setSampleBuffer: sample_buffer] }
}
pub fn start_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, startOfEncoderSampleIndex] }
}
pub fn set_start_of_encoder_sample_index(&self, start_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setStartOfEncoderSampleIndex: start_of_encoder_sample_index
]
}
}
pub fn end_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, endOfEncoderSampleIndex] }
}
pub fn set_end_of_encoder_sample_index(&self, end_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setEndOfEncoderSampleIndex: end_of_encoder_sample_index
]
}
}
}

366
vendor/metal/src/argument.rs vendored Normal file
View File

@@ -0,0 +1,366 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::{MTLTextureType, NSUInteger};
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtldatatype>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLDataType {
None = 0,
Struct = 1,
Array = 2,
Float = 3,
Float2 = 4,
Float3 = 5,
Float4 = 6,
Float2x2 = 7,
Float2x3 = 8,
Float2x4 = 9,
Float3x2 = 10,
Float3x3 = 11,
Float3x4 = 12,
Float4x2 = 13,
Float4x3 = 14,
Float4x4 = 15,
Half = 16,
Half2 = 17,
Half3 = 18,
Half4 = 19,
Half2x2 = 20,
Half2x3 = 21,
Half2x4 = 22,
Half3x2 = 23,
Half3x3 = 24,
Half3x4 = 25,
Half4x2 = 26,
Half4x3 = 27,
Half4x4 = 28,
Int = 29,
Int2 = 30,
Int3 = 31,
Int4 = 32,
UInt = 33,
UInt2 = 34,
UInt3 = 35,
UInt4 = 36,
Short = 37,
Short2 = 38,
Short3 = 39,
Short4 = 40,
UShort = 41,
UShort2 = 42,
UShort3 = 43,
UShort4 = 44,
Char = 45,
Char2 = 46,
Char3 = 47,
Char4 = 48,
UChar = 49,
UChar2 = 50,
UChar3 = 51,
UChar4 = 52,
Bool = 53,
Bool2 = 54,
Bool3 = 55,
Bool4 = 56,
Texture = 58,
Sampler = 59,
Pointer = 60,
R8Unorm = 62,
R8Snorm = 63,
R16Unorm = 64,
R16Snorm = 65,
RG8Unorm = 66,
RG8Snorm = 67,
RG16Unorm = 68,
RG16Snorm = 69,
RGBA8Unorm = 70,
RGBA8Unorm_sRGB = 71,
RGBA8Snorm = 72,
RGBA16Unorm = 73,
RGBA16Snorm = 74,
RGB10A2Unorm = 75,
RG11B10Float = 76,
RGB9E5Float = 77,
RenderPipeline = 78,
ComputePipeline = 79,
IndirectCommandBuffer = 80,
Long = 81,
Long2 = 82,
Long3 = 83,
Long4 = 84,
ULong = 85,
ULong2 = 86,
ULong3 = 87,
ULong4 = 88,
VisibleFunctionTable = 115,
IntersectionFunctionTable = 116,
PrimitiveAccelerationStructure = 117,
InstanceAccelerationStructure = 118,
BFloat = 121,
BFloat2 = 122,
BFloat3 = 123,
BFloat4 = 124,
}
/// See <https://developer.apple.com/documentation/metal/mtlargumenttype>
#[repr(u64)]
#[deprecated(
note = "Since: iOS 8.016.0, iPadOS 8.016.0, macOS 10.1113.0, Mac Catalyst 13.116.0, tvOS 9.016.0"
)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLArgumentType {
Buffer = 0,
ThreadgroupMemory = 1,
Texture = 2,
Sampler = 3,
ImageblockData = 16,
Imageblock = 17,
}
/// See <https://developer.apple.com/documentation/metal/mtlargumentaccess>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLArgumentAccess {
ReadOnly = 0,
ReadWrite = 1,
WriteOnly = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlstructmember>
pub enum MTLStructMember {}
foreign_obj_type! {
type CType = MTLStructMember;
pub struct StructMember;
}
impl StructMemberRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn offset(&self) -> NSUInteger {
unsafe { msg_send![self, offset] }
}
pub fn data_type(&self) -> MTLDataType {
unsafe { msg_send![self, dataType] }
}
pub fn struct_type(&self) -> MTLStructType {
unsafe { msg_send![self, structType] }
}
pub fn array_type(&self) -> MTLArrayType {
unsafe { msg_send![self, arrayType] }
}
}
pub enum MTLStructMemberArray {}
foreign_obj_type! {
type CType = MTLStructMemberArray;
pub struct StructMemberArray;
}
impl StructMemberArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&StructMemberRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn count(&self) -> NSUInteger {
unsafe { msg_send![self, count] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlstructtype>
pub enum MTLStructType {}
foreign_obj_type! {
type CType = MTLStructType;
pub struct StructType;
}
impl StructTypeRef {
pub fn members(&self) -> &StructMemberArrayRef {
unsafe { msg_send![self, members] }
}
pub fn member_from_name(&self, name: &str) -> Option<&StructMemberRef> {
let nsname = crate::nsstring_from_str(name);
unsafe { msg_send![self, memberByName: nsname] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlarraytype>
pub enum MTLArrayType {}
foreign_obj_type! {
type CType = MTLArrayType;
pub struct ArrayType;
}
impl ArrayTypeRef {
pub fn array_length(&self) -> NSUInteger {
unsafe { msg_send![self, arrayLength] }
}
pub fn stride(&self) -> NSUInteger {
unsafe { msg_send![self, stride] }
}
pub fn element_type(&self) -> MTLDataType {
unsafe { msg_send![self, elementType] }
}
pub fn element_struct_type(&self) -> MTLStructType {
unsafe { msg_send![self, elementStructType] }
}
pub fn element_array_type(&self) -> MTLArrayType {
unsafe { msg_send![self, elementArrayType] }
}
}
/// <https://developer.apple.com/documentation/metal/mtlargument>
#[deprecated(
note = "Since iOS 8.016.0, iPadOS 8.016.0, macOS 10.1113.0, Mac Catalyst 13.116.0, tvOS 9.016.0"
)]
pub enum MTLArgument {}
foreign_obj_type! {
type CType = MTLArgument;
pub struct Argument;
}
impl ArgumentRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn type_(&self) -> MTLArgumentType {
unsafe { msg_send![self, type] }
}
pub fn access(&self) -> MTLArgumentAccess {
unsafe { msg_send![self, access] }
}
pub fn index(&self) -> NSUInteger {
unsafe { msg_send![self, index] }
}
pub fn is_active(&self) -> bool {
unsafe { msg_send_bool![self, isActive] }
}
pub fn buffer_alignment(&self) -> NSUInteger {
unsafe { msg_send![self, bufferAlignment] }
}
pub fn buffer_data_size(&self) -> NSUInteger {
unsafe { msg_send![self, bufferDataSize] }
}
pub fn buffer_data_type(&self) -> MTLDataType {
unsafe { msg_send![self, bufferDataType] }
}
pub fn buffer_struct_type(&self) -> &StructTypeRef {
unsafe { msg_send![self, bufferStructType] }
}
pub fn threadgroup_memory_alignment(&self) -> NSUInteger {
unsafe { msg_send![self, threadgroupMemoryAlignment] }
}
pub fn threadgroup_memory_data_size(&self) -> NSUInteger {
unsafe { msg_send![self, threadgroupMemoryDataSize] }
}
pub fn texture_type(&self) -> MTLTextureType {
unsafe { msg_send![self, textureType] }
}
pub fn texture_data_type(&self) -> MTLDataType {
unsafe { msg_send![self, textureDataType] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlargumentdescriptor>
pub enum MTLArgumentDescriptor {}
foreign_obj_type! {
type CType = MTLArgumentDescriptor;
pub struct ArgumentDescriptor;
}
impl ArgumentDescriptor {
pub fn new<'a>() -> &'a ArgumentDescriptorRef {
unsafe {
let class = class!(MTLArgumentDescriptor);
msg_send![class, argumentDescriptor]
}
}
}
impl ArgumentDescriptorRef {
pub fn set_data_type(&self, ty: MTLDataType) {
unsafe { msg_send![self, setDataType: ty] }
}
pub fn set_index(&self, index: NSUInteger) {
unsafe { msg_send![self, setIndex: index] }
}
pub fn set_access(&self, access: MTLArgumentAccess) {
unsafe { msg_send![self, setAccess: access] }
}
pub fn set_array_length(&self, length: NSUInteger) {
unsafe { msg_send![self, setArrayLength: length] }
}
pub fn set_texture_type(&self, ty: MTLTextureType) {
unsafe { msg_send![self, setTextureType: ty] }
}
}

102
vendor/metal/src/blitpass.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
use super::*;
/// See <https://developer.apple.com/documentation/metal/mtlblitpassdescriptor>
pub enum MTLBlitPassDescriptor {}
foreign_obj_type! {
type CType = MTLBlitPassDescriptor;
pub struct BlitPassDescriptor;
}
impl BlitPassDescriptor {
/// Creates a default blit command pass descriptor with no attachments.
pub fn new<'a>() -> &'a BlitPassDescriptorRef {
unsafe { msg_send![class!(MTLBlitPassDescriptor), blitPassDescriptor] }
}
}
impl BlitPassDescriptorRef {
// See <https://developer.apple.com/documentation/metal/mtlblitpassdescriptor>
pub fn sample_buffer_attachments(&self) -> &BlitPassSampleBufferAttachmentDescriptorArrayRef {
unsafe { msg_send![self, sampleBufferAttachments] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlblitpasssamplebufferattachmentdescriptorarray>
pub enum MTLBlitPassSampleBufferAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLBlitPassSampleBufferAttachmentDescriptorArray;
pub struct BlitPassSampleBufferAttachmentDescriptorArray;
}
impl BlitPassSampleBufferAttachmentDescriptorArrayRef {
pub fn object_at(
&self,
index: NSUInteger,
) -> Option<&BlitPassSampleBufferAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&BlitPassSampleBufferAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlblitpasssamplebufferattachmentdescriptor>
pub enum MTLBlitPassSampleBufferAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLBlitPassSampleBufferAttachmentDescriptor;
pub struct BlitPassSampleBufferAttachmentDescriptor;
}
impl BlitPassSampleBufferAttachmentDescriptor {
pub fn new() -> Self {
let class = class!(MTLBlitPassSampleBufferAttachmentDescriptor);
unsafe { msg_send![class, new] }
}
}
impl BlitPassSampleBufferAttachmentDescriptorRef {
pub fn sample_buffer(&self) -> Option<&CounterSampleBufferRef> {
unsafe { msg_send![self, sampleBuffer] }
}
pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) {
unsafe { msg_send![self, setSampleBuffer: sample_buffer] }
}
pub fn start_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, startOfEncoderSampleIndex] }
}
pub fn set_start_of_encoder_sample_index(&self, start_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setStartOfEncoderSampleIndex: start_of_encoder_sample_index
]
}
}
pub fn end_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, endOfEncoderSampleIndex] }
}
pub fn set_end_of_encoder_sample_index(&self, end_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setEndOfEncoderSampleIndex: end_of_encoder_sample_index
]
}
}
}

71
vendor/metal/src/buffer.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
/// See <https://developer.apple.com/documentation/metal/mtlbuffer>
pub enum MTLBuffer {}
foreign_obj_type! {
type CType = MTLBuffer;
pub struct Buffer;
type ParentType = Resource;
}
impl BufferRef {
pub fn length(&self) -> u64 {
unsafe { msg_send![self, length] }
}
pub fn contents(&self) -> *mut std::ffi::c_void {
unsafe { msg_send![self, contents] }
}
pub fn did_modify_range(&self, range: crate::NSRange) {
unsafe { msg_send![self, didModifyRange: range] }
}
pub fn new_texture_with_descriptor(
&self,
descriptor: &TextureDescriptorRef,
offset: u64,
bytes_per_row: u64,
) -> Texture {
unsafe {
msg_send![self,
newTextureWithDescriptor:descriptor
offset:offset
bytesPerRow:bytes_per_row
]
}
}
/// Only available on macos(10.15), NOT available on (ios)
pub fn remote_storage_buffer(&self) -> &BufferRef {
unsafe { msg_send![self, remoteStorageBuffer] }
}
/// Only available on (macos(10.15), NOT available on (ios)
pub fn new_remote_buffer_view_for_device(&self, device: &DeviceRef) -> Buffer {
unsafe { msg_send![self, newRemoteBufferViewForDevice: device] }
}
pub fn add_debug_marker(&self, name: &str, range: crate::NSRange) {
unsafe {
let name = crate::nsstring_from_str(name);
msg_send![self, addDebugMarker:name range:range]
}
}
pub fn remove_all_debug_markers(&self) {
unsafe { msg_send![self, removeAllDebugMarkers] }
}
pub fn gpu_address(&self) -> u64 {
unsafe { msg_send![self, gpuAddress] }
}
}

76
vendor/metal/src/capturedescriptor.rs vendored Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2020 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use std::path::Path;
/// See <https://developer.apple.com/documentation/metal/mtlcapturedestination?language=objc>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCaptureDestination {
DeveloperTools = 1,
GpuTraceDocument = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor>
pub enum MTLCaptureDescriptor {}
foreign_obj_type! {
type CType = MTLCaptureDescriptor;
pub struct CaptureDescriptor;
}
impl CaptureDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLCaptureDescriptor);
msg_send![class, new]
}
}
}
impl CaptureDescriptorRef {
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject>
pub fn set_capture_device(&self, device: &DeviceRef) {
unsafe { msg_send![self, setCaptureObject: device] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject>
pub fn set_capture_scope(&self, scope: &CaptureScopeRef) {
unsafe { msg_send![self, setCaptureObject: scope] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject>
pub fn set_capture_command_queue(&self, command_queue: &CommandQueueRef) {
unsafe { msg_send![self, setCaptureObject: command_queue] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl>
pub fn output_url(&self) -> &Path {
let url: &URLRef = unsafe { msg_send![self, outputURL] };
Path::new(url.path())
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl>
pub fn set_output_url<P: AsRef<Path>>(&self, output_url: P) {
let output_url_string = String::from("file://") + output_url.as_ref().to_str().unwrap();
let output_url = URL::new_with_string(&output_url_string);
unsafe { msg_send![self, setOutputURL: output_url] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor?language=objc>
pub fn destination(&self) -> MTLCaptureDestination {
unsafe { msg_send![self, destination] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor?language=objc>
pub fn set_destination(&self, destination: MTLCaptureDestination) {
unsafe { msg_send![self, setDestination: destination] }
}
}

113
vendor/metal/src/capturemanager.rs vendored Normal file
View File

@@ -0,0 +1,113 @@
// Copyright 2018 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use std::ffi::CStr;
/// See <https://developer.apple.com/documentation/metal/mtlcapturescope>
pub enum MTLCaptureScope {}
foreign_obj_type! {
type CType = MTLCaptureScope;
pub struct CaptureScope;
}
impl CaptureScopeRef {
pub fn begin_scope(&self) {
unsafe { msg_send![self, beginScope] }
}
pub fn end_scope(&self) {
unsafe { msg_send![self, endScope] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturemanager>
pub enum MTLCaptureManager {}
foreign_obj_type! {
type CType = MTLCaptureManager;
pub struct CaptureManager;
}
impl CaptureManager {
pub fn shared<'a>() -> &'a CaptureManagerRef {
unsafe {
let class = class!(MTLCaptureManager);
msg_send![class, sharedCaptureManager]
}
}
}
impl CaptureManagerRef {
pub fn new_capture_scope_with_device(&self, device: &DeviceRef) -> CaptureScope {
unsafe { msg_send![self, newCaptureScopeWithDevice: device] }
}
pub fn new_capture_scope_with_command_queue(
&self,
command_queue: &CommandQueueRef,
) -> CaptureScope {
unsafe { msg_send![self, newCaptureScopeWithCommandQueue: command_queue] }
}
pub fn default_capture_scope(&self) -> Option<&CaptureScopeRef> {
unsafe { msg_send![self, defaultCaptureScope] }
}
pub fn set_default_capture_scope(&self, scope: &CaptureScopeRef) {
unsafe { msg_send![self, setDefaultCaptureScope: scope] }
}
/// Starts capturing with the capture session defined by a descriptor object.
///
/// This function will panic if Metal capture is not enabled. Capture can be enabled by
/// either:
/// 1. Running from Xcode
/// 2. Setting the environment variable `METAL_CAPTURE_ENABLED=1`
/// 3. Adding an info.plist file containing the `MetalCaptureEnabled` key set to `YES`
pub fn start_capture(&self, descriptor: &CaptureDescriptorRef) -> Result<(), String> {
unsafe {
Ok(try_objc! { err =>
msg_send![self, startCaptureWithDescriptor: descriptor
error: &mut err]
})
}
}
pub fn start_capture_with_device(&self, device: &DeviceRef) {
unsafe { msg_send![self, startCaptureWithDevice: device] }
}
pub fn start_capture_with_command_queue(&self, command_queue: &CommandQueueRef) {
unsafe { msg_send![self, startCaptureWithCommandQueue: command_queue] }
}
pub fn start_capture_with_scope(&self, scope: &CaptureScopeRef) {
unsafe { msg_send![self, startCaptureWithScope: scope] }
}
pub fn stop_capture(&self) {
unsafe { msg_send![self, stopCapture] }
}
pub fn is_capturing(&self) -> bool {
unsafe { msg_send![self, isCapturing] }
}
/// See <https://developer.apple.com/documentation/metal/mtlcapturemanager/3237260-supportsdestination?language=objc>
pub fn supports_destination(&self, destination: MTLCaptureDestination) -> bool {
unsafe { msg_send![self, supportsDestination: destination] }
}
}

192
vendor/metal/src/commandbuffer.rs vendored Normal file
View File

@@ -0,0 +1,192 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use block::Block;
/// See <https://developer.apple.com/documentation/metal/mtlcommandbufferstatus>
#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCommandBufferStatus {
NotEnqueued = 0,
Enqueued = 1,
Committed = 2,
Scheduled = 3,
Completed = 4,
Error = 5,
}
/// See <https://developer.apple.com/documentation/metal/mtlcommandbuffererror>
#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCommandBufferError {
None = 0,
Internal = 1,
Timeout = 2,
PageFault = 3,
Blacklisted = 4,
NotPermitted = 7,
OutOfMemory = 8,
InvalidResource = 9,
Memoryless = 10,
DeviceRemoved = 11,
}
/// See <https://developer.apple.com/documentation/metal/mtldispatchtype>
#[repr(u32)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLDispatchType {
Serial = 0,
Concurrent = 1,
}
type CommandBufferHandler<'a> = Block<(&'a CommandBufferRef,), ()>;
/// See <https://developer.apple.com/documentation/metal/mtlcommandbuffer>.
pub enum MTLCommandBuffer {}
foreign_obj_type! {
type CType = MTLCommandBuffer;
pub struct CommandBuffer;
}
impl CommandBufferRef {
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn enqueue(&self) {
unsafe { msg_send![self, enqueue] }
}
pub fn commit(&self) {
unsafe { msg_send![self, commit] }
}
pub fn status(&self) -> MTLCommandBufferStatus {
unsafe { msg_send![self, status] }
}
pub fn present_drawable(&self, drawable: &DrawableRef) {
unsafe { msg_send![self, presentDrawable: drawable] }
}
pub fn wait_until_completed(&self) {
unsafe { msg_send![self, waitUntilCompleted] }
}
pub fn wait_until_scheduled(&self) {
unsafe { msg_send![self, waitUntilScheduled] }
}
pub fn add_completed_handler(&self, block: &CommandBufferHandler) {
unsafe { msg_send![self, addCompletedHandler: block] }
}
pub fn add_scheduled_handler(&self, block: &CommandBufferHandler) {
unsafe { msg_send![self, addScheduledHandler: block] }
}
pub fn new_blit_command_encoder(&self) -> &BlitCommandEncoderRef {
unsafe { msg_send![self, blitCommandEncoder] }
}
pub fn blit_command_encoder_with_descriptor(
&self,
descriptor: &BlitPassDescriptorRef,
) -> &BlitCommandEncoderRef {
unsafe { msg_send![self, blitCommandEncoderWithDescriptor: descriptor] }
}
pub fn new_compute_command_encoder(&self) -> &ComputeCommandEncoderRef {
unsafe { msg_send![self, computeCommandEncoder] }
}
pub fn compute_command_encoder_with_dispatch_type(
&self,
ty: MTLDispatchType,
) -> &ComputeCommandEncoderRef {
unsafe { msg_send![self, computeCommandEncoderWithDispatchType: ty] }
}
pub fn compute_command_encoder_with_descriptor(
&self,
descriptor: &ComputePassDescriptorRef,
) -> &ComputeCommandEncoderRef {
unsafe { msg_send![self, computeCommandEncoderWithDescriptor: descriptor] }
}
pub fn new_render_command_encoder(
&self,
descriptor: &RenderPassDescriptorRef,
) -> &RenderCommandEncoderRef {
unsafe { msg_send![self, renderCommandEncoderWithDescriptor: descriptor] }
}
pub fn new_parallel_render_command_encoder(
&self,
descriptor: &RenderPassDescriptorRef,
) -> &ParallelRenderCommandEncoderRef {
unsafe { msg_send![self, parallelRenderCommandEncoderWithDescriptor: descriptor] }
}
pub fn new_acceleration_structure_command_encoder(
&self,
) -> &AccelerationStructureCommandEncoderRef {
unsafe { msg_send![self, accelerationStructureCommandEncoder] }
}
pub fn acceleration_structure_command_encoder_with_descriptor(
&self,
descriptor: &AccelerationStructurePassDescriptorRef,
) -> &AccelerationStructureCommandEncoderRef {
unsafe { msg_send![self, accelerationStructureCommandEncoderWithDescriptor: descriptor] }
}
pub fn encode_signal_event(&self, event: &EventRef, new_value: u64) {
unsafe {
msg_send![self,
encodeSignalEvent: event
value: new_value
]
}
}
pub fn encode_wait_for_event(&self, event: &EventRef, value: u64) {
unsafe {
msg_send![self,
encodeWaitForEvent: event
value: value
]
}
}
pub fn push_debug_group(&self, name: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(name);
msg_send![self, pushDebugGroup: nslabel]
}
}
pub fn pop_debug_group(&self) {
unsafe { msg_send![self, popDebugGroup] }
}
}

44
vendor/metal/src/commandqueue.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
/// See <https://developer.apple.com/documentation/metal/mtlcommandqueue>.
pub enum MTLCommandQueue {}
foreign_obj_type! {
type CType = MTLCommandQueue;
pub struct CommandQueue;
}
impl CommandQueueRef {
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn new_command_buffer(&self) -> &CommandBufferRef {
unsafe { msg_send![self, commandBuffer] }
}
pub fn new_command_buffer_with_unretained_references(&self) -> &CommandBufferRef {
unsafe { msg_send![self, commandBufferWithUnretainedReferences] }
}
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
}

107
vendor/metal/src/computepass.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
use super::*;
/// See <https://developer.apple.com/documentation/metal/mtlcomputepassdescriptor>
pub enum MTLComputePassDescriptor {}
foreign_obj_type! {
type CType = MTLComputePassDescriptor;
pub struct ComputePassDescriptor;
}
impl ComputePassDescriptor {
/// Creates a default compute pass descriptor with no attachments.
pub fn new<'a>() -> &'a ComputePassDescriptorRef {
unsafe { msg_send![class!(MTLComputePassDescriptor), computePassDescriptor] }
}
}
impl ComputePassDescriptorRef {
pub fn sample_buffer_attachments(
&self,
) -> &ComputePassSampleBufferAttachmentDescriptorArrayRef {
unsafe { msg_send![self, sampleBufferAttachments] }
}
pub fn set_dispatch_type(&self, ty: MTLDispatchType) {
unsafe { msg_send![self, setDispatchType: ty] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcomputepasssamplebufferattachmentdescriptorarray>
pub enum MTLComputePassSampleBufferAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLComputePassSampleBufferAttachmentDescriptorArray;
pub struct ComputePassSampleBufferAttachmentDescriptorArray;
}
impl ComputePassSampleBufferAttachmentDescriptorArrayRef {
pub fn object_at(
&self,
index: NSUInteger,
) -> Option<&ComputePassSampleBufferAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&ComputePassSampleBufferAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcomputepasssamplebufferattachmentdescriptor>
pub enum MTLComputePassSampleBufferAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLComputePassSampleBufferAttachmentDescriptor;
pub struct ComputePassSampleBufferAttachmentDescriptor;
}
impl ComputePassSampleBufferAttachmentDescriptor {
pub fn new() -> Self {
let class = class!(MTLComputePassSampleBufferAttachmentDescriptor);
unsafe { msg_send![class, new] }
}
}
impl ComputePassSampleBufferAttachmentDescriptorRef {
pub fn sample_buffer(&self) -> Option<&CounterSampleBufferRef> {
unsafe { msg_send![self, sampleBuffer] }
}
pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) {
unsafe { msg_send![self, setSampleBuffer: sample_buffer] }
}
pub fn start_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, startOfEncoderSampleIndex] }
}
pub fn set_start_of_encoder_sample_index(&self, start_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setStartOfEncoderSampleIndex: start_of_encoder_sample_index
]
}
}
pub fn end_of_encoder_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, endOfEncoderSampleIndex] }
}
pub fn set_end_of_encoder_sample_index(&self, end_of_encoder_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setEndOfEncoderSampleIndex: end_of_encoder_sample_index
]
}
}
}

152
vendor/metal/src/constants.rs vendored Normal file
View File

@@ -0,0 +1,152 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
/// See <https://developer.apple.com/documentation/metal/mtlpixelformat>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum MTLPixelFormat {
Invalid = 0,
A8Unorm = 1,
R8Unorm = 10,
R8Unorm_sRGB = 11,
R8Snorm = 12,
R8Uint = 13,
R8Sint = 14,
R16Unorm = 20,
R16Snorm = 22,
R16Uint = 23,
R16Sint = 24,
R16Float = 25,
RG8Unorm = 30,
RG8Unorm_sRGB = 31,
RG8Snorm = 32,
RG8Uint = 33,
RG8Sint = 34,
B5G6R5Unorm = 40,
A1BGR5Unorm = 41,
ABGR4Unorm = 42,
BGR5A1Unorm = 43,
R32Uint = 53,
R32Sint = 54,
R32Float = 55,
RG16Unorm = 60,
RG16Snorm = 62,
RG16Uint = 63,
RG16Sint = 64,
RG16Float = 65,
RGBA8Unorm = 70,
RGBA8Unorm_sRGB = 71,
RGBA8Snorm = 72,
RGBA8Uint = 73,
RGBA8Sint = 74,
BGRA8Unorm = 80,
BGRA8Unorm_sRGB = 81,
RGB10A2Unorm = 90,
RGB10A2Uint = 91,
RG11B10Float = 92,
RGB9E5Float = 93,
BGR10A2Unorm = 94,
RG32Uint = 103,
RG32Sint = 104,
RG32Float = 105,
RGBA16Unorm = 110,
RGBA16Snorm = 112,
RGBA16Uint = 113,
RGBA16Sint = 114,
RGBA16Float = 115,
RGBA32Uint = 123,
RGBA32Sint = 124,
RGBA32Float = 125,
BC1_RGBA = 130,
BC1_RGBA_sRGB = 131,
BC2_RGBA = 132,
BC2_RGBA_sRGB = 133,
BC3_RGBA = 134,
BC3_RGBA_sRGB = 135,
BC4_RUnorm = 140,
BC4_RSnorm = 141,
BC5_RGUnorm = 142,
BC5_RGSnorm = 143,
BC6H_RGBFloat = 150,
BC6H_RGBUfloat = 151,
BC7_RGBAUnorm = 152,
BC7_RGBAUnorm_sRGB = 153,
PVRTC_RGB_2BPP = 160,
PVRTC_RGB_2BPP_sRGB = 161,
PVRTC_RGB_4BPP = 162,
PVRTC_RGB_4BPP_sRGB = 163,
PVRTC_RGBA_2BPP = 164,
PVRTC_RGBA_2BPP_sRGB = 165,
PVRTC_RGBA_4BPP = 166,
PVRTC_RGBA_4BPP_sRGB = 167,
EAC_R11Unorm = 170,
EAC_R11Snorm = 172,
EAC_RG11Unorm = 174,
EAC_RG11Snorm = 176,
EAC_RGBA8 = 178,
EAC_RGBA8_sRGB = 179,
ETC2_RGB8 = 180,
ETC2_RGB8_sRGB = 181,
ETC2_RGB8A1 = 182,
ETC2_RGB8A1_sRGB = 183,
ASTC_4x4_sRGB = 186,
ASTC_5x4_sRGB = 187,
ASTC_5x5_sRGB = 188,
ASTC_6x5_sRGB = 189,
ASTC_6x6_sRGB = 190,
ASTC_8x5_sRGB = 192,
ASTC_8x6_sRGB = 193,
ASTC_8x8_sRGB = 194,
ASTC_10x5_sRGB = 195,
ASTC_10x6_sRGB = 196,
ASTC_10x8_sRGB = 197,
ASTC_10x10_sRGB = 198,
ASTC_12x10_sRGB = 199,
ASTC_12x12_sRGB = 200,
ASTC_4x4_LDR = 204,
ASTC_5x4_LDR = 205,
ASTC_5x5_LDR = 206,
ASTC_6x5_LDR = 207,
ASTC_6x6_LDR = 208,
ASTC_8x5_LDR = 210,
ASTC_8x6_LDR = 211,
ASTC_8x8_LDR = 212,
ASTC_10x5_LDR = 213,
ASTC_10x6_LDR = 214,
ASTC_10x8_LDR = 215,
ASTC_10x10_LDR = 216,
ASTC_12x10_LDR = 217,
ASTC_12x12_LDR = 218,
ASTC_4x4_HDR = 222,
ASTC_5x4_HDR = 223,
ASTC_5x5_HDR = 224,
ASTC_6x5_HDR = 225,
ASTC_6x6_HDR = 226,
ASTC_8x5_HDR = 228,
ASTC_8x6_HDR = 229,
ASTC_8x8_HDR = 230,
ASTC_10x5_HDR = 231,
ASTC_10x6_HDR = 232,
ASTC_10x8_HDR = 233,
ASTC_10x10_HDR = 234,
ASTC_12x10_HDR = 235,
ASTC_12x12_HDR = 236,
GBGR422 = 240,
BGRG422 = 241,
Depth16Unorm = 250,
Depth32Float = 252,
Stencil8 = 253,
Depth24Unorm_Stencil8 = 255,
Depth32Float_Stencil8 = 260,
X32_Stencil8 = 261,
X24_Stencil8 = 262,
BGRA10_XR = 552,
BGRA10_XR_SRGB = 553,
BGR10_XR = 554,
BGR10_XR_SRGB = 555,
}

119
vendor/metal/src/counters.rs vendored Normal file
View File

@@ -0,0 +1,119 @@
use crate::{MTLStorageMode, NSUInteger};
use std::mem;
/// See <https://developer.apple.com/documentation/metal/mtlcountersamplebufferdescriptor>
pub enum MTLCounterSampleBufferDescriptor {}
foreign_obj_type! {
type CType = MTLCounterSampleBufferDescriptor;
pub struct CounterSampleBufferDescriptor;
}
impl CounterSampleBufferDescriptor {
pub fn new() -> Self {
let class = class!(MTLCounterSampleBufferDescriptor);
unsafe { msg_send![class, new] }
}
}
impl CounterSampleBufferDescriptorRef {
pub fn counter_set(&self) -> &CounterSetRef {
unsafe { msg_send![self, counterSet] }
}
pub fn set_counter_set(&self, counter_set: &CounterSetRef) {
unsafe { msg_send![self, setCounterSet: counter_set] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn sample_count(&self) -> u64 {
unsafe { msg_send![self, sampleCount] }
}
pub fn set_sample_count(&self, sample_count: u64) {
unsafe { msg_send![self, setSampleCount: sample_count] }
}
pub fn storage_mode(&self) -> MTLStorageMode {
unsafe { msg_send![self, storageMode] }
}
pub fn set_storage_mode(&self, storage_mode: MTLStorageMode) {
unsafe { msg_send![self, setStorageMode: storage_mode] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcountersamplebuffer>
pub enum MTLCounterSampleBuffer {}
foreign_obj_type! {
type CType = MTLCounterSampleBuffer;
pub struct CounterSampleBuffer;
}
impl CounterSampleBufferRef {
pub fn sample_count(&self) -> u64 {
unsafe { msg_send![self, sampleCount] }
}
pub fn resolve_counter_range(&self, range: crate::NSRange) -> Vec<NSUInteger> {
let mut data = vec![0 as NSUInteger; range.length as usize];
let total_bytes = range.length * mem::size_of::<NSUInteger>() as u64;
unsafe {
let ns_data: *mut crate::Object = msg_send![self, resolveCounterRange: range];
let () = msg_send![ns_data, getBytes: data.as_mut_ptr() length: total_bytes];
}
data
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcounter>
pub enum MTLCounter {}
foreign_obj_type! {
type CType = MTLCounter;
pub struct Counter;
}
impl CounterRef {}
/// See <https://developer.apple.com/documentation/metal/mtlcounterset>
pub enum MTLCounterSet {}
foreign_obj_type! {
type CType = MTLCounterSet;
pub struct CounterSet;
}
impl CounterSetRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcommoncounterset>
pub enum MTLCommonCounterSet {}
/// See <https://developer.apple.com/documentation/metal/mtlcommoncounter>
pub enum MTLCommonCounter {}
foreign_obj_type! {
type CType = MTLCommonCounter;
pub struct CommonCounter;
}

190
vendor/metal/src/depthstencil.rs vendored Normal file
View File

@@ -0,0 +1,190 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use crate::DeviceRef;
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtlcomparefunction>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLCompareFunction {
Never = 0,
Less = 1,
Equal = 2,
LessEqual = 3,
Greater = 4,
NotEqual = 5,
GreaterEqual = 6,
Always = 7,
}
/// See <https://developer.apple.com/documentation/metal/mtlstenciloperation>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLStencilOperation {
Keep = 0,
Zero = 1,
Replace = 2,
IncrementClamp = 3,
DecrementClamp = 4,
Invert = 5,
IncrementWrap = 6,
DecrementWrap = 7,
}
/// See <https://developer.apple.com/documentation/metal/mtlstencildescriptor>
pub enum MTLStencilDescriptor {}
foreign_obj_type! {
type CType = MTLStencilDescriptor;
pub struct StencilDescriptor;
}
impl StencilDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLStencilDescriptor);
msg_send![class, new]
}
}
}
impl StencilDescriptorRef {
pub fn stencil_compare_function(&self) -> MTLCompareFunction {
unsafe { msg_send![self, stencilCompareFunction] }
}
pub fn set_stencil_compare_function(&self, func: MTLCompareFunction) {
unsafe { msg_send![self, setStencilCompareFunction: func] }
}
pub fn stencil_failure_operation(&self) -> MTLStencilOperation {
unsafe { msg_send![self, stencilFailureOperation] }
}
pub fn set_stencil_failure_operation(&self, operation: MTLStencilOperation) {
unsafe { msg_send![self, setStencilFailureOperation: operation] }
}
pub fn depth_failure_operation(&self) -> MTLStencilOperation {
unsafe { msg_send![self, depthFailureOperation] }
}
pub fn set_depth_failure_operation(&self, operation: MTLStencilOperation) {
unsafe { msg_send![self, setDepthFailureOperation: operation] }
}
pub fn depth_stencil_pass_operation(&self) -> MTLStencilOperation {
unsafe { msg_send![self, depthStencilPassOperation] }
}
pub fn set_depth_stencil_pass_operation(&self, operation: MTLStencilOperation) {
unsafe { msg_send![self, setDepthStencilPassOperation: operation] }
}
pub fn read_mask(&self) -> u32 {
unsafe { msg_send![self, readMask] }
}
pub fn set_read_mask(&self, mask: u32) {
unsafe { msg_send![self, setReadMask: mask] }
}
pub fn write_mask(&self) -> u32 {
unsafe { msg_send![self, writeMask] }
}
pub fn set_write_mask(&self, mask: u32) {
unsafe { msg_send![self, setWriteMask: mask] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtldepthstencildescriptor>
pub enum MTLDepthStencilDescriptor {}
foreign_obj_type! {
type CType = MTLDepthStencilDescriptor;
pub struct DepthStencilDescriptor;
}
impl DepthStencilDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLDepthStencilDescriptor);
msg_send![class, new]
}
}
}
impl DepthStencilDescriptorRef {
pub fn depth_compare_function(&self) -> MTLCompareFunction {
unsafe { msg_send![self, depthCompareFunction] }
}
pub fn set_depth_compare_function(&self, func: MTLCompareFunction) {
unsafe { msg_send![self, setDepthCompareFunction: func] }
}
pub fn depth_write_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isDepthWriteEnabled] }
}
pub fn set_depth_write_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setDepthWriteEnabled: enabled] }
}
pub fn front_face_stencil(&self) -> Option<&StencilDescriptorRef> {
unsafe { msg_send![self, frontFaceStencil] }
}
pub fn set_front_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
unsafe { msg_send![self, setFrontFaceStencil: descriptor] }
}
pub fn back_face_stencil(&self) -> Option<&StencilDescriptorRef> {
unsafe { msg_send![self, backFaceStencil] }
}
pub fn set_back_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) {
unsafe { msg_send![self, setBackFaceStencil: descriptor] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtldepthstencilstate>
pub enum MTLDepthStencilState {}
foreign_obj_type! {
type CType = MTLDepthStencilState;
pub struct DepthStencilState;
}
impl DepthStencilStateRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
}

2134
vendor/metal/src/device.rs vendored Normal file

File diff suppressed because it is too large Load Diff

39
vendor/metal/src/drawable.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use block::Block;
use super::NSUInteger;
type DrawablePresentedHandler<'a> = Block<(&'a DrawableRef,), ()>;
type CFTimeInterval = f64;
/// See <https://developer.apple.com/documentation/metal/mtldrawable>
pub enum MTLDrawable {}
foreign_obj_type! {
type CType = MTLDrawable;
pub struct Drawable;
}
impl DrawableRef {
pub fn present(&self) {
unsafe { msg_send![self, present] }
}
pub fn drawable_id(&self) -> NSUInteger {
unsafe { msg_send![self, drawableID] }
}
pub fn add_presented_handler(&self, block: &DrawablePresentedHandler) {
unsafe { msg_send![self, addPresentedHandler: block] }
}
pub fn presented_time(&self) -> CFTimeInterval {
unsafe { msg_send![self, presentedTime] }
}
}

2041
vendor/metal/src/encoder.rs vendored Normal file

File diff suppressed because it is too large Load Diff

281
vendor/metal/src/heap.rs vendored Normal file
View File

@@ -0,0 +1,281 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
/// Only available on macos(10.15), ios(13.0)
///
/// See <https://developer.apple.com/documentation/metal/mtlheaptype/>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLHeapType {
Automatic = 0,
Placement = 1,
/// Only available on macos(11.0), macCatalyst(14.0)
Sparse = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlheap/>
pub enum MTLHeap {}
foreign_obj_type! {
type CType = MTLHeap;
pub struct Heap;
}
impl HeapRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode {
unsafe { msg_send![self, cpuCacheMode] }
}
pub fn storage_mode(&self) -> MTLStorageMode {
unsafe { msg_send![self, storageMode] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode {
unsafe { msg_send![self, hazardTrackingMode] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn resource_options(&self) -> MTLResourceOptions {
unsafe { msg_send![self, resourceOptions] }
}
pub fn set_purgeable_state(&self, state: MTLPurgeableState) -> MTLPurgeableState {
unsafe { msg_send![self, setPurgeableState: state] }
}
pub fn size(&self) -> NSUInteger {
unsafe { msg_send![self, size] }
}
pub fn used_size(&self) -> NSUInteger {
unsafe { msg_send![self, usedSize] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn heap_type(&self) -> MTLHeapType {
unsafe { msg_send![self, type] }
}
/// Only available on macos(10.13), ios(11.0)
pub fn current_allocated_size(&self) -> NSUInteger {
unsafe { msg_send![self, currentAllocatedSize] }
}
pub fn max_available_size_with_alignment(&self, alignment: NSUInteger) -> NSUInteger {
unsafe { msg_send![self, maxAvailableSizeWithAlignment: alignment] }
}
pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Option<Buffer> {
unsafe {
let ptr: *mut MTLBuffer = msg_send![self, newBufferWithLength:length
options:options];
if !ptr.is_null() {
Some(Buffer::from_ptr(ptr))
} else {
None
}
}
}
pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Option<Texture> {
unsafe {
let ptr: *mut MTLTexture = msg_send![self, newTextureWithDescriptor: descriptor];
if !ptr.is_null() {
Some(Texture::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 10.15+ & iOS 13.0+
pub fn new_buffer_with_offset(
&self,
length: u64,
options: MTLResourceOptions,
offset: u64,
) -> Option<Buffer> {
unsafe {
let ptr: *mut MTLBuffer = msg_send![self, newBufferWithLength:length
options:options
offset:offset];
if !ptr.is_null() {
Some(Buffer::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 10.15+ & iOS 13.0+
pub fn new_texture_with_offset(
&self,
descriptor: &TextureDescriptorRef,
offset: u64,
) -> Option<Texture> {
unsafe {
let ptr: *mut MTLTexture = msg_send![self, newTextureWithDescriptor:descriptor
offset:offset];
if !ptr.is_null() {
Some(Texture::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 13.0+ & iOS 16.0+
pub fn new_acceleration_structure_with_descriptor(
&self,
descriptor: &AccelerationStructureDescriptorRef,
) -> Option<AccelerationStructure> {
unsafe {
let ptr: *mut MTLAccelerationStructure =
msg_send![self, newAccelerationStructureWithDescriptor: descriptor];
if !ptr.is_null() {
Some(AccelerationStructure::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 13.0+ & iOS 16.0+
pub fn new_acceleration_structure_with_descriptor_offset(
&self,
descriptor: &AccelerationStructureDescriptorRef,
offset: u64,
) -> Option<AccelerationStructure> {
unsafe {
let ptr: *mut MTLAccelerationStructure = msg_send![self, newAccelerationStructureWithDescriptor:descriptor
offset:offset];
if !ptr.is_null() {
Some(AccelerationStructure::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 13.0+ & iOS 16.0+
pub fn new_acceleration_structure_with_size(&self, size: u64) -> Option<AccelerationStructure> {
unsafe {
let ptr: *mut MTLAccelerationStructure =
msg_send![self, newAccelerationStructureWithSize:size];
if !ptr.is_null() {
Some(AccelerationStructure::from_ptr(ptr))
} else {
None
}
}
}
/// Only available on macOS 13.0+ & iOS 16.0+
pub fn new_acceleration_structure_with_size_offset(
&self,
size: u64,
offset: u64,
) -> Option<AccelerationStructure> {
unsafe {
let ptr: *mut MTLAccelerationStructure = msg_send![self, newAccelerationStructureWithSize:size
offset:offset];
if !ptr.is_null() {
Some(AccelerationStructure::from_ptr(ptr))
} else {
None
}
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlheapdescriptor/>
pub enum MTLHeapDescriptor {}
foreign_obj_type! {
type CType = MTLHeapDescriptor;
pub struct HeapDescriptor;
}
impl HeapDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLHeapDescriptor);
msg_send![class, new]
}
}
}
impl HeapDescriptorRef {
pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode {
unsafe { msg_send![self, cpuCacheMode] }
}
pub fn set_cpu_cache_mode(&self, mode: MTLCPUCacheMode) {
unsafe { msg_send![self, setCpuCacheMode: mode] }
}
pub fn storage_mode(&self) -> MTLStorageMode {
unsafe { msg_send![self, storageMode] }
}
pub fn set_storage_mode(&self, mode: MTLStorageMode) {
unsafe { msg_send![self, setStorageMode: mode] }
}
pub fn size(&self) -> NSUInteger {
unsafe { msg_send![self, size] }
}
pub fn set_size(&self, size: NSUInteger) {
unsafe { msg_send![self, setSize: size] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode {
unsafe { msg_send![self, hazardTrackingMode] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn set_hazard_tracking_mode(&self, hazard_tracking_mode: MTLHazardTrackingMode) {
unsafe { msg_send![self, setHazardTrackingMode: hazard_tracking_mode] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn resource_options(&self) -> MTLResourceOptions {
unsafe { msg_send![self, resourceOptions] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn heap_type(&self) -> MTLHeapType {
unsafe { msg_send![self, type] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn set_heap_type(&self, type_: MTLHeapType) {
unsafe { msg_send![self, setType: type_] }
}
}

344
vendor/metal/src/indirect_encoder.rs vendored Normal file
View File

@@ -0,0 +1,344 @@
use super::*;
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metal/mtlindirectcommandtype/>
#[allow(non_upper_case_globals)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLIndirectCommandType: NSUInteger {
const Draw = 1 << 0;
const DrawIndexed = 1 << 1;
const DrawPatches = 1 << 2;
const DrawIndexedPatches = 1 << 3;
const ConcurrentDispatch = 1 << 4;
const ConcurrentDispatchThreads = 1 << 5;
}
}
/// See <https://developer.apple.com/documentation/metal/mtlindirectcommandbufferdescriptor/>
pub enum MTLIndirectCommandBufferDescriptor {}
foreign_obj_type! {
type CType = MTLIndirectCommandBufferDescriptor;
pub struct IndirectCommandBufferDescriptor;
}
impl IndirectCommandBufferDescriptor {
pub fn new() -> Self {
let class = class!(MTLIndirectCommandBufferDescriptor);
unsafe { msg_send![class, new] }
}
}
impl IndirectCommandBufferDescriptorRef {
pub fn command_types(&self) -> MTLIndirectCommandType {
unsafe { msg_send![self, commandTypes] }
}
pub fn set_command_types(&self, types: MTLIndirectCommandType) {
unsafe { msg_send![self, setCommandTypes: types] }
}
pub fn inherit_buffers(&self) -> bool {
unsafe { msg_send_bool![self, inheritBuffers] }
}
pub fn set_inherit_buffers(&self, inherit: bool) {
unsafe { msg_send![self, setInheritBuffers: inherit] }
}
pub fn inherit_pipeline_state(&self) -> bool {
unsafe { msg_send_bool![self, inheritPipelineState] }
}
pub fn set_inherit_pipeline_state(&self, inherit: bool) {
unsafe { msg_send![self, setInheritPipelineState: inherit] }
}
pub fn max_vertex_buffer_bind_count(&self) -> NSUInteger {
unsafe { msg_send![self, maxVertexBufferBindCount] }
}
pub fn set_max_vertex_buffer_bind_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxVertexBufferBindCount: count] }
}
pub fn max_fragment_buffer_bind_count(&self) -> NSUInteger {
unsafe { msg_send![self, maxFragmentBufferBindCount] }
}
pub fn set_max_fragment_buffer_bind_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxFragmentBufferBindCount: count] }
}
pub fn max_kernel_buffer_bind_count(&self) -> NSUInteger {
unsafe { msg_send![self, maxKernelBufferBindCount] }
}
pub fn set_max_kernel_buffer_bind_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxKernelBufferBindCount: count] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlindirectcommandbuffer/>
pub enum MTLIndirectCommandBuffer {}
foreign_obj_type! {
type CType = MTLIndirectCommandBuffer;
pub struct IndirectCommandBuffer;
type ParentType = Resource;
}
impl IndirectCommandBufferRef {
pub fn size(&self) -> NSUInteger {
unsafe { msg_send![self, size] }
}
pub fn indirect_render_command_at_index(&self, index: NSUInteger) -> &IndirectRenderCommandRef {
unsafe { msg_send![self, indirectRenderCommandAtIndex: index] }
}
pub fn indirect_compute_command_at_index(
&self,
index: NSUInteger,
) -> &IndirectComputeCommandRef {
unsafe { msg_send![self, indirectComputeCommandAtIndex: index] }
}
pub fn reset_with_range(&self, range: crate::NSRange) {
unsafe { msg_send![self, resetWithRange: range] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlindirectrendercommand/>
pub enum MTLIndirectRenderCommand {}
foreign_obj_type! {
type CType = MTLIndirectRenderCommand;
pub struct IndirectRenderCommand;
}
impl IndirectRenderCommandRef {
pub fn set_render_pipeline_state(&self, pipeline_state: &RenderPipelineStateRef) {
unsafe { msg_send![self, setRenderPipelineState: pipeline_state] }
}
pub fn set_vertex_buffer(
&self,
index: NSUInteger,
buffer: Option<&BufferRef>,
offset: NSUInteger,
) {
unsafe {
msg_send![self,
setVertexBuffer: buffer
offset: offset
atIndex: index
]
}
}
pub fn set_fragment_buffer(
&self,
index: NSUInteger,
buffer: Option<&BufferRef>,
offset: NSUInteger,
) {
unsafe {
msg_send![self,
setFragmentBuffer:buffer
offset:offset
atIndex:index
]
}
}
pub fn draw_primitives(
&self,
primitive_type: MTLPrimitiveType,
vertex_start: NSUInteger,
vertex_count: NSUInteger,
instance_count: NSUInteger,
base_instance: NSUInteger,
) {
unsafe {
msg_send![self,
drawPrimitives: primitive_type
vertexStart: vertex_start
vertexCount: vertex_count
instanceCount: instance_count
baseInstance: base_instance
]
}
}
pub fn draw_indexed_primitives(
&self,
primitive_type: MTLPrimitiveType,
index_count: NSUInteger,
index_type: MTLIndexType,
index_buffer: &BufferRef,
index_buffer_offset: NSUInteger,
instance_count: NSUInteger,
base_vertex: NSUInteger,
base_instance: NSUInteger,
) {
unsafe {
msg_send![self,
drawIndexedPrimitives: primitive_type
indexCount: index_count
indexType: index_type
indexBuffer: index_buffer
indexBufferOffset: index_buffer_offset
instanceCount: instance_count
baseVertex: base_vertex
baseInstance: base_instance
]
}
}
pub fn draw_patches(
&self,
number_of_patch_control_points: NSUInteger,
patch_start: NSUInteger,
patch_count: NSUInteger,
patch_index_buffer: &BufferRef,
patch_index_buffer_offset: NSUInteger,
instance_count: NSUInteger,
base_instance: NSUInteger,
tesselation_factor_buffer: &BufferRef,
tesselation_factor_buffer_offset: NSUInteger,
tesselation_factor_buffer_instance_stride: NSUInteger,
) {
unsafe {
msg_send![self,
drawPatches: number_of_patch_control_points
patchStart: patch_start
patchCount: patch_count
patchIndexBuffer: patch_index_buffer
patchIndexBufferOffset: patch_index_buffer_offset
instanceCount: instance_count
baseInstance: base_instance
tessellationFactorBuffer: tesselation_factor_buffer
tessellationFactorBufferOffset: tesselation_factor_buffer_offset
tessellationFactorBufferInstanceStride: tesselation_factor_buffer_instance_stride
]
}
}
pub fn draw_indexed_patches(
&self,
number_of_patch_control_points: NSUInteger,
patch_start: NSUInteger,
patch_count: NSUInteger,
patch_index_buffer: &BufferRef,
patch_index_buffer_offset: NSUInteger,
control_point_index_buffer: &BufferRef,
control_point_index_buffer_offset: NSUInteger,
instance_count: NSUInteger,
base_instance: NSUInteger,
tesselation_factor_buffer: &BufferRef,
tesselation_factor_buffer_offset: NSUInteger,
tesselation_factor_buffer_instance_stride: NSUInteger,
) {
unsafe {
msg_send![self,
drawIndexedPatches: number_of_patch_control_points
patchStart: patch_start
patchCount: patch_count
patchIndexBuffer: patch_index_buffer
patchIndexBufferOffset: patch_index_buffer_offset
controlPointIndexBuffer: control_point_index_buffer
controlPointIndexBufferOffset: control_point_index_buffer_offset
instanceCount: instance_count
baseInstance: base_instance
tessellationFactorBuffer: tesselation_factor_buffer
tessellationFactorBufferOffset: tesselation_factor_buffer_offset
tessellationFactorBufferInstanceStride: tesselation_factor_buffer_instance_stride
]
}
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlindirectcomputecommand/>
pub enum MTLIndirectComputeCommand {}
foreign_obj_type! {
type CType = MTLIndirectComputeCommand;
pub struct IndirectComputeCommand;
}
impl IndirectComputeCommandRef {
pub fn set_compute_pipeline_state(&self, state: &ComputePipelineStateRef) {
unsafe { msg_send![self, setComputePipelineState: state] }
}
pub fn set_kernel_buffer(
&self,
index: NSUInteger,
buffer: Option<&BufferRef>,
offset: NSUInteger,
) {
unsafe {
msg_send![self,
setKernelBuffer: buffer
offset: offset
atIndex: index
]
}
}
pub fn set_threadgroup_memory_length(&self, index: NSUInteger, length: NSUInteger) {
unsafe {
msg_send![self,
setThreadgroupMemoryLength: length
atIndex: index
]
}
}
pub fn set_stage_in_region(&self, region: MTLRegion) {
unsafe { msg_send![self, setStageInRegion: region] }
}
pub fn set_barrier(&self) {
unsafe { msg_send![self, setBarrier] }
}
pub fn clear_barrier(&self) {
unsafe { msg_send![self, clearBarrier] }
}
pub fn concurrent_dispatch_threadgroups(
&self,
thread_groups_per_grid: MTLSize,
threads_per_threadgroup: MTLSize,
) {
unsafe {
msg_send![self,
concurrentDispatchThreadgroups: thread_groups_per_grid
threadsPerThreadgroup: threads_per_threadgroup
]
}
}
pub fn concurrent_dispatch_threads(
&self,
thread_groups_per_grid: MTLSize,
threads_per_threadgroup: MTLSize,
) {
unsafe {
msg_send![self,
concurrentDispatchThreads: thread_groups_per_grid
threadsPerThreadgroup: threads_per_threadgroup
]
}
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}

657
vendor/metal/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,657 @@
// Copyright 2023 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#![allow(deprecated)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
// Silence clippy warnings as a stopgap to get CI working.
#![allow(clippy::enum_variant_names)]
#![allow(clippy::identity_op)]
#![allow(clippy::let_and_return)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::new_ret_no_self)]
#![allow(clippy::new_without_default)]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::transmute_ptr_to_ref)]
#![allow(clippy::unit_arg)]
#[macro_use]
pub extern crate objc;
#[macro_use]
pub extern crate foreign_types;
#[macro_use]
pub extern crate paste;
use std::{borrow::Borrow, marker::PhantomData, mem, ops::Deref, os::raw::c_void};
use core_graphics_types::{base::CGFloat, geometry::CGSize};
use foreign_types::ForeignType;
use objc::runtime::{Object, NO, YES};
/// See <https://developer.apple.com/documentation/objectivec/nsinteger>
#[cfg(target_pointer_width = "64")]
pub type NSInteger = i64;
/// See <https://developer.apple.com/documentation/objectivec/nsinteger>
#[cfg(not(target_pointer_width = "64"))]
pub type NSInteger = i32;
/// See <https://developer.apple.com/documentation/objectivec/nsuinteger>
#[cfg(target_pointer_width = "64")]
pub type NSUInteger = u64;
/// See <https://developer.apple.com/documentation/objectivec/nsuinteger>
#[cfg(target_pointer_width = "32")]
pub type NSUInteger = u32;
/// See <https://developer.apple.com/documentation/foundation/nsrange>
#[repr(C)]
#[derive(Copy, Clone)]
pub struct NSRange {
pub location: NSUInteger,
pub length: NSUInteger,
}
impl NSRange {
#[inline]
pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange {
NSRange { location, length }
}
}
fn nsstring_as_str(nsstr: &objc::runtime::Object) -> &str {
let bytes = unsafe {
let bytes: *const std::os::raw::c_char = msg_send![nsstr, UTF8String];
bytes as *const u8
};
let len: NSUInteger = unsafe { msg_send![nsstr, length] };
unsafe {
let bytes = std::slice::from_raw_parts(bytes, len as usize);
std::str::from_utf8(bytes).unwrap()
}
}
fn nsstring_from_str(string: &str) -> *mut objc::runtime::Object {
const UTF8_ENCODING: usize = 4;
let cls = class!(NSString);
let bytes = string.as_ptr() as *const c_void;
unsafe {
let obj: *mut objc::runtime::Object = msg_send![cls, alloc];
let obj: *mut objc::runtime::Object = msg_send![
obj,
initWithBytes:bytes
length:string.len()
encoding:UTF8_ENCODING
];
let _: *mut c_void = msg_send![obj, autorelease];
obj
}
}
/// Define a Rust wrapper for an Objective-C opaque type.
///
/// This macro adapts the `foreign-types` crate's [`foreign_type!`]
/// macro to Objective-C, defining Rust types that represent owned and
/// borrowed forms of some underlying Objective-C type, using
/// Objective-C's reference counting to manage its lifetime.
///
/// Given a use of the form:
///
/// ```ignore
/// foreign_obj_type! {
/// type CType = MTLBuffer; // underlying Objective-C type
/// pub struct Buffer; // owned Rust type
/// pub struct BufferRef; // borrowed Rust type
/// type ParentType = ResourceRef; // borrowed parent class
/// }
/// ```
///
/// This defines the types `Buffer` and `BufferRef` as owning and
/// non-owning types, analogous to `String` and `str`, that manage
/// some underlying `*mut MTLBuffer`:
///
/// - Both `Buffer` and `BufferRef` implement [`obj::Message`], indicating
/// that they can be sent Objective-C messages.
///
/// - Dropping a `Buffer` sends the underlying `MTLBuffer` a `release`
/// message, and cloning a `BufferRef` sends a `retain` message and
/// returns a new `Buffer`.
///
/// - `Buffer` dereferences to `BufferRef`.
///
/// - `BufferRef` dereferences to its parent type `ResourceRef`. The
/// `ParentType` component is optional; if omitted, the `Ref` type
/// doesn't implement `Deref` or `DerefMut`.
///
/// - Both `Buffer` and `BufferRef` implement `std::fmt::Debug`,
/// sending an Objective-C `debugDescription` message to the
/// underlying `MTLBuffer`.
///
/// Following the `foreign_types` crate's nomenclature, the `Ref`
/// suffix indicates that `BufferRef` and `ResourceRef` are non-owning
/// types, used *by reference*, like `&BufferRef` or `&ResourceRef`.
/// These types are not, themselves, references.
macro_rules! foreign_obj_type {
{
type CType = $raw_ident:ident;
pub struct $owned_ident:ident;
type ParentType = $parent_ident:ident;
} => {
foreign_obj_type! {
type CType = $raw_ident;
pub struct $owned_ident;
}
impl ::std::ops::Deref for paste!{[<$owned_ident Ref>]} {
type Target = paste!{[<$parent_ident Ref>]};
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { &*(self as *const Self as *const Self::Target) }
}
}
impl ::std::convert::From<$owned_ident> for $parent_ident {
fn from(item: $owned_ident) -> Self {
unsafe { Self::from_ptr(::std::mem::transmute(item.into_ptr())) }
}
}
};
{
type CType = $raw_ident:ident;
pub struct $owned_ident:ident;
} => {
foreign_type! {
pub unsafe type $owned_ident: Sync + Send {
type CType = $raw_ident;
fn drop = crate::obj_drop;
fn clone = crate::obj_clone;
}
}
unsafe impl ::objc::Message for $raw_ident {
}
unsafe impl ::objc::Message for paste!{[<$owned_ident Ref>]} {
}
impl ::std::fmt::Debug for paste!{[<$owned_ident Ref>]} {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
unsafe {
let string: *mut ::objc::runtime::Object = msg_send![self, debugDescription];
write!(f, "{}", crate::nsstring_as_str(&*string))
}
}
}
impl ::std::fmt::Debug for $owned_ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
::std::ops::Deref::deref(self).fmt(f)
}
}
};
}
macro_rules! try_objc {
{
$err_name: ident => $body:expr
} => {
{
let mut $err_name: *mut Object = ::std::ptr::null_mut();
let value = $body;
if !$err_name.is_null() {
let desc: *mut Object = msg_send![$err_name, localizedDescription];
let compile_error: *const std::os::raw::c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
return Err(message);
}
value
}
};
}
macro_rules! msg_send_bool {
($obj:expr, $name:ident) => {{
match msg_send![$obj, $name] {
YES => true,
NO => false,
#[cfg(not(target_arch = "aarch64"))]
_ => unreachable!(),
}
}};
($obj:expr, $name:ident : $arg:expr) => {{
match msg_send![$obj, $name: $arg] {
YES => true,
NO => false,
#[cfg(not(target_arch = "aarch64"))]
_ => unreachable!(),
}
}};
}
macro_rules! msg_send_bool_error_check {
($obj:expr, $name:ident: $arg:expr) => {{
let mut err: *mut Object = ptr::null_mut();
let result: BOOL = msg_send![$obj, $name:$arg
error:&mut err];
if !err.is_null() {
let desc: *mut Object = msg_send![err, localizedDescription];
let c_msg: *const c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(c_msg).to_string_lossy().into_owned();
Err(message)
} else {
match result {
YES => Ok(true),
NO => Ok(false),
#[cfg(not(target_arch = "aarch64"))]
_ => unreachable!(),
}
}
}};
}
/// See <https://developer.apple.com/documentation/foundation/nsarray>
pub struct NSArray<T> {
_phantom: PhantomData<T>,
}
pub struct Array<T>(*mut NSArray<T>)
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static;
pub struct ArrayRef<T>(foreign_types::Opaque, PhantomData<T>)
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static;
impl<T> Drop for Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
fn drop(&mut self) {
unsafe {
let () = msg_send![self.0, release];
}
}
}
impl<T> Clone for Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
fn clone(&self) -> Self {
unsafe { Array(msg_send![self.0, retain]) }
}
}
unsafe impl<T> objc::Message for NSArray<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
}
unsafe impl<T> objc::Message for ArrayRef<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
}
impl<T> Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef<T> {
unsafe {
let class = class!(NSArray);
msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
}
}
pub fn from_owned_slice<'a>(s: &[T]) -> &'a ArrayRef<T> {
unsafe {
let class = class!(NSArray);
msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()]
}
}
}
unsafe impl<T> foreign_types::ForeignType for Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
type CType = NSArray<T>;
type Ref = ArrayRef<T>;
unsafe fn from_ptr(p: *mut NSArray<T>) -> Self {
Array(p)
}
fn as_ptr(&self) -> *mut NSArray<T> {
self.0
}
}
unsafe impl<T> foreign_types::ForeignTypeRef for ArrayRef<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
type CType = NSArray<T>;
}
impl<T> Deref for Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
type Target = ArrayRef<T>;
#[inline]
fn deref(&self) -> &ArrayRef<T> {
unsafe { mem::transmute(self.as_ptr()) }
}
}
impl<T> Borrow<ArrayRef<T>> for Array<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
fn borrow(&self) -> &ArrayRef<T> {
unsafe { mem::transmute(self.as_ptr()) }
}
}
impl<T> ToOwned for ArrayRef<T>
where
T: ForeignType + 'static,
T::Ref: objc::Message + 'static,
{
type Owned = Array<T>;
fn to_owned(&self) -> Array<T> {
unsafe { Array::from_ptr(msg_send![self, retain]) }
}
}
/// See <https://developer.apple.com/documentation/quartzcore/cametaldrawable>
pub enum CAMetalDrawable {}
foreign_obj_type! {
type CType = CAMetalDrawable;
pub struct MetalDrawable;
type ParentType = Drawable;
}
impl MetalDrawableRef {
pub fn texture(&self) -> &TextureRef {
unsafe { msg_send![self, texture] }
}
}
pub enum NSObject {}
foreign_obj_type! {
type CType = NSObject;
pub struct NsObject;
}
impl NsObjectRef {
pub fn conforms_to_protocol<T>(&self) -> Result<bool, String> {
let name = ::std::any::type_name::<T>();
if let Some(name) = name.split("::").last() {
if let Some(protocol) = objc::runtime::Protocol::get(name) {
Ok(unsafe { msg_send![self, conformsToProtocol: protocol] })
} else {
Err(format!("Can not find the protocol for type: {}.", name))
}
} else {
Err(format!("Unexpected type name: {}.", name))
}
}
}
// See <https://developer.apple.com/documentation/quartzcore/cametallayer>
pub enum CAMetalLayer {}
foreign_obj_type! {
type CType = CAMetalLayer;
pub struct MetalLayer;
}
impl MetalLayer {
pub fn new() -> Self {
unsafe {
let class = class!(CAMetalLayer);
msg_send![class, new]
}
}
}
impl MetalLayerRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn set_device(&self, device: &DeviceRef) {
unsafe { msg_send![self, setDevice: device] }
}
pub fn pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, pixelFormat] }
}
pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setPixelFormat: pixel_format] }
}
pub fn drawable_size(&self) -> CGSize {
unsafe { msg_send![self, drawableSize] }
}
pub fn set_drawable_size(&self, size: CGSize) {
unsafe { msg_send![self, setDrawableSize: size] }
}
pub fn presents_with_transaction(&self) -> bool {
unsafe { msg_send_bool![self, presentsWithTransaction] }
}
pub fn set_presents_with_transaction(&self, transaction: bool) {
unsafe { msg_send![self, setPresentsWithTransaction: transaction] }
}
pub fn display_sync_enabled(&self) -> bool {
unsafe { msg_send_bool![self, displaySyncEnabled] }
}
pub fn set_display_sync_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setDisplaySyncEnabled: enabled] }
}
pub fn maximum_drawable_count(&self) -> NSUInteger {
unsafe { msg_send![self, maximumDrawableCount] }
}
pub fn set_maximum_drawable_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaximumDrawableCount: count] }
}
pub fn set_edge_antialiasing_mask(&self, mask: u64) {
unsafe { msg_send![self, setEdgeAntialiasingMask: mask] }
}
pub fn set_masks_to_bounds(&self, masks: bool) {
unsafe { msg_send![self, setMasksToBounds: masks] }
}
pub fn remove_all_animations(&self) {
unsafe { msg_send![self, removeAllAnimations] }
}
pub fn next_drawable(&self) -> Option<&MetalDrawableRef> {
unsafe { msg_send![self, nextDrawable] }
}
pub fn contents_scale(&self) -> CGFloat {
unsafe { msg_send![self, contentsScale] }
}
pub fn set_contents_scale(&self, scale: CGFloat) {
unsafe { msg_send![self, setContentsScale: scale] }
}
/// [framebufferOnly Apple Docs](https://developer.apple.com/documentation/metal/mtltexture/1515749-framebufferonly?language=objc)
pub fn framebuffer_only(&self) -> bool {
unsafe { msg_send_bool!(self, framebufferOnly) }
}
pub fn set_framebuffer_only(&self, framebuffer_only: bool) {
unsafe { msg_send![self, setFramebufferOnly: framebuffer_only] }
}
pub fn is_opaque(&self) -> bool {
unsafe { msg_send_bool!(self, isOpaque) }
}
pub fn set_opaque(&self, opaque: bool) {
unsafe { msg_send![self, setOpaque: opaque] }
}
pub fn wants_extended_dynamic_range_content(&self) -> bool {
unsafe { msg_send_bool![self, wantsExtendedDynamicRangeContent] }
}
pub fn set_wants_extended_dynamic_range_content(
&self,
wants_extended_dynamic_range_content: bool,
) {
unsafe {
msg_send![
self,
setWantsExtendedDynamicRangeContent: wants_extended_dynamic_range_content
]
}
}
}
mod acceleration_structure;
mod acceleration_structure_pass;
mod argument;
mod blitpass;
mod buffer;
mod capturedescriptor;
mod capturemanager;
mod commandbuffer;
mod commandqueue;
mod computepass;
mod constants;
mod counters;
mod depthstencil;
mod device;
mod drawable;
mod encoder;
mod heap;
mod indirect_encoder;
mod library;
#[cfg(feature = "mps")]
pub mod mps;
mod pipeline;
mod renderpass;
mod resource;
mod sampler;
mod sync;
mod texture;
mod types;
mod vertexdescriptor;
#[rustfmt::skip]
pub use {
acceleration_structure::*,
acceleration_structure_pass::*,
argument::*,
blitpass::*,
buffer::*,
counters::*,
computepass::*,
capturedescriptor::*,
capturemanager::*,
commandbuffer::*,
commandqueue::*,
constants::*,
depthstencil::*,
device::*,
drawable::*,
encoder::*,
heap::*,
indirect_encoder::*,
library::*,
pipeline::*,
renderpass::*,
resource::*,
sampler::*,
texture::*,
types::*,
vertexdescriptor::*,
sync::*,
};
#[inline]
unsafe fn obj_drop<T>(p: *mut T) {
msg_send![(p as *mut Object), release]
}
#[inline]
unsafe fn obj_clone<T: 'static>(p: *mut T) -> *mut T {
msg_send![(p as *mut Object), retain]
}
#[allow(non_camel_case_types)]
type c_size_t = usize;
// TODO: expand supported interface
/// See <https://developer.apple.com/documentation/foundation/nsurl>
pub enum NSURL {}
foreign_obj_type! {
type CType = NSURL;
pub struct URL;
}
impl URL {
pub fn new_with_string(string: &str) -> Self {
unsafe {
let ns_str = crate::nsstring_from_str(string);
let class = class!(NSURL);
msg_send![class, URLWithString: ns_str]
}
}
}
impl URLRef {
pub fn absolute_string(&self) -> &str {
unsafe {
let absolute_string = msg_send![self, absoluteString];
crate::nsstring_as_str(absolute_string)
}
}
pub fn path(&self) -> &str {
unsafe {
let path = msg_send![self, path];
crate::nsstring_as_str(path)
}
}
}

902
vendor/metal/src/library.rs vendored Normal file
View File

@@ -0,0 +1,902 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::{BOOL, NO, YES};
use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr;
/// Only available on (macos(10.12), ios(10.0)
///
/// See <https://developer.apple.com/documentation/metal/mtlpatchtype/>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLPatchType {
None = 0,
Triangle = 1,
Quad = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexattribute/>
pub enum MTLVertexAttribute {}
foreign_obj_type! {
type CType = MTLVertexAttribute;
pub struct VertexAttribute;
}
impl VertexAttributeRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn attribute_index(&self) -> u64 {
unsafe { msg_send![self, attributeIndex] }
}
pub fn attribute_type(&self) -> MTLDataType {
unsafe { msg_send![self, attributeType] }
}
pub fn is_active(&self) -> bool {
unsafe { msg_send_bool![self, isActive] }
}
/// Only available on (macos(10.12), ios(10.0)
pub fn is_patch_data(&self) -> bool {
unsafe { msg_send_bool![self, isPatchData] }
}
/// Only available on (macos(10.12), ios(10.0)
pub fn is_patch_control_point_data(&self) -> bool {
unsafe { msg_send_bool![self, isPatchControlPointData] }
}
}
/// Only available on (macos(10.12), ios(10.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlattribute/>
pub enum MTLAttribute {}
foreign_obj_type! {
type CType = MTLAttribute;
pub struct Attribute;
}
impl AttributeRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn attribute_index(&self) -> u64 {
unsafe { msg_send![self, attributeIndex] }
}
pub fn attribute_type(&self) -> MTLDataType {
unsafe { msg_send![self, attributeType] }
}
pub fn is_active(&self) -> bool {
unsafe { msg_send_bool![self, isActive] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn is_patch_data(&self) -> bool {
unsafe { msg_send_bool![self, isPatchData] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn is_patch_control_point_data(&self) -> bool {
unsafe { msg_send_bool![self, isPatchControlPointData] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlfunctiontype/>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLFunctionType {
Vertex = 1,
Fragment = 2,
Kernel = 3,
/// Only available on (macos(11.0), ios(14.0))
Visible = 5,
/// Only available on (macos(11.0), ios(14.0))
Intersection = 6,
}
/// Only available on (macos(10.12), ios(10.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlfunctionconstant/>
pub enum MTLFunctionConstant {}
foreign_obj_type! {
type CType = MTLFunctionConstant;
pub struct FunctionConstant;
}
impl FunctionConstantRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn data_type(&self) -> MTLDataType {
unsafe { msg_send![self, type] }
}
pub fn index(&self) -> NSUInteger {
unsafe { msg_send![self, index] }
}
pub fn required(&self) -> bool {
unsafe { msg_send_bool![self, required] }
}
}
bitflags::bitflags! {
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlfunctionoptions/>
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLFunctionOptions: NSUInteger {
const None = 0;
const CompileToBinary = 1 << 0;
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlfunctiondescriptor/>
pub enum MTLFunctionDescriptor {}
foreign_obj_type! {
type CType = MTLFunctionDescriptor;
pub struct FunctionDescriptor;
}
impl FunctionDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLFunctionDescriptor);
msg_send![class, new]
}
}
}
impl FunctionDescriptorRef {
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn set_name(&self, name: &str) {
unsafe {
let ns_name = crate::nsstring_from_str(name);
let () = msg_send![self, setName: ns_name];
}
}
pub fn specialized_name(&self) -> &str {
unsafe {
let name = msg_send![self, specializedName];
crate::nsstring_as_str(name)
}
}
pub fn set_specialized_name(&self, name: &str) {
unsafe {
let ns_name = crate::nsstring_from_str(name);
let () = msg_send![self, setSpecializedName: ns_name];
}
}
pub fn constant_values(&self) -> &FunctionConstantValuesRef {
unsafe { msg_send![self, constantValues] }
}
pub fn set_constant_values(&self, values: &FunctionConstantValuesRef) {
unsafe { msg_send![self, setConstantValues: values] }
}
pub fn options(&self) -> MTLFunctionOptions {
unsafe { msg_send![self, options] }
}
pub fn set_options(&self, options: MTLFunctionOptions) {
unsafe { msg_send![self, setOptions: options] }
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlintersectionfunctiondescriptor/>
pub enum MTLIntersectionFunctionDescriptor {}
foreign_obj_type! {
type CType = MTLIntersectionFunctionDescriptor;
pub struct IntersectionFunctionDescriptor;
type ParentType = FunctionDescriptor;
}
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtlfunctionhandle/>
pub enum MTLFunctionHandle {}
foreign_obj_type! {
type CType = MTLFunctionHandle;
pub struct FunctionHandle;
}
impl FunctionHandleRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn name(&self) -> &str {
unsafe {
let ns_name = msg_send![self, name];
crate::nsstring_as_str(ns_name)
}
}
pub fn function_type(&self) -> MTLFunctionType {
unsafe { msg_send![self, functionType] }
}
}
// TODO:
// MTLIntersectionFunctionSignature
// MTLIntersectionFunctionTableDescriptor
// MTLIntersectionFunctionTable
/// See <https://developer.apple.com/documentation/metal/mtlfunction/>
pub enum MTLFunction {}
foreign_obj_type! {
type CType = MTLFunction;
pub struct Function;
}
impl FunctionRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn label(&self) -> &str {
unsafe {
let ns_label = msg_send![self, label];
crate::nsstring_as_str(ns_label)
}
}
/// Only available on (macos(10.12), ios(10.0))
pub fn set_label(&self, label: &str) {
unsafe {
let ns_label = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: ns_label];
}
}
pub fn name(&self) -> &str {
unsafe {
let name = msg_send![self, name];
crate::nsstring_as_str(name)
}
}
pub fn function_type(&self) -> MTLFunctionType {
unsafe { msg_send![self, functionType] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn patch_type(&self) -> MTLPatchType {
unsafe { msg_send![self, patchType] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn patch_control_point_count(&self) -> NSUInteger {
unsafe { msg_send![self, patchControlPointCount] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn vertex_attributes(&self) -> &Array<VertexAttribute> {
unsafe { msg_send![self, vertexAttributes] }
}
/// Only available on (macos(10.12), ios(10.0))
pub fn stage_input_attributes(&self) -> &Array<Attribute> {
unsafe { msg_send![self, stageInputAttributes] }
}
pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder {
unsafe {
let ptr = msg_send![self, newArgumentEncoderWithBufferIndex: buffer_index];
ArgumentEncoder::from_ptr(ptr)
}
}
pub fn function_constants_dictionary(&self) -> *mut Object {
unsafe { msg_send![self, functionConstantsDictionary] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn options(&self) -> MTLFunctionOptions {
unsafe { msg_send![self, options] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtllanguageversion/>
#[repr(u64)]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum MTLLanguageVersion {
V1_0 = 0x10000,
V1_1 = 0x10001,
V1_2 = 0x10002,
V2_0 = 0x20000,
V2_1 = 0x20001,
V2_2 = 0x20002,
/// available on macOS 11.0+, iOS 14.0+
V2_3 = 0x20003,
/// available on macOS 12.0+, iOS 15.0+
V2_4 = 0x20004,
/// available on macOS 13.0+, iOS 16.0+
V3_0 = 0x30000,
/// available on macOS 14.0+, iOS 17.0+
V3_1 = 0x30001,
}
/// See <https://developer.apple.com/documentation/metal/mtlfunctionconstantvalues/>
pub enum MTLFunctionConstantValues {}
foreign_obj_type! {
type CType = MTLFunctionConstantValues;
pub struct FunctionConstantValues;
}
impl FunctionConstantValues {
pub fn new() -> Self {
unsafe {
let class = class!(MTLFunctionConstantValues);
msg_send![class, new]
}
}
}
impl FunctionConstantValuesRef {
pub fn set_constant_value_at_index(
&self,
value: *const c_void,
ty: MTLDataType,
index: NSUInteger,
) {
unsafe { msg_send![self, setConstantValue:value type:ty atIndex:index] }
}
pub fn set_constant_values_with_range(
&self,
values: *const c_void,
ty: MTLDataType,
range: NSRange,
) {
unsafe { msg_send![self, setConstantValues:values type:ty withRange:range] }
}
pub fn set_constant_value_with_name(&self, value: *const c_void, ty: MTLDataType, name: &str) {
unsafe {
let ns_name = crate::nsstring_from_str(name);
msg_send![self, setConstantValue:value type:ty withName:ns_name]
}
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtllibrarytype/>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLLibraryType {
Executable = 0,
Dynamic = 1,
}
/// See <https://developer.apple.com/documentation/metal/mtlcompileoptions/>
pub enum MTLCompileOptions {}
foreign_obj_type! {
type CType = MTLCompileOptions;
pub struct CompileOptions;
}
impl CompileOptions {
pub fn new() -> Self {
unsafe {
let class = class!(MTLCompileOptions);
msg_send![class, new]
}
}
}
impl CompileOptionsRef {
pub unsafe fn preprocessor_macros(&self) -> *mut Object {
msg_send![self, preprocessorMacros]
}
pub unsafe fn set_preprocessor_macros(&self, defines: *mut Object) {
msg_send![self, setPreprocessorMacros: defines]
}
pub fn is_fast_math_enabled(&self) -> bool {
unsafe { msg_send_bool![self, fastMathEnabled] }
}
pub fn set_fast_math_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setFastMathEnabled: enabled] }
}
/// Only available on (macos(10.11), ios(9.0))
pub fn language_version(&self) -> MTLLanguageVersion {
unsafe { msg_send![self, languageVersion] }
}
/// Only available on (macos(10.11), ios(9.0))
pub fn set_language_version(&self, version: MTLLanguageVersion) {
unsafe { msg_send![self, setLanguageVersion: version] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn library_type(&self) -> MTLLibraryType {
unsafe { msg_send![self, libraryType] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn set_library_type(&self, lib_type: MTLLibraryType) {
unsafe { msg_send![self, setLibraryType: lib_type] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn install_name(&self) -> &str {
unsafe {
let name = msg_send![self, installName];
crate::nsstring_as_str(name)
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn set_install_name(&self, name: &str) {
unsafe {
let install_name = crate::nsstring_from_str(name);
let () = msg_send![self, setInstallName: install_name];
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// Marshal to Rust Vec
pub fn libraries(&self) -> Vec<DynamicLibrary> {
unsafe {
let libraries: *mut Object = msg_send![self, libraries];
let count: NSUInteger = msg_send![libraries, count];
let ret = (0..count)
.map(|i| {
let lib = msg_send![libraries, objectAtIndex: i];
DynamicLibrary::from_ptr(lib)
})
.collect();
ret
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// As raw NSArray
pub fn libraries_as_nsarray(&self) -> &ArrayRef<DynamicLibrary> {
unsafe { msg_send![self, libraries] }
}
/// Only available on (macos(11.0), ios(14.0))
///
/// Marshal from Rust slice
pub fn set_libraries(&self, libraries: &[&DynamicLibraryRef]) {
let ns_array = Array::<DynamicLibrary>::from_slice(libraries);
unsafe { msg_send![self, setLibraries: ns_array] }
}
/// Only available on (macos(11.0), ios(14.0))
///
/// From raw NSArray
pub fn set_libraries_nsarray(&self, libraries: &ArrayRef<DynamicLibrary>) {
unsafe { msg_send![self, setLibraries: libraries] }
}
/// Only available on (macos(11.0), macCatalyst(14.0), ios(13.0))
pub fn preserve_invariance(&self) -> bool {
unsafe { msg_send_bool![self, preserveInvariance] }
}
/// Only available on (macos(11.0), macCatalyst(14.0), ios(13.0))
pub fn set_preserve_invariance(&self, preserve: bool) {
unsafe { msg_send![self, setPreserveInvariance: preserve] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtllibraryerror/>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLLibraryError {
Unsupported = 1,
Internal = 2,
CompileFailure = 3,
CompileWarning = 4,
/// Only available on (macos(10.12), ios(10.0))
FunctionNotFound = 5,
/// Only available on (macos(10.12), ios(10.0))
FileNotFound = 6,
}
/// See <https://developer.apple.com/documentation/metal/mtllibrary/>
pub enum MTLLibrary {}
foreign_obj_type! {
type CType = MTLLibrary;
pub struct Library;
}
impl LibraryRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
// FIXME: should rename to new_function
pub fn get_function(
&self,
name: &str,
constants: Option<FunctionConstantValues>,
) -> Result<Function, String> {
unsafe {
let nsname = crate::nsstring_from_str(name);
let function: *mut MTLFunction = match constants {
Some(c) => try_objc! { err => msg_send![self,
newFunctionWithName: nsname.as_ref()
constantValues: c.as_ref()
error: &mut err
]},
None => msg_send![self, newFunctionWithName: nsname.as_ref()],
};
if !function.is_null() {
Ok(Function::from_ptr(function))
} else {
Err(format!("Function '{}' does not exist", name))
}
}
}
// TODO: get_function_async with completion handler
pub fn function_names(&self) -> Vec<String> {
unsafe {
let names: *mut Object = msg_send![self, functionNames];
let count: NSUInteger = msg_send![names, count];
let ret = (0..count)
.map(|i| {
let name = msg_send![names, objectAtIndex: i];
nsstring_as_str(name).to_string()
})
.collect();
ret
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn library_type(&self) -> MTLLibraryType {
unsafe { msg_send![self, type] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn install_name(&self) -> Option<&str> {
unsafe {
let maybe_name: *mut Object = msg_send![self, installName];
maybe_name.as_ref().map(crate::nsstring_as_str)
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn new_function_with_descriptor(
&self,
descriptor: &FunctionDescriptorRef,
) -> Result<Function, String> {
unsafe {
let function: *mut MTLFunction = try_objc! {
err => msg_send![self,
newFunctionWithDescriptor: descriptor
error: &mut err
]
};
if !function.is_null() {
Ok(Function::from_ptr(function))
} else {
Err(String::from("new_function_with_descriptor() failed"))
}
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn new_intersection_function_with_descriptor(
&self,
descriptor: &IntersectionFunctionDescriptorRef,
) -> Result<Function, String> {
unsafe {
let function: *mut MTLFunction = try_objc! {
err => msg_send![self,
newIntersectionFunctionWithDescriptor: descriptor
error: &mut err
]
};
if !function.is_null() {
Ok(Function::from_ptr(function))
} else {
Err(String::from(
"new_intersection_function_with_descriptor() failed",
))
}
}
}
}
/// Only available on (macos(11.0), ios(14.0))
///
/// See <https://developer.apple.com/documentation/metal/mtldynamiclibraryerror/>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLDynamicLibraryError {
None = 0,
InvalidFile = 1,
CompilationFailure = 2,
UnresolvedInstallName = 3,
DependencyLoadFailure = 4,
Unsupported = 5,
}
/// See <https://developer.apple.com/documentation/metal/mtldynamiclibrary/>
pub enum MTLDynamicLibrary {}
foreign_obj_type! {
type CType = MTLDynamicLibrary;
pub struct DynamicLibrary;
}
impl DynamicLibraryRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn install_name(&self) -> &str {
unsafe {
let name = msg_send![self, installName];
crate::nsstring_as_str(name)
}
}
pub fn serialize_to_url(&self, url: &URLRef) -> Result<bool, String> {
unsafe { msg_send_bool_error_check![self, serializeToURL: url] }
}
}
/// macOS 11.0+ iOS 14.0+
///
/// See <https://developer.apple.com/documentation/metal/mtlbinaryarchivedescriptor/>
pub enum MTLBinaryArchiveDescriptor {}
foreign_obj_type! {
type CType = MTLBinaryArchiveDescriptor;
pub struct BinaryArchiveDescriptor;
}
impl BinaryArchiveDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLBinaryArchiveDescriptor);
msg_send![class, new]
}
}
}
impl BinaryArchiveDescriptorRef {
pub fn url(&self) -> &URLRef {
unsafe { msg_send![self, url] }
}
pub fn set_url(&self, url: &URLRef) {
unsafe { msg_send![self, setUrl: url] }
}
}
/// macOS 11.0+ iOS 14.0+
///
/// See <https://developer.apple.com/documentation/metal/mtlbinaryarchive/>
pub enum MTLBinaryArchive {}
foreign_obj_type! {
type CType = MTLBinaryArchive;
pub struct BinaryArchive;
}
impl BinaryArchiveRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn add_compute_pipeline_functions_with_descriptor(
&self,
descriptor: &ComputePipelineDescriptorRef,
) -> Result<bool, String> {
unsafe {
msg_send_bool_error_check![self, addComputePipelineFunctionsWithDescriptor: descriptor]
}
}
pub fn add_render_pipeline_functions_with_descriptor(
&self,
descriptor: &RenderPipelineDescriptorRef,
) -> Result<bool, String> {
unsafe {
msg_send_bool_error_check![self, addRenderPipelineFunctionsWithDescriptor: descriptor]
}
}
// TODO: addTileRenderPipelineFunctionsWithDescriptor
// - (BOOL)addTileRenderPipelineFunctionsWithDescriptor:(MTLTileRenderPipelineDescriptor *)descriptor
// error:(NSError * _Nullable *)error;
pub fn serialize_to_url(&self, url: &URLRef) -> Result<bool, String> {
unsafe {
let mut err: *mut Object = ptr::null_mut();
let result: BOOL = msg_send![self, serializeToURL:url
error:&mut err];
if !err.is_null() {
// FIXME: copy pasta
let desc: *mut Object = msg_send![err, localizedDescription];
let c_msg: *const c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(c_msg).to_string_lossy().into_owned();
Err(message)
} else {
match result {
YES => Ok(true),
NO => Ok(false),
#[cfg(not(target_arch = "aarch64"))]
_ => unreachable!(),
}
}
}
}
}
/// macOS 11.0+ iOS 14.0+
///
/// See <https://developer.apple.com/documentation/metal/mtllinkedfunctions/>
pub enum MTLLinkedFunctions {}
foreign_obj_type! {
type CType = MTLLinkedFunctions;
pub struct LinkedFunctions;
}
impl LinkedFunctions {
pub fn new() -> Self {
unsafe {
let class = class!(MTLLinkedFunctions);
msg_send![class, new]
}
}
}
impl LinkedFunctionsRef {
/// Marshal to Rust Vec
pub fn functions(&self) -> Vec<Function> {
unsafe {
let functions: *mut Object = msg_send![self, functions];
let count: NSUInteger = msg_send![functions, count];
let ret = (0..count)
.map(|i| {
let f = msg_send![functions, objectAtIndex: i];
Function::from_ptr(f)
})
.collect();
ret
}
}
/// Marshal from Rust slice
pub fn set_functions(&self, functions: &[&FunctionRef]) {
let ns_array = Array::<Function>::from_slice(functions);
unsafe { msg_send![self, setFunctions: ns_array] }
}
/// Marshal to Rust Vec
pub fn binary_functions(&self) -> Vec<Function> {
unsafe {
let functions: *mut Object = msg_send![self, binaryFunctions];
let count: NSUInteger = msg_send![functions, count];
let ret = (0..count)
.map(|i| {
let f = msg_send![functions, objectAtIndex: i];
Function::from_ptr(f)
})
.collect();
ret
}
}
/// Marshal from Rust slice
pub fn set_binary_functions(&self, functions: &[&FunctionRef]) {
let ns_array = Array::<Function>::from_slice(functions);
unsafe { msg_send![self, setBinaryFunctions: ns_array] }
}
// TODO: figure out NSDictionary wrapper
// TODO: groups
// @property (readwrite, nonatomic, copy, nullable) NSDictionary<NSString*, NSArray<id<MTLFunction>>*> *groups;
}

575
vendor/metal/src/mps.rs vendored Normal file
View File

@@ -0,0 +1,575 @@
// Copyright 2020 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::BOOL;
#[cfg_attr(
feature = "link",
link(name = "MetalPerformanceShaders", kind = "framework")
)]
extern "C" {
fn MPSSupportsMTLDevice(device: *const std::ffi::c_void) -> BOOL;
}
pub fn mps_supports_device(device: &DeviceRef) -> bool {
let b: BOOL = unsafe {
let ptr: *const DeviceRef = device;
MPSSupportsMTLDevice(ptr as _)
};
b == YES
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpskernel>
pub enum MPSKernel {}
foreign_obj_type! {
type CType = MPSKernel;
pub struct Kernel;
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsraydatatype>
pub enum MPSRayDataType {
OriginDirection = 0,
OriginMinDistanceDirectionMaxDistance = 1,
OriginMaskDirectionMaxDistance = 2,
}
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsraymaskoptions>
#[allow(non_upper_case_globals)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MPSRayMaskOptions: NSUInteger {
/// Enable primitive masks
const Primitive = 1;
/// Enable instance masks
const Instance = 2;
}
}
/// Options that determine the data contained in an intersection result.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsintersectiondatatype>
pub enum MPSIntersectionDataType {
Distance = 0,
DistancePrimitiveIndex = 1,
DistancePrimitiveIndexCoordinates = 2,
DistancePrimitiveIndexInstanceIndex = 3,
DistancePrimitiveIndexInstanceIndexCoordinates = 4,
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsintersectiontype>
pub enum MPSIntersectionType {
/// Find the closest intersection to the ray's origin along the ray direction.
/// This is potentially slower than `Any` but is well suited to primary visibility rays.
Nearest = 0,
/// Find any intersection along the ray direction. This is potentially faster than `Nearest` and
/// is well suited to shadow and occlusion rays.
Any = 1,
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsraymaskoperator>
pub enum MPSRayMaskOperator {
/// Accept the intersection if `(primitive mask & ray mask) != 0`.
And = 0,
/// Accept the intersection if `~(primitive mask & ray mask) != 0`.
NotAnd = 1,
/// Accept the intersection if `(primitive mask | ray mask) != 0`.
Or = 2,
/// Accept the intersection if `~(primitive mask | ray mask) != 0`.
NotOr = 3,
/// Accept the intersection if `(primitive mask ^ ray mask) != 0`.
/// Note that this is equivalent to the "!=" operator.
Xor = 4,
/// Accept the intersection if `~(primitive mask ^ ray mask) != 0`.
/// Note that this is equivalent to the "==" operator.
NotXor = 5,
/// Accept the intersection if `(primitive mask < ray mask) != 0`.
LessThan = 6,
/// Accept the intersection if `(primitive mask <= ray mask) != 0`.
LessThanOrEqualTo = 7,
/// Accept the intersection if `(primitive mask > ray mask) != 0`.
GreaterThan = 8,
/// Accept the intersection if `(primitive mask >= ray mask) != 0`.
GreaterThanOrEqualTo = 9,
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpstriangleintersectiontesttype>
pub enum MPSTriangleIntersectionTestType {
/// Use the default ray/triangle intersection test
Default = 0,
/// Use a watertight ray/triangle intersection test which avoids gaps along shared triangle edges.
/// Shared vertices may still have gaps.
/// This intersection test may be slower than `Default`.
Watertight = 1,
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructurestatus>
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MPSAccelerationStructureStatus {
Unbuilt = 0,
Built = 1,
}
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructureusage>
#[allow(non_upper_case_globals)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MPSAccelerationStructureUsage: NSUInteger {
/// No usage options specified
const None = 0;
/// Option that enables support for refitting the acceleration structure after it has been built.
const Refit = 1;
/// Option indicating that the acceleration structure will be rebuilt frequently.
const FrequentRebuild = 2;
const PreferGPUBuild = 4;
const PreferCPUBuild = 8;
}
}
/// A common bit for all floating point data types.
const MPSDataTypeFloatBit: isize = 0x10000000;
const MPSDataTypeSignedBit: isize = 0x20000000;
const MPSDataTypeNormalizedBit: isize = 0x40000000;
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsdatatype>
pub enum MPSDataType {
Invalid = 0,
Float32 = MPSDataTypeFloatBit | 32,
Float16 = MPSDataTypeFloatBit | 16,
// Signed integers.
Int8 = MPSDataTypeSignedBit | 8,
Int16 = MPSDataTypeSignedBit | 16,
Int32 = MPSDataTypeSignedBit | 32,
// Unsigned integers. Range: [0, UTYPE_MAX]
UInt8 = 8,
UInt16 = 16,
UInt32 = 32,
// Unsigned normalized. Range: [0, 1.0]
Unorm1 = MPSDataTypeNormalizedBit | 1,
Unorm8 = MPSDataTypeNormalizedBit | 8,
}
/// A kernel that performs intersection tests between rays and geometry.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsrayintersector>
pub enum MPSRayIntersector {}
foreign_obj_type! {
type CType = MPSRayIntersector;
pub struct RayIntersector;
type ParentType = Kernel;
}
impl RayIntersector {
pub fn from_device(device: &DeviceRef) -> Option<Self> {
unsafe {
let intersector: RayIntersector = msg_send![class!(MPSRayIntersector), alloc];
let ptr: *mut Object = msg_send![intersector.as_ref(), initWithDevice: device];
if ptr.is_null() {
None
} else {
Some(intersector)
}
}
}
}
impl RayIntersectorRef {
pub fn set_cull_mode(&self, mode: MTLCullMode) {
unsafe { msg_send![self, setCullMode: mode] }
}
pub fn set_front_facing_winding(&self, winding: MTLWinding) {
unsafe { msg_send![self, setFrontFacingWinding: winding] }
}
pub fn set_intersection_data_type(&self, options: MPSIntersectionDataType) {
unsafe { msg_send![self, setIntersectionDataType: options] }
}
pub fn set_intersection_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setIntersectionStride: stride] }
}
pub fn set_ray_data_type(&self, ty: MPSRayDataType) {
unsafe { msg_send![self, setRayDataType: ty] }
}
pub fn set_ray_index_data_type(&self, ty: MPSDataType) {
unsafe { msg_send![self, setRayIndexDataType: ty] }
}
pub fn set_ray_mask(&self, ray_mask: u32) {
unsafe { msg_send![self, setRayMask: ray_mask] }
}
pub fn set_ray_mask_operator(&self, operator: MPSRayMaskOperator) {
unsafe { msg_send![self, setRayMaskOperator: operator] }
}
pub fn set_ray_mask_options(&self, options: MPSRayMaskOptions) {
unsafe { msg_send![self, setRayMaskOptions: options] }
}
pub fn set_ray_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setRayStride: stride] }
}
pub fn set_triangle_intersection_test_type(&self, test_type: MPSTriangleIntersectionTestType) {
unsafe { msg_send![self, setTriangleIntersectionTestType: test_type] }
}
pub fn encode_intersection_to_command_buffer(
&self,
command_buffer: &CommandBufferRef,
intersection_type: MPSIntersectionType,
ray_buffer: &BufferRef,
ray_buffer_offset: NSUInteger,
intersection_buffer: &BufferRef,
intersection_buffer_offset: NSUInteger,
ray_count: NSUInteger,
acceleration_structure: &AccelerationStructureRef,
) {
unsafe {
msg_send![
self,
encodeIntersectionToCommandBuffer: command_buffer
intersectionType: intersection_type
rayBuffer: ray_buffer
rayBufferOffset: ray_buffer_offset
intersectionBuffer: intersection_buffer
intersectionBufferOffset: intersection_buffer_offset
rayCount: ray_count
accelerationStructure: acceleration_structure
]
}
}
pub fn recommended_minimum_ray_batch_size_for_ray_count(
&self,
ray_count: NSUInteger,
) -> NSUInteger {
unsafe { msg_send![self, recommendedMinimumRayBatchSizeForRayCount: ray_count] }
}
}
/// A group of acceleration structures which may be used together in an instance acceleration structure.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructuregroup>
pub enum MPSAccelerationStructureGroup {}
foreign_obj_type! {
type CType = MPSAccelerationStructureGroup;
pub struct AccelerationStructureGroup;
}
impl AccelerationStructureGroup {
pub fn new_with_device(device: &DeviceRef) -> Option<Self> {
unsafe {
let group: AccelerationStructureGroup =
msg_send![class!(MPSAccelerationStructureGroup), alloc];
let ptr: *mut Object = msg_send![group.as_ref(), initWithDevice: device];
if ptr.is_null() {
None
} else {
Some(group)
}
}
}
}
impl AccelerationStructureGroupRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
}
/// The base class for data structures that are built over geometry and used to accelerate ray tracing.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructure>
pub enum MPSAccelerationStructure {}
foreign_obj_type! {
type CType = MPSAccelerationStructure;
pub struct AccelerationStructure;
}
impl AccelerationStructureRef {
pub fn status(&self) -> MPSAccelerationStructureStatus {
unsafe { msg_send![self, status] }
}
pub fn usage(&self) -> MPSAccelerationStructureUsage {
unsafe { msg_send![self, usage] }
}
pub fn set_usage(&self, usage: MPSAccelerationStructureUsage) {
unsafe { msg_send![self, setUsage: usage] }
}
pub fn group(&self) -> &AccelerationStructureGroupRef {
unsafe { msg_send![self, group] }
}
pub fn encode_refit_to_command_buffer(&self, buffer: &CommandBufferRef) {
unsafe { msg_send![self, encodeRefitToCommandBuffer: buffer] }
}
pub fn rebuild(&self) {
unsafe { msg_send![self, rebuild] }
}
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpspolygonaccelerationstructure>
pub enum MPSPolygonAccelerationStructure {}
foreign_obj_type! {
type CType = MPSPolygonAccelerationStructure;
pub struct PolygonAccelerationStructure;
type ParentType = AccelerationStructure;
}
impl PolygonAccelerationStructureRef {
pub fn set_index_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setIndexBuffer: buffer] }
}
pub fn set_index_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setIndexBufferOffset: offset] }
}
pub fn set_index_type(&self, data_type: MPSDataType) {
unsafe { msg_send![self, setIndexType: data_type] }
}
pub fn set_mask_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setMaskBuffer: buffer] }
}
pub fn set_mask_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setMaskBufferOffset: offset] }
}
pub fn set_vertex_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setVertexBuffer: buffer] }
}
pub fn set_vertex_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setVertexBufferOffset: offset] }
}
pub fn set_vertex_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setVertexStride: stride] }
}
}
/// An acceleration structure built over triangles.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpstriangleaccelerationstructure>
pub enum MPSTriangleAccelerationStructure {}
foreign_obj_type! {
type CType = MPSTriangleAccelerationStructure;
pub struct TriangleAccelerationStructure;
type ParentType = PolygonAccelerationStructure;
}
impl TriangleAccelerationStructure {
pub fn from_device(device: &DeviceRef) -> Option<Self> {
unsafe {
let structure: TriangleAccelerationStructure =
msg_send![class!(MPSTriangleAccelerationStructure), alloc];
let ptr: *mut Object = msg_send![structure.as_ref(), initWithDevice: device];
if ptr.is_null() {
None
} else {
Some(structure)
}
}
}
}
impl TriangleAccelerationStructureRef {
pub fn triangle_count(&self) -> NSUInteger {
unsafe { msg_send![self, triangleCount] }
}
pub fn set_triangle_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setTriangleCount: count] }
}
}
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpstransformtype>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MPSTransformType {
Float4x4 = 0,
Identity = 1,
}
/// An acceleration structure built over instances of other acceleration structures
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsinstanceaccelerationstructure>
pub enum MPSInstanceAccelerationStructure {}
foreign_obj_type! {
type CType = MPSInstanceAccelerationStructure;
pub struct InstanceAccelerationStructure;
type ParentType = AccelerationStructure;
}
impl InstanceAccelerationStructure {
pub fn init_with_group(group: &AccelerationStructureGroupRef) -> Option<Self> {
unsafe {
let structure: InstanceAccelerationStructure =
msg_send![class!(MPSInstanceAccelerationStructure), alloc];
let ptr: *mut Object = msg_send![structure.as_ref(), initWithGroup: group];
if ptr.is_null() {
None
} else {
Some(structure)
}
}
}
}
impl InstanceAccelerationStructureRef {
/// Marshal to Rust Vec
pub fn acceleration_structures(&self) -> Vec<PolygonAccelerationStructure> {
unsafe {
let acs: *mut Object = msg_send![self, accelerationStructures];
let count: NSUInteger = msg_send![acs, count];
let ret = (0..count)
.map(|i| {
let ac = msg_send![acs, objectAtIndex: i];
PolygonAccelerationStructure::from_ptr(ac)
})
.collect();
ret
}
}
/// Marshal from Rust slice
pub fn set_acceleration_structures(&self, acs: &[&PolygonAccelerationStructureRef]) {
let ns_array = Array::<PolygonAccelerationStructure>::from_slice(acs);
unsafe { msg_send![self, setAccelerationStructures: ns_array] }
}
pub fn instance_buffer(&self) -> &BufferRef {
unsafe { msg_send![self, instanceBuffer] }
}
pub fn set_instance_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setInstanceBuffer: buffer] }
}
pub fn instance_buffer_offset(&self) -> NSUInteger {
unsafe { msg_send![self, instanceBufferOffset] }
}
pub fn set_instance_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setInstanceBufferOffset: offset] }
}
pub fn transform_buffer(&self) -> &BufferRef {
unsafe { msg_send![self, transformBuffer] }
}
pub fn set_transform_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setTransformBuffer: buffer] }
}
pub fn transform_buffer_offset(&self) -> NSUInteger {
unsafe { msg_send![self, transformBufferOffset] }
}
pub fn set_transform_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setTransformBufferOffset: offset] }
}
pub fn transform_type(&self) -> MPSTransformType {
unsafe { msg_send![self, transformType] }
}
pub fn set_transform_type(&self, transform_type: MPSTransformType) {
unsafe { msg_send![self, setTransformType: transform_type] }
}
pub fn mask_buffer(&self) -> &BufferRef {
unsafe { msg_send![self, maskBuffer] }
}
pub fn set_mask_buffer(&self, buffer: &BufferRef) {
unsafe { msg_send![self, setMaskBuffer: buffer] }
}
pub fn mask_buffer_offset(&self) -> NSUInteger {
unsafe { msg_send![self, maskBufferOffset] }
}
pub fn set_mask_buffer_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setMaskBufferOffset: offset] }
}
pub fn instance_count(&self) -> NSUInteger {
unsafe { msg_send![self, instanceCount] }
}
pub fn set_instance_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setInstanceCount: count] }
}
}
#[repr(C)]
pub struct MPSPackedFloat3 {
pub elements: [f32; 3],
}
/// Represents a 3D ray with an origin, a direction, and an intersection distance range from the origin.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsrayoriginmindistancedirectionmaxdistance>
#[repr(C)]
pub struct MPSRayOriginMinDistanceDirectionMaxDistance {
/// Ray origin. The intersection test will be skipped if the origin contains NaNs or infinities.
pub origin: MPSPackedFloat3,
/// Minimum intersection distance from the origin along the ray direction.
/// The intersection test will be skipped if the minimum distance is equal to positive infinity or NaN.
pub min_distance: f32,
/// Ray direction. Does not need to be normalized. The intersection test will be skipped if
/// the direction has length zero or contains NaNs or infinities.
pub direction: MPSPackedFloat3,
/// Maximum intersection distance from the origin along the ray direction. May be infinite.
/// The intersection test will be skipped if the maximum distance is less than zero, NaN, or
/// less than the minimum intersection distance.
pub max_distance: f32,
}
/// Intersection result which contains the distance from the ray origin to the intersection point,
/// the index of the intersected primitive, and the first two barycentric coordinates of the intersection point.
///
/// See <https://developer.apple.com/documentation/metalperformanceshaders/mpsintersectiondistanceprimitiveindexcoordinates>
#[repr(C)]
pub struct MPSIntersectionDistancePrimitiveIndexCoordinates {
/// Distance from the ray origin to the intersection point along the ray direction vector such
/// that `intersection = ray.origin + ray.direction * distance`.
/// Is negative if there is no intersection. If the intersection type is `MPSIntersectionTypeAny`,
/// is a positive value for a hit or a negative value for a miss.
pub distance: f32,
/// Index of the intersected primitive. Undefined if the ray does not intersect a primitive or
/// if the intersection type is `MPSIntersectionTypeAny`.
pub primitive_index: u32,
/// The first two barycentric coordinates `U` and `V` of the intersection point.
/// The third coordinate `W = 1 - U - V`. Undefined if the ray does not intersect a primitive or
/// if the intersection type is `MPSIntersectionTypeAny`.
pub coordinates: [f32; 2],
}

475
vendor/metal/src/pipeline/compute.rs vendored Normal file
View File

@@ -0,0 +1,475 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtlattributeformat>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLAttributeFormat {
Invalid = 0,
UChar2 = 1,
UChar3 = 2,
UChar4 = 3,
Char2 = 4,
Char3 = 5,
Char4 = 6,
UChar2Normalized = 7,
UChar3Normalized = 8,
UChar4Normalized = 9,
Char2Normalized = 10,
Char3Normalized = 11,
Char4Normalized = 12,
UShort2 = 13,
UShort3 = 14,
UShort4 = 15,
Short2 = 16,
Short3 = 17,
Short4 = 18,
UShort2Normalized = 19,
UShort3Normalized = 20,
UShort4Normalized = 21,
Short2Normalized = 22,
Short3Normalized = 23,
Short4Normalized = 24,
Half2 = 25,
Half3 = 26,
Half4 = 27,
Float = 28,
Float2 = 29,
Float3 = 30,
Float4 = 31,
Int = 32,
Int2 = 33,
Int3 = 34,
Int4 = 35,
UInt = 36,
UInt2 = 37,
UInt3 = 38,
UInt4 = 39,
Int1010102Normalized = 40,
UInt1010102Normalized = 41,
UChar4Normalized_BGRA = 42,
UChar = 45,
Char = 46,
UCharNormalized = 47,
CharNormalized = 48,
UShort = 49,
Short = 50,
UShortNormalized = 51,
ShortNormalized = 52,
Half = 53,
}
/// See <https://developer.apple.com/documentation/metal/mtlstepfunction>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLStepFunction {
Constant = 0,
PerInstance = 1,
PerPatch = 2,
PerPatchControlPoint = 3,
PerVertex = 4,
ThreadPositionInGridX = 5,
ThreadPositionInGridXIndexed = 6,
ThreadPositionInGridY = 7,
ThreadPositionInGridYIndexed = 8,
}
/// See <https://developer.apple.com/documentation/metal/mtlcomputepipelinedescriptor>
pub enum MTLComputePipelineDescriptor {}
foreign_obj_type! {
type CType = MTLComputePipelineDescriptor;
pub struct ComputePipelineDescriptor;
}
impl ComputePipelineDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLComputePipelineDescriptor);
msg_send![class, new]
}
}
}
impl ComputePipelineDescriptorRef {
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn compute_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, computeFunction] }
}
pub fn set_compute_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setComputeFunction: function] }
}
pub fn thread_group_size_is_multiple_of_thread_execution_width(&self) -> bool {
unsafe { msg_send_bool![self, threadGroupSizeIsMultipleOfThreadExecutionWidth] }
}
pub fn set_thread_group_size_is_multiple_of_thread_execution_width(
&self,
size_is_multiple_of_width: bool,
) {
unsafe {
msg_send![
self,
setThreadGroupSizeIsMultipleOfThreadExecutionWidth: size_is_multiple_of_width
]
}
}
/// API_AVAILABLE(macos(10.14), ios(12.0));
pub fn max_total_threads_per_threadgroup(&self) -> NSUInteger {
unsafe { msg_send![self, maxTotalThreadsPerThreadgroup] }
}
/// API_AVAILABLE(macos(10.14), ios(12.0));
pub fn set_max_total_threads_per_threadgroup(&self, max_total_threads: NSUInteger) {
unsafe { msg_send![self, setMaxTotalThreadsPerThreadgroup: max_total_threads] }
}
/// API_AVAILABLE(ios(13.0),macos(11.0));
pub fn support_indirect_command_buffers(&self) -> bool {
unsafe { msg_send_bool![self, supportIndirectCommandBuffers] }
}
/// API_AVAILABLE(ios(13.0),macos(11.0));
pub fn set_support_indirect_command_buffers(&self, support: bool) {
unsafe { msg_send![self, setSupportIndirectCommandBuffers: support] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn support_adding_binary_functions(&self) -> bool {
unsafe { msg_send_bool![self, supportAddingBinaryFunctions] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn set_support_adding_binary_functions(&self, support: bool) {
unsafe { msg_send![self, setSupportAddingBinaryFunctions: support] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn max_call_stack_depth(&self) -> NSUInteger {
unsafe { msg_send![self, maxCallStackDepth] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn set_max_call_stack_depth(&self, depth: NSUInteger) {
unsafe { msg_send![self, setMaxCallStackDepth: depth] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
/// Marshal to Rust Vec
pub fn insert_libraries(&self) -> Vec<DynamicLibrary> {
unsafe {
let libraries: *mut Object = msg_send![self, insertLibraries];
let count: NSUInteger = msg_send![libraries, count];
let ret = (0..count)
.map(|i| {
let lib = msg_send![libraries, objectAtIndex: i];
DynamicLibrary::from_ptr(lib)
})
.collect();
ret
}
}
/// Marshal from Rust slice
pub fn set_insert_libraries(&self, libraries: &[&DynamicLibraryRef]) {
let ns_array = Array::<DynamicLibrary>::from_slice(libraries);
unsafe { msg_send![self, setInsertLibraries: ns_array] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
/// Marshal to Rust Vec
pub fn binary_archives(&self) -> Vec<BinaryArchive> {
unsafe {
let archives: *mut Object = msg_send![self, binaryArchives];
let count: NSUInteger = msg_send![archives, count];
let ret = (0..count)
.map(|i| {
let a = msg_send![archives, objectAtIndex: i];
BinaryArchive::from_ptr(a)
})
.collect();
ret
}
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
/// Marshal from Rust slice
pub fn set_binary_archives(&self, archives: &[&BinaryArchiveRef]) {
let ns_array = Array::<BinaryArchive>::from_slice(archives);
unsafe { msg_send![self, setBinaryArchives: ns_array] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn linked_functions(&self) -> &LinkedFunctionsRef {
unsafe { msg_send![self, linkedFunctions] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn set_linked_functions(&self, functions: &LinkedFunctionsRef) {
unsafe { msg_send![self, setLinkedFunctions: functions] }
}
pub fn stage_input_descriptor(&self) -> Option<&StageInputOutputDescriptorRef> {
unsafe { msg_send![self, stageInputDescriptor] }
}
pub fn set_stage_input_descriptor(&self, descriptor: Option<&StageInputOutputDescriptorRef>) {
unsafe { msg_send![self, setStageInputDescriptor: descriptor] }
}
pub fn buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, buffers] }
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcomputepipelinestate>
pub enum MTLComputePipelineState {}
foreign_obj_type! {
type CType = MTLComputePipelineState;
pub struct ComputePipelineState;
}
impl ComputePipelineStateRef {
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn max_total_threads_per_threadgroup(&self) -> NSUInteger {
unsafe { msg_send![self, maxTotalThreadsPerThreadgroup] }
}
pub fn thread_execution_width(&self) -> NSUInteger {
unsafe { msg_send![self, threadExecutionWidth] }
}
pub fn static_threadgroup_memory_length(&self) -> NSUInteger {
unsafe { msg_send![self, staticThreadgroupMemoryLength] }
}
/// Only available on (ios(11.0), macos(11.0), macCatalyst(14.0)) NOT available on (tvos)
pub fn imageblock_memory_length_for_dimensions(&self, dimensions: MTLSize) -> NSUInteger {
unsafe { msg_send![self, imageblockMemoryLengthForDimensions: dimensions] }
}
/// Only available on (ios(13.0), macos(11.0))
pub fn support_indirect_command_buffers(&self) -> bool {
unsafe { msg_send_bool![self, supportIndirectCommandBuffers] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn function_handle_with_function(
&self,
function: &FunctionRef,
) -> Option<&FunctionHandleRef> {
unsafe { msg_send![self, functionHandleWithFunction: function] }
}
// API_AVAILABLE(macos(11.0), ios(14.0));
// TODO: newComputePipelineStateWithAdditionalBinaryFunctions
// - (nullable id <MTLComputePipelineState>)newComputePipelineStateWithAdditionalBinaryFunctions:(nonnull NSArray<id<MTLFunction>> *)functions error:(__autoreleasing NSError **)error
// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn new_visible_function_table_with_descriptor(
&self,
descriptor: &VisibleFunctionTableDescriptorRef,
) -> VisibleFunctionTable {
unsafe { msg_send![self, newVisibleFunctionTableWithDescriptor: descriptor ] }
}
/// Only available on (macos(11.0), ios(14.0))
pub fn new_intersection_function_table_with_descriptor(
&self,
descriptor: &IntersectionFunctionTableDescriptorRef,
) -> IntersectionFunctionTable {
unsafe { msg_send![self, newIntersectionFunctionTableWithDescriptor: descriptor] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlstageinputoutputdescriptor>
pub enum MTLStageInputOutputDescriptor {}
foreign_obj_type! {
type CType = MTLStageInputOutputDescriptor;
pub struct StageInputOutputDescriptor;
}
impl StageInputOutputDescriptor {
pub fn new<'a>() -> &'a StageInputOutputDescriptorRef {
unsafe {
let class = class!(MTLStageInputOutputDescriptor);
msg_send![class, stageInputOutputDescriptor]
}
}
}
impl StageInputOutputDescriptorRef {
pub fn attributes(&self) -> Option<&AttributeDescriptorArrayRef> {
unsafe { msg_send![self, attributes] }
}
pub fn index_buffer_index(&self) -> NSUInteger {
unsafe { msg_send![self, indexBufferIndex] }
}
pub fn set_index_buffer_index(&self, idx_buffer_idx: NSUInteger) {
unsafe { msg_send![self, setIndexBufferIndex: idx_buffer_idx] }
}
pub fn index_type(&self) -> MTLIndexType {
unsafe { msg_send![self, indexType] }
}
pub fn set_index_type(&self, index_ty: MTLIndexType) {
unsafe { msg_send![self, setIndexType: index_ty] }
}
pub fn layouts(&self) -> Option<&BufferLayoutDescriptorArrayRef> {
unsafe { msg_send![self, layouts] }
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlattributedescriptorarray>
pub enum MTLAttributeDescriptorArray {}
foreign_obj_type! {
type CType = MTLAttributeDescriptorArray;
pub struct AttributeDescriptorArray;
}
impl AttributeDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&AttributeDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(&self, index: NSUInteger, buffer_desc: Option<&AttributeDescriptorRef>) {
unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlattributedescriptor>
pub enum MTLAttributeDescriptor {}
foreign_obj_type! {
type CType = MTLAttributeDescriptor;
pub struct AttributeDescriptor;
}
impl AttributeDescriptorRef {
pub fn buffer_index(&self) -> NSUInteger {
unsafe { msg_send![self, bufferIndex] }
}
pub fn set_buffer_index(&self, buffer_index: NSUInteger) {
unsafe { msg_send![self, setBufferIndex: buffer_index] }
}
pub fn format(&self) -> MTLAttributeFormat {
unsafe { msg_send![self, format] }
}
pub fn set_format(&self, format: MTLAttributeFormat) {
unsafe { msg_send![self, setFormat: format] }
}
pub fn offset(&self) -> NSUInteger {
unsafe { msg_send![self, offset] }
}
pub fn set_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setOffset: offset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlbufferlayoutdescriptorarray>
pub enum MTLBufferLayoutDescriptorArray {}
foreign_obj_type! {
type CType = MTLBufferLayoutDescriptorArray;
pub struct BufferLayoutDescriptorArray;
}
impl BufferLayoutDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&BufferLayoutDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
buffer_desc: Option<&BufferLayoutDescriptorRef>,
) {
unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlbufferlayoutdescriptor>
pub enum MTLBufferLayoutDescriptor {}
foreign_obj_type! {
type CType = MTLBufferLayoutDescriptor;
pub struct BufferLayoutDescriptor;
}
impl BufferLayoutDescriptorRef {
pub fn step_function(&self) -> MTLStepFunction {
unsafe { msg_send![self, stepFunction] }
}
pub fn set_step_function(&self, step_function: MTLStepFunction) {
unsafe { msg_send![self, setStepFunction: step_function] }
}
pub fn step_rate(&self) -> NSUInteger {
unsafe { msg_send![self, stepRate] }
}
pub fn set_step_rate(&self, step_rate: NSUInteger) {
unsafe { msg_send![self, setStepRate: step_rate] }
}
pub fn stride(&self) -> NSUInteger {
unsafe { msg_send![self, stride] }
}
pub fn set_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setStride: stride] }
}
}

71
vendor/metal/src/pipeline/mod.rs vendored Normal file
View File

@@ -0,0 +1,71 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
mod compute;
mod render;
pub use self::compute::*;
pub use self::render::*;
/// See <https://developer.apple.com/documentation/metal/mtlmutability>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLMutability {
Default = 0,
Mutable = 1,
Immutable = 2,
}
impl Default for MTLMutability {
#[inline]
fn default() -> Self {
MTLMutability::Default
}
}
/// See <https://developer.apple.com/documentation/metal/mtlpipelinebufferdescriptorarray>
pub enum MTLPipelineBufferDescriptorArray {}
foreign_obj_type! {
type CType = MTLPipelineBufferDescriptorArray;
pub struct PipelineBufferDescriptorArray;
}
impl PipelineBufferDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&PipelineBufferDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
buffer_desc: Option<&PipelineBufferDescriptorRef>,
) {
unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlpipelinebufferdescriptor>
pub enum MTLPipelineBufferDescriptor {}
foreign_obj_type! {
type CType = MTLPipelineBufferDescriptor;
pub struct PipelineBufferDescriptor;
}
impl PipelineBufferDescriptorRef {
pub fn mutability(&self) -> MTLMutability {
unsafe { msg_send![self, mutability] }
}
pub fn set_mutability(&self, new_mutability: MTLMutability) {
unsafe { msg_send![self, setMutability: new_mutability] }
}
}

762
vendor/metal/src/pipeline/render.rs vendored Normal file
View File

@@ -0,0 +1,762 @@
// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtlblendfactor>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLBlendFactor {
Zero = 0,
One = 1,
SourceColor = 2,
OneMinusSourceColor = 3,
SourceAlpha = 4,
OneMinusSourceAlpha = 5,
DestinationColor = 6,
OneMinusDestinationColor = 7,
DestinationAlpha = 8,
OneMinusDestinationAlpha = 9,
SourceAlphaSaturated = 10,
BlendColor = 11,
OneMinusBlendColor = 12,
BlendAlpha = 13,
OneMinusBlendAlpha = 14,
Source1Color = 15,
OneMinusSource1Color = 16,
Source1Alpha = 17,
OneMinusSource1Alpha = 18,
}
/// See <https://developer.apple.com/documentation/metal/mtlblendoperation>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLBlendOperation {
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4,
}
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metal/mtlcolorwritemask>
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLColorWriteMask: NSUInteger {
const None = 0;
const Red = 0x1 << 3;
const Green = 0x1 << 2;
const Blue = 0x1 << 1;
const Alpha = 0x1 << 0;
const All = 0xf;
}
}
/// See <https://developer.apple.com/documentation/metal/mtlprimitivetopologyclass>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLPrimitiveTopologyClass {
Unspecified = 0,
Point = 1,
Line = 2,
Triangle = 3,
}
// TODO: MTLTessellationPartitionMode
// TODO: MTLTessellationFactorStepFunction
// TODO: MTLTessellationFactorFormat
// TODO: MTLTessellationControlPointIndexType
/// See <https://developer.apple.com/documentation/metal/mtlrenderpipelinecolorattachmentdescriptor>
pub enum MTLRenderPipelineColorAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPipelineColorAttachmentDescriptor;
pub struct RenderPipelineColorAttachmentDescriptor;
}
impl RenderPipelineColorAttachmentDescriptorRef {
pub fn pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, pixelFormat] }
}
pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setPixelFormat: pixel_format] }
}
pub fn is_blending_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isBlendingEnabled] }
}
pub fn set_blending_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setBlendingEnabled: enabled] }
}
pub fn source_rgb_blend_factor(&self) -> MTLBlendFactor {
unsafe { msg_send![self, sourceRGBBlendFactor] }
}
pub fn set_source_rgb_blend_factor(&self, blend_factor: MTLBlendFactor) {
unsafe { msg_send![self, setSourceRGBBlendFactor: blend_factor] }
}
pub fn destination_rgb_blend_factor(&self) -> MTLBlendFactor {
unsafe { msg_send![self, destinationRGBBlendFactor] }
}
pub fn set_destination_rgb_blend_factor(&self, blend_factor: MTLBlendFactor) {
unsafe { msg_send![self, setDestinationRGBBlendFactor: blend_factor] }
}
pub fn rgb_blend_operation(&self) -> MTLBlendOperation {
unsafe { msg_send![self, rgbBlendOperation] }
}
pub fn set_rgb_blend_operation(&self, blend_operation: MTLBlendOperation) {
unsafe { msg_send![self, setRgbBlendOperation: blend_operation] }
}
pub fn source_alpha_blend_factor(&self) -> MTLBlendFactor {
unsafe { msg_send![self, sourceAlphaBlendFactor] }
}
pub fn set_source_alpha_blend_factor(&self, blend_factor: MTLBlendFactor) {
unsafe { msg_send![self, setSourceAlphaBlendFactor: blend_factor] }
}
pub fn destination_alpha_blend_factor(&self) -> MTLBlendFactor {
unsafe { msg_send![self, destinationAlphaBlendFactor] }
}
pub fn set_destination_alpha_blend_factor(&self, blend_factor: MTLBlendFactor) {
unsafe { msg_send![self, setDestinationAlphaBlendFactor: blend_factor] }
}
pub fn alpha_blend_operation(&self) -> MTLBlendOperation {
unsafe { msg_send![self, alphaBlendOperation] }
}
pub fn set_alpha_blend_operation(&self, blend_operation: MTLBlendOperation) {
unsafe { msg_send![self, setAlphaBlendOperation: blend_operation] }
}
pub fn write_mask(&self) -> MTLColorWriteMask {
unsafe { msg_send![self, writeMask] }
}
pub fn set_write_mask(&self, mask: MTLColorWriteMask) {
unsafe { msg_send![self, setWriteMask: mask] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpipelinereflection>
pub enum MTLRenderPipelineReflection {}
foreign_obj_type! {
type CType = MTLRenderPipelineReflection;
pub struct RenderPipelineReflection;
}
impl RenderPipelineReflection {
#[cfg(feature = "private")]
pub unsafe fn new(
vertex_data: *mut std::ffi::c_void,
fragment_data: *mut std::ffi::c_void,
vertex_desc: *mut std::ffi::c_void,
device: &DeviceRef,
options: u64,
flags: u64,
) -> Self {
let class = class!(MTLRenderPipelineReflection);
let this: RenderPipelineReflection = msg_send![class, alloc];
let this_alias: *mut Object = msg_send![this.as_ref(), initWithVertexData:vertex_data
fragmentData:fragment_data
serializedVertexDescriptor:vertex_desc
device:device
options:options
flags:flags];
if this_alias.is_null() {
panic!("[MTLRenderPipelineReflection init] failed");
}
this
}
}
impl RenderPipelineReflectionRef {
/// An array of objects that describe the arguments of a fragment function.
pub fn fragment_arguments(&self) -> &ArgumentArrayRef {
unsafe { msg_send![self, fragmentArguments] }
}
/// An array of objects that describe the arguments of a vertex function.
pub fn vertex_arguments(&self) -> &ArgumentArrayRef {
unsafe { msg_send![self, vertexArguments] }
}
/// An array of objects that describe the arguments of a tile shading function.
pub fn tile_arguments(&self) -> &ArgumentArrayRef {
unsafe { msg_send![self, tileArguments] }
}
}
/// TODO: Find documentation link.
pub enum MTLArgumentArray {}
foreign_obj_type! {
type CType = MTLArgumentArray;
pub struct ArgumentArray;
}
impl ArgumentArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&ArgumentRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn count(&self) -> NSUInteger {
unsafe { msg_send![self, count] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlcomputepipelinereflection>
pub enum MTLComputePipelineReflection {}
foreign_obj_type! {
type CType = MTLComputePipelineReflection;
pub struct ComputePipelineReflection;
}
impl ComputePipelineReflectionRef {
/// An array of objects that describe the arguments of a compute function.
pub fn arguments(&self) -> &ArgumentArrayRef {
unsafe { msg_send![self, arguments] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlmeshrenderpipelinedescriptor>
/// Only available in (macos(13.0), ios(16.0))
pub enum MTLMeshRenderPipelineDescriptor {}
foreign_obj_type! {
type CType = MTLMeshRenderPipelineDescriptor;
pub struct MeshRenderPipelineDescriptor;
}
impl MeshRenderPipelineDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLMeshRenderPipelineDescriptor);
msg_send![class, new]
}
}
}
impl MeshRenderPipelineDescriptorRef {
pub fn color_attachments(&self) -> &RenderPipelineColorAttachmentDescriptorArrayRef {
unsafe { msg_send![self, colorAttachments] }
}
pub fn depth_attachment_pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, depthAttachmentPixelFormat] }
}
pub fn set_depth_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setDepthAttachmentPixelFormat: pixel_format] }
}
pub fn fragment_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, fragmentBuffers] }
}
pub fn fragment_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, fragmentFunction] }
}
pub fn set_fragment_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setFragmentFunction: function] }
}
pub fn is_alpha_to_coverage_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isAlphaToCoverageEnabled] }
}
pub fn set_alpha_to_coverage_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setAlphaToCoverageEnabled: enabled] }
}
pub fn is_alpha_to_one_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isAlphaToOneEnabled] }
}
pub fn set_alpha_to_one_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setAlphaToOneEnabled: enabled] }
}
pub fn is_rasterization_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isRasterizationEnabled] }
}
pub fn set_rasterization_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setRasterizationEnabled: enabled] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn max_total_threadgroups_per_mesh_grid(&self) -> NSUInteger {
unsafe { msg_send![self, maxTotalThreadgroupsPerMeshGrid] }
}
pub fn set_max_total_threadgroups_per_mesh_grid(
&self,
max_total_threadgroups_per_mesh_grid: NSUInteger,
) {
unsafe {
msg_send![
self,
setMaxTotalThreadgroupsPerMeshGrid: max_total_threadgroups_per_mesh_grid
]
}
}
pub fn max_total_threads_per_mesh_threadgroup(&self) -> NSUInteger {
unsafe { msg_send![self, maxTotalThreadsPerMeshThreadgroup] }
}
pub fn set_max_total_threads_per_mesh_threadgroup(
&self,
max_total_threads_per_mesh_threadgroup: NSUInteger,
) {
unsafe {
msg_send![
self,
setMaxTotalThreadsPerMeshThreadgroup: max_total_threads_per_mesh_threadgroup
]
}
}
pub fn max_total_threads_per_object_threadgroup(&self) -> NSUInteger {
unsafe { msg_send![self, maxTotalThreadsPerObjectThreadgroup] }
}
pub fn set_max_total_threads_per_object_threadgroup(
&self,
max_total_threads_per_object_threadgroup: NSUInteger,
) {
unsafe {
msg_send![
self,
setMaxTotalThreadsPerObjectThreadgroup: max_total_threads_per_object_threadgroup
]
}
}
pub fn max_vertex_amplification_count(&self) -> NSUInteger {
unsafe { msg_send![self, maxVertexAmplificationCount] }
}
pub fn set_max_vertex_amplification_count(&self, max_vertex_amplification_count: NSUInteger) {
unsafe {
msg_send![
self,
setMaxVertexAmplificationCount: max_vertex_amplification_count
]
}
}
pub fn mesh_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, meshBuffers] }
}
pub fn mesh_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, meshFunction] }
}
pub fn set_mesh_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setMeshFunction: function] }
}
pub fn mesh_threadgroup_size_is_multiple_of_thread_execution_width(&self) -> bool {
unsafe { msg_send_bool![self, isMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth] }
}
pub fn set_mesh_threadgroup_size_is_multiple_of_thread_execution_width(
&self,
mesh_threadgroup_size_is_multiple_of_thread_execution_width: bool,
) {
unsafe {
msg_send![
self,
setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth:
mesh_threadgroup_size_is_multiple_of_thread_execution_width
]
}
}
pub fn object_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, objectBuffers] }
}
pub fn object_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, objectFunction] }
}
pub fn set_object_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setObjectFunction: function] }
}
pub fn object_threadgroup_size_is_multiple_of_thread_execution_width(&self) -> bool {
unsafe {
msg_send_bool![
self,
isObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth
]
}
}
pub fn set_object_threadgroup_size_is_multiple_of_thread_execution_width(
&self,
object_threadgroup_size_is_multiple_of_thread_execution_width: bool,
) {
unsafe {
msg_send![
self,
setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth:
object_threadgroup_size_is_multiple_of_thread_execution_width
]
}
}
pub fn payload_memory_length(&self) -> NSUInteger {
unsafe { msg_send![self, payloadMemoryLength] }
}
pub fn set_payload_memory_length(&self, payload_memory_length: NSUInteger) {
unsafe { msg_send![self, setPayloadMemoryLength: payload_memory_length] }
}
pub fn raster_sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, rasterSampleCount] }
}
pub fn set_raster_sample_count(&self, raster_sample_count: NSUInteger) {
unsafe { msg_send![self, setRasterSampleCount: raster_sample_count] }
}
pub fn stencil_attachment_pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, stencilAttachmentPixelFormat] }
}
pub fn set_stencil_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setStencilAttachmentPixelFormat: pixel_format] }
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpipelinedescriptor>
pub enum MTLRenderPipelineDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPipelineDescriptor;
pub struct RenderPipelineDescriptor;
}
impl RenderPipelineDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLRenderPipelineDescriptor);
msg_send![class, new]
}
}
}
impl RenderPipelineDescriptorRef {
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn vertex_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, vertexFunction] }
}
pub fn set_vertex_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setVertexFunction: function] }
}
pub fn fragment_function(&self) -> Option<&FunctionRef> {
unsafe { msg_send![self, fragmentFunction] }
}
pub fn set_fragment_function(&self, function: Option<&FunctionRef>) {
unsafe { msg_send![self, setFragmentFunction: function] }
}
pub fn vertex_descriptor(&self) -> Option<&VertexDescriptorRef> {
unsafe { msg_send![self, vertexDescriptor] }
}
pub fn set_vertex_descriptor(&self, descriptor: Option<&VertexDescriptorRef>) {
unsafe { msg_send![self, setVertexDescriptor: descriptor] }
}
/// DEPRECATED - aliases rasterSampleCount property
pub fn sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, sampleCount] }
}
/// DEPRECATED - aliases rasterSampleCount property
pub fn set_sample_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setSampleCount: count] }
}
pub fn raster_sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, rasterSampleCount] }
}
pub fn set_raster_sample_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setRasterSampleCount: count] }
}
pub fn max_vertex_amplification_count(&self) -> NSUInteger {
unsafe { msg_send![self, maxVertexAmplificationCount] }
}
pub fn set_max_vertex_amplification_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMaxVertexAmplificationCount: count] }
}
pub fn is_alpha_to_coverage_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isAlphaToCoverageEnabled] }
}
pub fn set_alpha_to_coverage_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setAlphaToCoverageEnabled: enabled] }
}
pub fn is_alpha_to_one_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isAlphaToOneEnabled] }
}
pub fn set_alpha_to_one_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setAlphaToOneEnabled: enabled] }
}
pub fn is_rasterization_enabled(&self) -> bool {
unsafe { msg_send_bool![self, isRasterizationEnabled] }
}
pub fn set_rasterization_enabled(&self, enabled: bool) {
unsafe { msg_send![self, setRasterizationEnabled: enabled] }
}
pub fn color_attachments(&self) -> &RenderPipelineColorAttachmentDescriptorArrayRef {
unsafe { msg_send![self, colorAttachments] }
}
pub fn depth_attachment_pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, depthAttachmentPixelFormat] }
}
pub fn set_depth_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setDepthAttachmentPixelFormat: pixel_format] }
}
pub fn stencil_attachment_pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, stencilAttachmentPixelFormat] }
}
pub fn set_stencil_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setStencilAttachmentPixelFormat: pixel_format] }
}
pub fn input_primitive_topology(&self) -> MTLPrimitiveTopologyClass {
unsafe { msg_send![self, inputPrimitiveTopology] }
}
pub fn set_input_primitive_topology(&self, topology: MTLPrimitiveTopologyClass) {
unsafe { msg_send![self, setInputPrimitiveTopology: topology] }
}
#[cfg(feature = "private")]
pub unsafe fn serialize_vertex_data(&self) -> *mut std::ffi::c_void {
use std::ptr;
let flags = 0;
let err: *mut Object = ptr::null_mut();
msg_send![self, newSerializedVertexDataWithFlags:flags
error:err]
}
#[cfg(feature = "private")]
pub unsafe fn serialize_fragment_data(&self) -> *mut std::ffi::c_void {
msg_send![self, serializeFragmentData]
}
pub fn support_indirect_command_buffers(&self) -> bool {
unsafe { msg_send_bool![self, supportIndirectCommandBuffers] }
}
pub fn set_support_indirect_command_buffers(&self, support: bool) {
unsafe { msg_send![self, setSupportIndirectCommandBuffers: support] }
}
pub fn vertex_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, vertexBuffers] }
}
pub fn fragment_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> {
unsafe { msg_send![self, fragmentBuffers] }
}
// TODO: tesselation stuff
/// API_AVAILABLE(macos(11.0), ios(14.0));
/// Marshal to Rust Vec
pub fn binary_archives(&self) -> Vec<BinaryArchive> {
unsafe {
let archives: *mut Object = msg_send![self, binaryArchives];
let count: NSUInteger = msg_send![archives, count];
let ret = (0..count)
.map(|i| {
let a = msg_send![archives, objectAtIndex: i];
BinaryArchive::from_ptr(a)
})
.collect();
ret
}
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
/// Marshal from Rust slice
pub fn set_binary_archives(&self, archives: &[&BinaryArchiveRef]) {
let ns_array = Array::<BinaryArchive>::from_slice(archives);
unsafe { msg_send![self, setBinaryArchives: ns_array] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn fragment_linked_functions(&self) -> &LinkedFunctionsRef {
unsafe { msg_send![self, fragmentLinkedFunctions] }
}
/// API_AVAILABLE(macos(11.0), ios(14.0));
pub fn set_fragment_linked_functions(&self, functions: &LinkedFunctionsRef) {
unsafe { msg_send![self, setFragmentLinkedFunctions: functions] }
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpipelinestate>
pub enum MTLRenderPipelineState {}
foreign_obj_type! {
type CType = MTLRenderPipelineState;
pub struct RenderPipelineState;
}
impl RenderPipelineStateRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn new_intersection_function_table_with_descriptor(
&self,
descriptor: &IntersectionFunctionTableDescriptorRef,
stage: MTLRenderStages,
) -> IntersectionFunctionTable {
unsafe {
msg_send![self, newIntersectionFunctionTableWithDescriptor: descriptor
stage:stage]
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn function_handle_with_function(
&self,
function: &FunctionRef,
stage: MTLRenderStages,
) -> Option<&FunctionHandleRef> {
unsafe {
msg_send![self, functionHandleWithFunction: function
stage:stage]
}
}
/// Only available on (macos(11.0), ios(14.0))
pub fn new_visible_function_table_with_descriptor(
&self,
descriptor: &VisibleFunctionTableDescriptorRef,
stage: MTLRenderStages,
) -> VisibleFunctionTable {
unsafe { msg_send![self, newVisibleFunctionTableWithDescriptor: descriptor stage:stage] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpipelinecolorattachmentdescriptorarray>
pub enum MTLRenderPipelineColorAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLRenderPipelineColorAttachmentDescriptorArray;
pub struct RenderPipelineColorAttachmentDescriptorArray;
}
impl RenderPipelineColorAttachmentDescriptorArrayRef {
pub fn object_at(
&self,
index: NSUInteger,
) -> Option<&RenderPipelineColorAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&RenderPipelineColorAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}

443
vendor/metal/src/renderpass.rs vendored Normal file
View File

@@ -0,0 +1,443 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
/// See <https://developer.apple.com/documentation/metal/mtlloadaction>
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLLoadAction {
DontCare = 0,
Load = 1,
Clear = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlstoreaction>
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLStoreAction {
DontCare = 0,
Store = 1,
MultisampleResolve = 2,
StoreAndMultisampleResolve = 3,
Unknown = 4,
CustomSampleDepthStore = 5,
}
/// See <https://developer.apple.com/documentation/metal/mtlclearcolor>
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MTLClearColor {
pub red: f64,
pub green: f64,
pub blue: f64,
pub alpha: f64,
}
impl MTLClearColor {
#[inline]
pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
Self {
red,
green,
blue,
alpha,
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlmultisamplestencilresolvefilter>
#[repr(u32)]
#[allow(non_camel_case_types)]
pub enum MTLMultisampleStencilResolveFilter {
Sample0 = 0,
DepthResolvedSample = 1,
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpassattachmentdescriptor>
pub enum MTLRenderPassAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassAttachmentDescriptor;
pub struct RenderPassAttachmentDescriptor;
}
impl RenderPassAttachmentDescriptorRef {
pub fn texture(&self) -> Option<&TextureRef> {
unsafe { msg_send![self, texture] }
}
pub fn set_texture(&self, texture: Option<&TextureRef>) {
unsafe { msg_send![self, setTexture: texture] }
}
pub fn level(&self) -> NSUInteger {
unsafe { msg_send![self, level] }
}
pub fn set_level(&self, level: NSUInteger) {
unsafe { msg_send![self, setLevel: level] }
}
pub fn slice(&self) -> NSUInteger {
unsafe { msg_send![self, slice] }
}
pub fn set_slice(&self, slice: NSUInteger) {
unsafe { msg_send![self, setSlice: slice] }
}
pub fn depth_plane(&self) -> NSUInteger {
unsafe { msg_send![self, depthPlane] }
}
pub fn set_depth_plane(&self, depth_plane: NSUInteger) {
unsafe { msg_send![self, setDepthPlane: depth_plane] }
}
pub fn resolve_texture(&self) -> Option<&TextureRef> {
unsafe { msg_send![self, resolveTexture] }
}
pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) {
unsafe { msg_send![self, setResolveTexture: resolve_texture] }
}
pub fn resolve_level(&self) -> NSUInteger {
unsafe { msg_send![self, resolveLevel] }
}
pub fn set_resolve_level(&self, resolve_level: NSUInteger) {
unsafe { msg_send![self, setResolveLevel: resolve_level] }
}
pub fn resolve_slice(&self) -> NSUInteger {
unsafe { msg_send![self, resolveSlice] }
}
pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) {
unsafe { msg_send![self, setResolveSlice: resolve_slice] }
}
pub fn resolve_depth_plane(&self) -> NSUInteger {
unsafe { msg_send![self, resolveDepthPlane] }
}
pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) {
unsafe { msg_send![self, setResolveDepthPlane: resolve_depth_plane] }
}
pub fn load_action(&self) -> MTLLoadAction {
unsafe { msg_send![self, loadAction] }
}
pub fn set_load_action(&self, load_action: MTLLoadAction) {
unsafe { msg_send![self, setLoadAction: load_action] }
}
pub fn store_action(&self) -> MTLStoreAction {
unsafe { msg_send![self, storeAction] }
}
pub fn set_store_action(&self, store_action: MTLStoreAction) {
unsafe { msg_send![self, setStoreAction: store_action] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpasscolorattachmentdescriptor>
pub enum MTLRenderPassColorAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassColorAttachmentDescriptor;
pub struct RenderPassColorAttachmentDescriptor;
type ParentType = RenderPassAttachmentDescriptor;
}
impl RenderPassColorAttachmentDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLRenderPassColorAttachmentDescriptor);
msg_send![class, new]
}
}
}
impl RenderPassColorAttachmentDescriptorRef {
pub fn clear_color(&self) -> MTLClearColor {
unsafe { msg_send![self, clearColor] }
}
pub fn set_clear_color(&self, clear_color: MTLClearColor) {
unsafe { msg_send![self, setClearColor: clear_color] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpassdepthattachmentdescriptor>
pub enum MTLRenderPassDepthAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassDepthAttachmentDescriptor;
pub struct RenderPassDepthAttachmentDescriptor;
type ParentType = RenderPassAttachmentDescriptor;
}
impl RenderPassDepthAttachmentDescriptorRef {
pub fn clear_depth(&self) -> f64 {
unsafe { msg_send![self, clearDepth] }
}
pub fn set_clear_depth(&self, clear_depth: f64) {
unsafe { msg_send![self, setClearDepth: clear_depth] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpassstencilattachmentdescriptor>
pub enum MTLRenderPassStencilAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassStencilAttachmentDescriptor;
pub struct RenderPassStencilAttachmentDescriptor;
type ParentType = RenderPassAttachmentDescriptor;
}
impl RenderPassStencilAttachmentDescriptorRef {
pub fn clear_stencil(&self) -> u32 {
unsafe { msg_send![self, clearStencil] }
}
pub fn set_clear_stencil(&self, clear_stencil: u32) {
unsafe { msg_send![self, setClearStencil: clear_stencil] }
}
pub fn stencil_resolve_filter(&self) -> MTLMultisampleStencilResolveFilter {
unsafe { msg_send![self, stencilResolveFilter] }
}
pub fn set_stencil_resolve_filter(
&self,
stencil_resolve_filter: MTLMultisampleStencilResolveFilter,
) {
unsafe { msg_send![self, setStencilResolveFilter: stencil_resolve_filter] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpasscolorattachmentdescriptorarray>
pub enum MTLRenderPassColorAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLRenderPassColorAttachmentDescriptorArray;
pub struct RenderPassColorAttachmentDescriptorArray;
}
impl RenderPassColorAttachmentDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&RenderPassColorAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&RenderPassColorAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpasssamplebufferattachmentdescriptor>
pub enum MTLRenderPassSampleBufferAttachmentDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassSampleBufferAttachmentDescriptor;
pub struct RenderPassSampleBufferAttachmentDescriptor;
}
impl RenderPassSampleBufferAttachmentDescriptor {
pub fn new() -> Self {
let class = class!(MTLRenderPassSampleBufferAttachmentDescriptor);
unsafe { msg_send![class, new] }
}
}
impl RenderPassSampleBufferAttachmentDescriptorRef {
pub fn sample_buffer(&self) -> Option<&CounterSampleBufferRef> {
unsafe { msg_send![self, sampleBuffer] }
}
pub fn set_sample_buffer(&self, sample_buffer: &CounterSampleBufferRef) {
unsafe { msg_send![self, setSampleBuffer: sample_buffer] }
}
pub fn start_of_vertex_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, startOfVertexSampleIndex] }
}
pub fn set_start_of_vertex_sample_index(&self, start_of_vertex_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setStartOfVertexSampleIndex: start_of_vertex_sample_index
]
}
}
pub fn end_of_vertex_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, endOfVertexSampleIndex] }
}
pub fn set_end_of_vertex_sample_index(&self, end_of_vertex_sample_index: NSUInteger) {
unsafe { msg_send![self, setEndOfVertexSampleIndex: end_of_vertex_sample_index] }
}
pub fn start_of_fragment_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, startOfFragmentSampleIndex] }
}
pub fn set_start_of_fragment_sample_index(&self, start_of_fragment_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setStartOfFragmentSampleIndex: start_of_fragment_sample_index
]
}
}
pub fn end_of_fragment_sample_index(&self) -> NSUInteger {
unsafe { msg_send![self, endOfFragmentSampleIndex] }
}
pub fn set_end_of_fragment_sample_index(&self, end_of_fragment_sample_index: NSUInteger) {
unsafe {
msg_send![
self,
setEndOfFragmentSampleIndex: end_of_fragment_sample_index
]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlrenderpasssamplebufferattachmentdescriptorarray>
pub enum MTLRenderPassSampleBufferAttachmentDescriptorArray {}
foreign_obj_type! {
type CType = MTLRenderPassSampleBufferAttachmentDescriptorArray;
pub struct RenderPassSampleBufferAttachmentDescriptorArray;
}
impl RenderPassSampleBufferAttachmentDescriptorArrayRef {
pub fn object_at(
&self,
index: NSUInteger,
) -> Option<&RenderPassSampleBufferAttachmentDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attachment: Option<&RenderPassSampleBufferAttachmentDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attachment
atIndexedSubscript:index]
}
}
}
/// ## Important!
/// When configuring a [`MTLTextureDescriptor`] object for use with an attachment, set its usage
/// value to renderTarget if you already know that you intend to use the resulting MTLTexture object in
/// an attachment. This may significantly improve your apps performance with certain hardware.
///
/// See <https://developer.apple.com/documentation/metal/mtlrenderpassdescriptor>
pub enum MTLRenderPassDescriptor {}
foreign_obj_type! {
type CType = MTLRenderPassDescriptor;
pub struct RenderPassDescriptor;
}
impl RenderPassDescriptor {
/// Creates a default render pass descriptor with no attachments.
pub fn new<'a>() -> &'a RenderPassDescriptorRef {
unsafe { msg_send![class!(MTLRenderPassDescriptor), renderPassDescriptor] }
}
}
impl RenderPassDescriptorRef {
pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef {
unsafe { msg_send![self, colorAttachments] }
}
pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> {
unsafe { msg_send![self, depthAttachment] }
}
pub fn set_depth_attachment(
&self,
depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>,
) {
unsafe { msg_send![self, setDepthAttachment: depth_attachment] }
}
pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> {
unsafe { msg_send![self, stencilAttachment] }
}
pub fn set_stencil_attachment(
&self,
stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>,
) {
unsafe { msg_send![self, setStencilAttachment: stencil_attachment] }
}
pub fn visibility_result_buffer(&self) -> Option<&BufferRef> {
unsafe { msg_send![self, visibilityResultBuffer] }
}
pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) {
unsafe { msg_send![self, setVisibilityResultBuffer: buffer] }
}
pub fn render_target_array_length(&self) -> NSUInteger {
unsafe { msg_send![self, renderTargetArrayLength] }
}
pub fn set_render_target_array_length(&self, length: NSUInteger) {
unsafe { msg_send![self, setRenderTargetArrayLength: length] }
}
pub fn render_target_width(&self) -> NSUInteger {
unsafe { msg_send![self, renderTargetWidth] }
}
pub fn set_render_target_width(&self, size: NSUInteger) {
unsafe { msg_send![self, setRenderTargetWidth: size] }
}
pub fn render_target_height(&self) -> NSUInteger {
unsafe { msg_send![self, renderTargetHeight] }
}
pub fn set_render_target_height(&self, size: NSUInteger) {
unsafe { msg_send![self, setRenderTargetHeight: size] }
}
pub fn default_raster_sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, defaultRasterSampleCount] }
}
pub fn set_default_raster_sample_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setDefaultRasterSampleCount: count] }
}
pub fn sample_buffer_attachments(&self) -> &RenderPassSampleBufferAttachmentDescriptorArrayRef {
unsafe { msg_send![self, sampleBufferAttachments] }
}
}

182
vendor/metal/src/resource.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtlpurgeablestate>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLPurgeableState {
KeepCurrent = 1,
NonVolatile = 2,
Volatile = 3,
Empty = 4,
}
/// See <https://developer.apple.com/documentation/metal/mtlcpucachemode>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLCPUCacheMode {
DefaultCache = 0,
WriteCombined = 1,
}
/// See <https://developer.apple.com/documentation/metal/mtlstoragemode>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLStorageMode {
Shared = 0,
Managed = 1,
Private = 2,
/// Only available on macos(11.0), macCatalyst(14.0), ios(10.0)
Memoryless = 3,
}
/// Only available on macos(10.15), ios(13.0)
///
/// See <https://developer.apple.com/documentation/metal/mtlhazardtrackingmode>
#[repr(u64)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLHazardTrackingMode {
Default = 0,
Untracked = 1,
Tracked = 2,
}
pub const MTLResourceCPUCacheModeShift: NSUInteger = 0;
pub const MTLResourceCPUCacheModeMask: NSUInteger = 0xf << MTLResourceCPUCacheModeShift;
pub const MTLResourceStorageModeShift: NSUInteger = 4;
pub const MTLResourceStorageModeMask: NSUInteger = 0xf << MTLResourceStorageModeShift;
pub const MTLResourceHazardTrackingModeShift: NSUInteger = 8;
pub const MTLResourceHazardTrackingModeMask: NSUInteger = 0x3 << MTLResourceHazardTrackingModeShift;
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metal/mtlresourceoptions>
#[allow(non_upper_case_globals)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLResourceOptions: NSUInteger {
const CPUCacheModeDefaultCache = (MTLCPUCacheMode::DefaultCache as NSUInteger) << MTLResourceCPUCacheModeShift;
const CPUCacheModeWriteCombined = (MTLCPUCacheMode::WriteCombined as NSUInteger) << MTLResourceCPUCacheModeShift;
const StorageModeShared = (MTLStorageMode::Shared as NSUInteger) << MTLResourceStorageModeShift;
const StorageModeManaged = (MTLStorageMode::Managed as NSUInteger) << MTLResourceStorageModeShift;
const StorageModePrivate = (MTLStorageMode::Private as NSUInteger) << MTLResourceStorageModeShift;
const StorageModeMemoryless = (MTLStorageMode::Memoryless as NSUInteger) << MTLResourceStorageModeShift;
/// Only available on macos(10.13), ios(10.0)
const HazardTrackingModeDefault = (MTLHazardTrackingMode::Default as NSUInteger) << MTLResourceHazardTrackingModeShift;
/// Only available on macos(10.13), ios(10.0)
const HazardTrackingModeUntracked = (MTLHazardTrackingMode::Untracked as NSUInteger) << MTLResourceHazardTrackingModeShift;
/// Only available on macos(10.15), ios(13.0)
const HazardTrackingModeTracked = (MTLHazardTrackingMode::Tracked as NSUInteger) << MTLResourceHazardTrackingModeShift;
}
}
bitflags::bitflags! {
/// Options that describe how a graphics or compute function uses an argument buffers resource.
///
/// Enabling certain options for certain resources determines whether the Metal driver should
/// convert the resource to another format (for example, whether to decompress a color render target).
///
/// See <https://developer.apple.com/documentation/metal/mtlresourceusage>
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLResourceUsage: NSUInteger {
/// An option that enables reading from the resource.
const Read = 1 << 0;
/// An option that enables writing to the resource.
const Write = 1 << 1;
/// An option that enables sampling from the resource.
///
/// Specify this option only if the resource is a texture.
const Sample = 1 << 2;
}
}
/// See <https://developer.apple.com/documentation/metal/mtlsizeandalign>
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
#[repr(C)]
pub struct MTLSizeAndAlign {
pub size: NSUInteger,
pub align: NSUInteger,
}
/// See <https://developer.apple.com/documentation/metal/mtlresource>
pub enum MTLResource {}
foreign_obj_type! {
type CType = MTLResource;
pub struct Resource;
type ParentType = NsObject;
}
impl ResourceRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode {
unsafe { msg_send![self, cpuCacheMode] }
}
pub fn storage_mode(&self) -> MTLStorageMode {
unsafe { msg_send![self, storageMode] }
}
pub fn set_purgeable_state(&self, state: MTLPurgeableState) -> MTLPurgeableState {
unsafe { msg_send![self, setPurgeableState: state] }
}
/// Only available on macOS 10.13+ & iOS 10.11+
pub fn allocated_size(&self) -> NSUInteger {
unsafe { msg_send![self, allocatedSize] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode {
unsafe { msg_send![self, hazardTrackingMode] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn resource_options(&self) -> MTLResourceOptions {
unsafe { msg_send![self, resourceOptions] }
}
/// Only available on macos(10.13), ios(10.0)
pub fn heap(&self) -> &HeapRef {
unsafe { msg_send![self, heap] }
}
/// Only available on macos(10.15), ios(13.0)
pub fn heap_offset(&self) -> NSUInteger {
unsafe { msg_send![self, heapOffset] }
}
/// Only available on macos(10.13), ios(10.0)
pub fn make_aliasable(&self) {
unsafe { msg_send![self, makeAliasable] }
}
/// Only available on macos(10.13), ios(10.0)
pub fn is_aliasable(&self) -> bool {
unsafe { msg_send_bool![self, isAliasable] }
}
}

165
vendor/metal/src/sampler.rs vendored Normal file
View File

@@ -0,0 +1,165 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::{depthstencil::MTLCompareFunction, DeviceRef, MTLResourceID, NSUInteger};
/// See <https://developer.apple.com/documentation/metal/mtlsamplerminmagfilter>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLSamplerMinMagFilter {
Nearest = 0,
Linear = 1,
}
/// See <https://developer.apple.com/documentation/metal/mtlsamplermipfilter>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLSamplerMipFilter {
NotMipmapped = 0,
Nearest = 1,
Linear = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlsampleraddressmode>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLSamplerAddressMode {
ClampToEdge = 0,
MirrorClampToEdge = 1,
Repeat = 2,
MirrorRepeat = 3,
ClampToZero = 4,
ClampToBorderColor = 5,
}
/// See <https://developer.apple.com/documentation/metal/mtlsamplerbordercolor>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLSamplerBorderColor {
TransparentBlack = 0,
OpaqueBlack = 1,
OpaqueWhite = 2,
}
/// See <https://developer.apple.com/documentation/metal/mtlsamplerdescriptor>
pub enum MTLSamplerDescriptor {}
foreign_obj_type! {
type CType = MTLSamplerDescriptor;
pub struct SamplerDescriptor;
}
impl SamplerDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLSamplerDescriptor);
msg_send![class, new]
}
}
}
impl SamplerDescriptorRef {
pub fn set_min_filter(&self, filter: MTLSamplerMinMagFilter) {
unsafe { msg_send![self, setMinFilter: filter] }
}
pub fn set_mag_filter(&self, filter: MTLSamplerMinMagFilter) {
unsafe { msg_send![self, setMagFilter: filter] }
}
pub fn set_mip_filter(&self, filter: MTLSamplerMipFilter) {
unsafe { msg_send![self, setMipFilter: filter] }
}
pub fn set_address_mode_s(&self, mode: MTLSamplerAddressMode) {
unsafe { msg_send![self, setSAddressMode: mode] }
}
pub fn set_address_mode_t(&self, mode: MTLSamplerAddressMode) {
unsafe { msg_send![self, setTAddressMode: mode] }
}
pub fn set_address_mode_r(&self, mode: MTLSamplerAddressMode) {
unsafe { msg_send![self, setRAddressMode: mode] }
}
pub fn set_max_anisotropy(&self, anisotropy: NSUInteger) {
unsafe { msg_send![self, setMaxAnisotropy: anisotropy] }
}
pub fn set_compare_function(&self, func: MTLCompareFunction) {
unsafe { msg_send![self, setCompareFunction: func] }
}
#[cfg(feature = "private")]
pub unsafe fn set_lod_bias(&self, bias: f32) {
msg_send![self, setLodBias: bias]
}
pub fn set_lod_min_clamp(&self, clamp: f32) {
unsafe { msg_send![self, setLodMinClamp: clamp] }
}
pub fn set_lod_max_clamp(&self, clamp: f32) {
unsafe { msg_send![self, setLodMaxClamp: clamp] }
}
pub fn set_lod_average(&self, enable: bool) {
unsafe { msg_send![self, setLodAverage: enable] }
}
pub fn set_normalized_coordinates(&self, enable: bool) {
unsafe { msg_send![self, setNormalizedCoordinates: enable] }
}
pub fn set_support_argument_buffers(&self, enable: bool) {
unsafe { msg_send![self, setSupportArgumentBuffers: enable] }
}
pub fn set_border_color(&self, color: MTLSamplerBorderColor) {
unsafe { msg_send![self, setBorderColor: color] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlsamplerstate>
pub enum MTLSamplerState {}
foreign_obj_type! {
type CType = MTLSamplerState;
pub struct SamplerState;
}
impl SamplerStateRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn gpu_resource_id(&self) -> MTLResourceID {
unsafe { msg_send![self, gpuResourceID] }
}
}

178
vendor/metal/src/sync.rs vendored Normal file
View File

@@ -0,0 +1,178 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use block::{Block, RcBlock};
use std::ptr;
#[cfg(feature = "dispatch")]
use dispatch;
/// See <https://developer.apple.com/documentation/metal/mtlsharedeventnotificationblock>
type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>;
/// See <https://developer.apple.com/documentation/metal/mtlevent>
pub enum MTLEvent {}
foreign_obj_type! {
type CType = MTLEvent;
pub struct Event;
}
impl EventRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlsharedevent>
pub enum MTLSharedEvent {}
foreign_obj_type! {
type CType = MTLSharedEvent;
pub struct SharedEvent;
type ParentType = Event;
}
impl SharedEventRef {
pub fn signaled_value(&self) -> u64 {
unsafe { msg_send![self, signaledValue] }
}
pub fn set_signaled_value(&self, new_value: u64) {
unsafe { msg_send![self, setSignaledValue: new_value] }
}
/// Schedules a notification handler to be called after the shareable events signal value
/// equals or exceeds a given value.
pub fn notify(
&self,
listener: &SharedEventListenerRef,
value: u64,
block: MTLSharedEventNotificationBlock,
) {
unsafe {
// If the block doesn't have a signature, this segfaults.
// Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327
let block = mem::transmute::<
MTLSharedEventNotificationBlock,
*mut BlockBase<(&SharedEventRef, u64), ()>,
>(block);
(*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE;
(*block).extra = ptr::addr_of!(BLOCK_EXTRA);
let () = msg_send![self, notifyListener:listener atValue:value block:block];
}
extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {}
const SIGNATURE: &[u8] = b"v16@?0Q8\0";
const SIGNATURE_PTR: *const i8 = &SIGNATURE[0] as *const u8 as *const i8;
static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra {
unknown0: 0 as *mut i32,
unknown1: 0 as *mut i32,
unknown2: 0 as *mut i32,
dtor,
signature: &SIGNATURE_PTR,
};
}
}
/// See <https://developer.apple.com/documentation/metal/mtlsharedeventlistener>
pub enum MTLSharedEventListener {}
foreign_obj_type! {
type CType = MTLSharedEventListener;
pub struct SharedEventListener;
}
impl SharedEventListener {
pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self {
let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc];
let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue];
if ptr.is_null() {
panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed");
}
listener
}
#[cfg(feature = "dispatch")]
pub fn from_queue(queue: &dispatch::Queue) -> Self {
unsafe {
let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue);
Self::from_queue_handle(*raw_queue)
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlfence>
pub enum MTLFence {}
foreign_obj_type! {
type CType = MTLFence;
pub struct Fence;
}
impl FenceRef {
pub fn device(&self) -> &DeviceRef {
unsafe { msg_send![self, device] }
}
pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}
pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
let () = msg_send![self, setLabel: nslabel];
}
}
}
bitflags::bitflags! {
/// The render stages at which a synchronization command is triggered.
///
/// Render stages provide finer control for specifying when synchronization must occur,
/// allowing for vertex and fragment processing to overlap in execution.
///
/// See <https://developer.apple.com/documentation/metal/mtlrenderstages>
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLRenderStages: NSUInteger {
/// The vertex rendering stage.
const Vertex = 1 << 0;
/// The fragment rendering stage.
const Fragment = 1 << 1;
/// The tile rendering stage.
const Tile = 1 << 2;
}
}
const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000;
const BLOCK_HAS_SIGNATURE: i32 = 0x40000000;
#[repr(C)]
struct BlockBase<A, R> {
isa: *const std::ffi::c_void, // 0x00
flags: i32, // 0x08
_reserved: i32, // 0x0c
invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10
extra: *const BlockExtra<A, R>, // 0x18
}
type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>);
#[repr(C)]
struct BlockExtra<A, R> {
unknown0: *mut i32, // 0x00
unknown1: *mut i32, // 0x08
unknown2: *mut i32, // 0x10
dtor: BlockExtraDtor<A, R>, // 0x18
signature: *const *const i8, // 0x20
}

352
vendor/metal/src/texture.rs vendored Normal file
View File

@@ -0,0 +1,352 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::*;
use objc::runtime::{NO, YES};
/// See <https://developer.apple.com/documentation/metal/mtltexturetype>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum MTLTextureType {
D1 = 0,
D1Array = 1,
D2 = 2,
D2Array = 3,
D2Multisample = 4,
Cube = 5,
CubeArray = 6,
D3 = 7,
D2MultisampleArray = 8,
}
/// See <https://developer.apple.com/documentation/metal/mtltexturecompressiontype>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum MTLTextureCompressionType {
Lossless = 0,
Lossy = 1,
}
bitflags::bitflags! {
/// See <https://developer.apple.com/documentation/metal/mtltextureusage>
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MTLTextureUsage: NSUInteger {
const Unknown = 0x0000;
const ShaderRead = 0x0001;
const ShaderWrite = 0x0002;
const RenderTarget = 0x0004;
const PixelFormatView = 0x0010;
const ShaderAtomic = 0x0020;
}
}
/// See <https://developer.apple.com/documentation/metal/mtltexturedescriptor>
pub enum MTLTextureDescriptor {}
foreign_obj_type! {
type CType = MTLTextureDescriptor;
pub struct TextureDescriptor;
}
impl TextureDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLTextureDescriptor);
msg_send![class, new]
}
}
}
impl TextureDescriptorRef {
pub fn texture_type(&self) -> MTLTextureType {
unsafe { msg_send![self, textureType] }
}
pub fn set_texture_type(&self, texture_type: MTLTextureType) {
unsafe { msg_send![self, setTextureType: texture_type] }
}
pub fn pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, pixelFormat] }
}
pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) {
unsafe { msg_send![self, setPixelFormat: pixel_format] }
}
pub fn width(&self) -> NSUInteger {
unsafe { msg_send![self, width] }
}
pub fn set_width(&self, width: NSUInteger) {
unsafe { msg_send![self, setWidth: width] }
}
pub fn height(&self) -> NSUInteger {
unsafe { msg_send![self, height] }
}
pub fn set_height(&self, height: NSUInteger) {
unsafe { msg_send![self, setHeight: height] }
}
pub fn depth(&self) -> NSUInteger {
unsafe { msg_send![self, depth] }
}
pub fn set_depth(&self, depth: NSUInteger) {
unsafe { msg_send![self, setDepth: depth] }
}
pub fn mipmap_level_count(&self) -> NSUInteger {
unsafe { msg_send![self, mipmapLevelCount] }
}
pub fn set_mipmap_level_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setMipmapLevelCount: count] }
}
pub fn set_mipmap_level_count_for_size(&self, size: MTLSize) {
let MTLSize {
width,
height,
depth,
} = size;
let count = (width.max(height).max(depth) as f64).log2().ceil() as u64;
self.set_mipmap_level_count(count);
}
pub fn sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, sampleCount] }
}
pub fn set_sample_count(&self, count: NSUInteger) {
unsafe { msg_send![self, setSampleCount: count] }
}
pub fn array_length(&self) -> NSUInteger {
unsafe { msg_send![self, arrayLength] }
}
pub fn set_array_length(&self, length: NSUInteger) {
unsafe { msg_send![self, setArrayLength: length] }
}
pub fn resource_options(&self) -> MTLResourceOptions {
unsafe { msg_send![self, resourceOptions] }
}
pub fn set_resource_options(&self, options: MTLResourceOptions) {
unsafe { msg_send![self, setResourceOptions: options] }
}
pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode {
unsafe { msg_send![self, cpuCacheMode] }
}
pub fn set_cpu_cache_mode(&self, mode: MTLCPUCacheMode) {
unsafe { msg_send![self, setCpuCacheMode: mode] }
}
pub fn storage_mode(&self) -> MTLStorageMode {
unsafe { msg_send![self, storageMode] }
}
pub fn set_storage_mode(&self, mode: MTLStorageMode) {
unsafe { msg_send![self, setStorageMode: mode] }
}
pub fn usage(&self) -> MTLTextureUsage {
unsafe { msg_send![self, usage] }
}
pub fn set_usage(&self, usage: MTLTextureUsage) {
unsafe { msg_send![self, setUsage: usage] }
}
pub fn compression_type(&self) -> MTLTextureCompressionType {
unsafe { msg_send![self, compressionType] }
}
pub fn set_compression_type(&self, compression_type: MTLTextureCompressionType) {
unsafe { msg_send![self, setCompressionType: compression_type] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtltexture>
pub enum MTLTexture {}
foreign_obj_type! {
type CType = MTLTexture;
pub struct Texture;
type ParentType = Resource;
}
impl TextureRef {
#[deprecated(since = "0.13.0")]
pub fn root_resource(&self) -> Option<&ResourceRef> {
unsafe { msg_send![self, rootResource] }
}
pub fn parent_texture(&self) -> Option<&TextureRef> {
unsafe { msg_send![self, parentTexture] }
}
pub fn parent_relative_level(&self) -> NSUInteger {
unsafe { msg_send![self, parentRelativeLevel] }
}
pub fn parent_relative_slice(&self) -> NSUInteger {
unsafe { msg_send![self, parentRelativeSlice] }
}
pub fn buffer(&self) -> Option<&BufferRef> {
unsafe { msg_send![self, buffer] }
}
pub fn buffer_offset(&self) -> NSUInteger {
unsafe { msg_send![self, bufferOffset] }
}
pub fn buffer_stride(&self) -> NSUInteger {
unsafe { msg_send![self, bufferBytesPerRow] }
}
pub fn texture_type(&self) -> MTLTextureType {
unsafe { msg_send![self, textureType] }
}
pub fn pixel_format(&self) -> MTLPixelFormat {
unsafe { msg_send![self, pixelFormat] }
}
pub fn width(&self) -> NSUInteger {
unsafe { msg_send![self, width] }
}
pub fn height(&self) -> NSUInteger {
unsafe { msg_send![self, height] }
}
pub fn depth(&self) -> NSUInteger {
unsafe { msg_send![self, depth] }
}
pub fn mipmap_level_count(&self) -> NSUInteger {
unsafe { msg_send![self, mipmapLevelCount] }
}
pub fn sample_count(&self) -> NSUInteger {
unsafe { msg_send![self, sampleCount] }
}
pub fn array_length(&self) -> NSUInteger {
unsafe { msg_send![self, arrayLength] }
}
pub fn usage(&self) -> MTLTextureUsage {
unsafe { msg_send![self, usage] }
}
/// [framebufferOnly Apple Docs](https://developer.apple.com/documentation/metal/mtltexture/1515749-framebufferonly?language=objc)
pub fn framebuffer_only(&self) -> bool {
unsafe { msg_send_bool![self, isFramebufferOnly] }
}
pub fn get_bytes(
&self,
bytes: *mut std::ffi::c_void,
stride: NSUInteger,
region: MTLRegion,
mipmap_level: NSUInteger,
) {
unsafe {
msg_send![self, getBytes:bytes
bytesPerRow:stride
fromRegion:region
mipmapLevel:mipmap_level]
}
}
pub fn get_bytes_in_slice(
&self,
bytes: *mut std::ffi::c_void,
stride: NSUInteger,
image_stride: NSUInteger,
region: MTLRegion,
mipmap_level: NSUInteger,
slice: NSUInteger,
) {
unsafe {
msg_send![self, getBytes:bytes
bytesPerRow:stride
bytesPerImage:image_stride
fromRegion:region
mipmapLevel:mipmap_level
slice:slice]
}
}
pub fn replace_region(
&self,
region: MTLRegion,
mipmap_level: NSUInteger,
bytes: *const std::ffi::c_void,
stride: NSUInteger,
) {
unsafe {
msg_send![self, replaceRegion:region
mipmapLevel:mipmap_level
withBytes:bytes
bytesPerRow:stride]
}
}
pub fn replace_region_in_slice(
&self,
region: MTLRegion,
mipmap_level: NSUInteger,
slice: NSUInteger,
bytes: *const std::ffi::c_void,
stride: NSUInteger,
image_stride: NSUInteger,
) {
unsafe {
msg_send![self, replaceRegion:region
mipmapLevel:mipmap_level
slice:slice
withBytes:bytes
bytesPerRow:stride
bytesPerImage:image_stride]
}
}
pub fn new_texture_view(&self, pixel_format: MTLPixelFormat) -> Texture {
unsafe { msg_send![self, newTextureViewWithPixelFormat: pixel_format] }
}
pub fn new_texture_view_from_slice(
&self,
pixel_format: MTLPixelFormat,
texture_type: MTLTextureType,
mipmap_levels: crate::NSRange,
slices: crate::NSRange,
) -> Texture {
unsafe {
msg_send![self, newTextureViewWithPixelFormat:pixel_format
textureType:texture_type
levels:mipmap_levels
slices:slices]
}
}
pub fn gpu_resource_id(&self) -> MTLResourceID {
unsafe { msg_send![self, gpuResourceID] }
}
}

90
vendor/metal/src/types.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::NSUInteger;
use std::default::Default;
/// See <https://developer.apple.com/documentation/metal/mtlorigin>
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MTLOrigin {
pub x: NSUInteger,
pub y: NSUInteger,
pub z: NSUInteger,
}
/// See <https://developer.apple.com/documentation/metal/mtlsize>
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MTLSize {
pub width: NSUInteger,
pub height: NSUInteger,
pub depth: NSUInteger,
}
impl MTLSize {
pub fn new(width: NSUInteger, height: NSUInteger, depth: NSUInteger) -> Self {
Self {
width,
height,
depth,
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlregion>
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MTLRegion {
pub origin: MTLOrigin,
pub size: MTLSize,
}
impl MTLRegion {
#[inline]
pub fn new_1d(x: NSUInteger, width: NSUInteger) -> Self {
Self::new_2d(x, 0, width, 1)
}
#[inline]
pub fn new_2d(x: NSUInteger, y: NSUInteger, width: NSUInteger, height: NSUInteger) -> Self {
Self::new_3d(x, y, 0, width, height, 1)
}
#[inline]
pub fn new_3d(
x: NSUInteger,
y: NSUInteger,
z: NSUInteger,
width: NSUInteger,
height: NSUInteger,
depth: NSUInteger,
) -> Self {
Self {
origin: MTLOrigin { x, y, z },
size: MTLSize {
width,
height,
depth,
},
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlsampleposition>
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub struct MTLSamplePosition {
pub x: f32,
pub y: f32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct MTLResourceID {
pub _impl: u64,
}

250
vendor/metal/src/vertexdescriptor.rs vendored Normal file
View File

@@ -0,0 +1,250 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use super::NSUInteger;
/// See <https://developer.apple.com/documentation/metal/mtlvertexformat>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLVertexFormat {
Invalid = 0,
UChar2 = 1,
UChar3 = 2,
UChar4 = 3,
Char2 = 4,
Char3 = 5,
Char4 = 6,
UChar2Normalized = 7,
UChar3Normalized = 8,
UChar4Normalized = 9,
Char2Normalized = 10,
Char3Normalized = 11,
Char4Normalized = 12,
UShort2 = 13,
UShort3 = 14,
UShort4 = 15,
Short2 = 16,
Short3 = 17,
Short4 = 18,
UShort2Normalized = 19,
UShort3Normalized = 20,
UShort4Normalized = 21,
Short2Normalized = 22,
Short3Normalized = 23,
Short4Normalized = 24,
Half2 = 25,
Half3 = 26,
Half4 = 27,
Float = 28,
Float2 = 29,
Float3 = 30,
Float4 = 31,
Int = 32,
Int2 = 33,
Int3 = 34,
Int4 = 35,
UInt = 36,
UInt2 = 37,
UInt3 = 38,
UInt4 = 39,
Int1010102Normalized = 40,
UInt1010102Normalized = 41,
UChar4Normalized_BGRA = 42,
UChar = 45,
Char = 46,
UCharNormalized = 47,
CharNormalized = 48,
UShort = 49,
Short = 50,
UShortNormalized = 51,
ShortNormalized = 52,
Half = 53,
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexstepfunction>
#[repr(u64)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum MTLVertexStepFunction {
Constant = 0,
PerVertex = 1,
PerInstance = 2,
PerPatch = 3,
PerPatchControlPoint = 4,
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexbufferlayoutdescriptor>
pub enum MTLVertexBufferLayoutDescriptor {}
foreign_obj_type! {
type CType = MTLVertexBufferLayoutDescriptor;
pub struct VertexBufferLayoutDescriptor;
}
impl VertexBufferLayoutDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLVertexBufferLayoutDescriptor);
msg_send![class, new]
}
}
}
impl VertexBufferLayoutDescriptorRef {
pub fn stride(&self) -> NSUInteger {
unsafe { msg_send![self, stride] }
}
pub fn set_stride(&self, stride: NSUInteger) {
unsafe { msg_send![self, setStride: stride] }
}
pub fn step_function(&self) -> MTLVertexStepFunction {
unsafe { msg_send![self, stepFunction] }
}
pub fn set_step_function(&self, func: MTLVertexStepFunction) {
unsafe { msg_send![self, setStepFunction: func] }
}
pub fn step_rate(&self) -> NSUInteger {
unsafe { msg_send![self, stepRate] }
}
pub fn set_step_rate(&self, step_rate: NSUInteger) {
unsafe { msg_send![self, setStepRate: step_rate] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexbufferlayoutdescriptorarray>
pub enum MTLVertexBufferLayoutDescriptorArray {}
foreign_obj_type! {
type CType = MTLVertexBufferLayoutDescriptorArray;
pub struct VertexBufferLayoutDescriptorArray;
}
impl VertexBufferLayoutDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&VertexBufferLayoutDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
layout: Option<&VertexBufferLayoutDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:layout
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor>
pub enum MTLVertexAttributeDescriptor {}
foreign_obj_type! {
type CType = MTLVertexAttributeDescriptor;
pub struct VertexAttributeDescriptor;
}
impl VertexAttributeDescriptor {
pub fn new() -> Self {
unsafe {
let class = class!(MTLVertexAttributeDescriptor);
msg_send![class, new]
}
}
}
impl VertexAttributeDescriptorRef {
pub fn format(&self) -> MTLVertexFormat {
unsafe { msg_send![self, format] }
}
pub fn set_format(&self, format: MTLVertexFormat) {
unsafe { msg_send![self, setFormat: format] }
}
pub fn offset(&self) -> NSUInteger {
unsafe { msg_send![self, offset] }
}
pub fn set_offset(&self, offset: NSUInteger) {
unsafe { msg_send![self, setOffset: offset] }
}
pub fn buffer_index(&self) -> NSUInteger {
unsafe { msg_send![self, bufferIndex] }
}
pub fn set_buffer_index(&self, index: NSUInteger) {
unsafe { msg_send![self, setBufferIndex: index] }
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexattributedescriptorarray>
pub enum MTLVertexAttributeDescriptorArray {}
foreign_obj_type! {
type CType = MTLVertexAttributeDescriptorArray;
pub struct VertexAttributeDescriptorArray;
}
impl VertexAttributeDescriptorArrayRef {
pub fn object_at(&self, index: NSUInteger) -> Option<&VertexAttributeDescriptorRef> {
unsafe { msg_send![self, objectAtIndexedSubscript: index] }
}
pub fn set_object_at(
&self,
index: NSUInteger,
attribute: Option<&VertexAttributeDescriptorRef>,
) {
unsafe {
msg_send![self, setObject:attribute
atIndexedSubscript:index]
}
}
}
/// See <https://developer.apple.com/documentation/metal/mtlvertexdescriptor>
pub enum MTLVertexDescriptor {}
foreign_obj_type! {
type CType = MTLVertexDescriptor;
pub struct VertexDescriptor;
}
impl VertexDescriptor {
pub fn new<'a>() -> &'a VertexDescriptorRef {
unsafe {
let class = class!(MTLVertexDescriptor);
msg_send![class, vertexDescriptor]
}
}
}
impl VertexDescriptorRef {
pub fn layouts(&self) -> &VertexBufferLayoutDescriptorArrayRef {
unsafe { msg_send![self, layouts] }
}
pub fn attributes(&self) -> &VertexAttributeDescriptorArrayRef {
unsafe { msg_send![self, attributes] }
}
#[cfg(feature = "private")]
pub unsafe fn serialize_descriptor(&self) -> *mut std::ffi::c_void {
msg_send![self, newSerializedDescriptor]
}
pub fn reset(&self) {
unsafe { msg_send![self, reset] }
}
}