Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1 @@
{"files":{"Cargo.toml":"0ba8b79fa3f4218fbcb299d83fb206fa7e9cb2d8299fc0873fd4648f2a433327","src/fake_sign/mod.rs":"d64059885d744d83487c5a8b17625023fe8bcdddacf60d0b76326fc3bce964d2","src/fake_sign/modified_md5.rs":"132f133c3df2dd7d4bc342085a8168cd3e6a95cd692fb21d74bb6cef92bd8755","src/ffi.rs":"07d2e9dda37db4fd2d03d6732ad771e87c4e121c37f2ebc914dacdb6548bd037","src/intellisense/ffi.rs":"9bbdedb675ba057ad3b4f8027f0e919986f98a56060482f9433480677e09d0c0","src/intellisense/mod.rs":"675903eb100f9a00c28ab4c8ae6349188de15b0b22a48d87737bf246a659d611","src/intellisense/wrapper.rs":"c30973dd6f199bd79ddc7ebffda8f5f417cbc297ed3de0b25a14fbf0ca05e37f","src/lib.rs":"b86a02f40f2a4e18798486f999ecb69d640564fa928f09cb7acdc100e86b1394","src/os.rs":"4957c14583481654b5b5707964e46b9832f9d494303754851c63df3289542d3b","src/unknown.rs":"bc1535f6d12454d221d76a8f7249a3efa5f69e162e0d9ded2ee06461853d7eaf","src/utils.rs":"3aefbdcf33dd3d850cab4bb0382ff76cafd15315d2c22c76061b63c1fbb0fa89","src/wrapper.rs":"014edb2a8640817e665503838ec9f56c657ee2d22b8722c4b376045c5aeeea9e"},"package":"1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0"}

74
third-party/vendor/hassle-rs/Cargo.toml vendored Normal file
View file

@ -0,0 +1,74 @@
# 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 = "2018"
name = "hassle-rs"
version = "0.10.0"
authors = ["Traverse-Research <support@traverseresearch.nl>"]
include = [
"src/*.rs",
"src/intellisense/*.rs",
"src/fake_sign/*.rs",
"Cargo.toml",
]
description = "HLSL compiler library, this crate provides an FFI layer and idiomatic rust wrappers for the new DXC hlsl compiler and validator."
homepage = "https://github.com/Traverse-Research/hassle-rs"
documentation = "https://docs.rs/hassle-rs"
readme = "README.md"
keywords = [
"shader",
"pipeline",
"hlsl",
"dxc",
"intellisense",
]
categories = [
"rendering",
"rendering::graphics-api",
]
license = "MIT"
repository = "https://github.com/Traverse-Research/hassle-rs"
[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
[dependencies.bitflags]
version = "1.2.1"
[dependencies.com-rs]
version = "0.2.1"
[dependencies.libloading]
version = "0.7.0"
[dependencies.thiserror]
version = "1.0"
[dependencies.widestring]
version = "1.0.1"
[dev-dependencies.rspirv]
version = "0.11"
[target."cfg(not(windows))".dependencies.libc]
version = "0.2"
[target."cfg(windows)".dependencies.winapi]
version = "0.3.9"
features = [
"wtypes",
"oleauto",
"combaseapi",
]
[badges.maintenance]
status = "actively-developed"

View file

@ -0,0 +1,98 @@
mod modified_md5;
use modified_md5::Context;
#[repr(C)]
struct FileHeader {
fourcc: u32,
hash_value: [u32; 4],
container_version: u32,
file_length: u32,
num_chunks: u32,
}
const DXIL_HEADER_CONTAINER_VERSION_OFFSET: usize = 20;
const DXBC_FOURCC: u32 = u32::from_le_bytes([b'D', b'X', b'B', b'C']);
fn read_fourcc(dxil: &[u8]) -> u32 {
let header: *const FileHeader = dxil.as_ptr().cast();
unsafe { (*header).fourcc }
}
fn read_file_length(dxil: &[u8]) -> u32 {
let header: *const FileHeader = dxil.as_ptr().cast();
unsafe { (*header).file_length }
}
fn write_hash_value(dxil: &mut [u8], state: [u32; 4]) {
let header: *mut FileHeader = dxil.as_mut_ptr().cast();
unsafe {
(*header).hash_value.copy_from_slice(&state);
}
}
/// Helper function for signing DXIL binary blobs when
/// `dxil.dll` might not be available (such as on Linux based
/// platforms).
/// This essentially performs the same functionality as [`crate::validate_dxil()`]
/// but in a more cross platform way.
///
/// Ported from <https://github.com/baldurk/renderdoc/blob/v1.x/renderdoc/driver/shaders/dxbc/dxbc_container.cpp#L832>
pub fn fake_sign_dxil_in_place(dxil: &mut [u8]) -> bool {
if read_fourcc(dxil) != DXBC_FOURCC {
return false;
}
if read_file_length(dxil) != dxil.len() as u32 {
return false;
}
// the hashable data starts immediately after the hash.
let data = &dxil[DXIL_HEADER_CONTAINER_VERSION_OFFSET..];
let num_bits: u32 = data.len() as u32 * 8;
let num_bits_part_2: u32 = (num_bits >> 2) | 1;
let left_over_len: u32 = data.len() as u32 % 64;
let (first_part, padding_part) = data.split_at(data.len() - left_over_len as usize);
let mut ctx = Context::new();
ctx.consume(first_part);
let mut block = [0u8; 64];
if left_over_len >= 56 {
assert_eq!(padding_part.len(), left_over_len as usize);
ctx.consume(padding_part);
block[0..4].copy_from_slice(&0x80u32.to_le_bytes());
ctx.consume(&block[0..64 - left_over_len as usize]);
// the final block contains the number of bits in the first dword, and the weird upper bits
block[0..4].copy_from_slice(&num_bits.to_le_bytes());
// write to last dword
block[15 * 4..].copy_from_slice(&num_bits_part_2.to_le_bytes());
ctx.consume(block);
} else {
ctx.consume(num_bits.to_le_bytes());
if left_over_len != 0 {
ctx.consume(padding_part)
}
let padding_bytes = (64 - left_over_len - 4) as usize;
block[0] = 0x80;
block[padding_bytes - 4..padding_bytes].copy_from_slice(&num_bits_part_2.to_le_bytes());
ctx.consume(&block[0..padding_bytes]);
}
// dxil signing is odd - it doesn't run the finalization step of the md5
// algorithm but instead pokes the hasher state directly into container
write_hash_value(dxil, ctx.state);
true
}

View file

@ -0,0 +1,251 @@
// https://github.com/stainless-steel/md5/blob/3236fc93c26af909923767e65be87e45c47aab89/LICENSE.md
//
// Taken under the Apache 2.0 and MIT dual license to be included into this project with small
// modifications.
//
// Apache 2.0
//
// Copyright 20152019 The md5 Developers
//
// 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.
//
//
// MIT:
//
// Copyright 20152019 The md5 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.
#[derive(Clone)]
pub struct Context {
buffer: [u8; 64],
count: [u32; 2],
pub state: [u32; 4], // hassle-rs modification
}
impl Context {
#[inline]
pub fn new() -> Context {
Context {
buffer: [0; 64],
count: [0, 0],
state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
}
}
/// Consume data.
#[cfg(target_pointer_width = "32")]
#[inline]
pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
consume(self, data.as_ref());
}
/// Consume data.
#[cfg(target_pointer_width = "64")]
pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
for chunk in data.as_ref().chunks(core::u32::MAX as usize) {
consume(self, chunk);
}
}
}
fn consume(
Context {
buffer,
count,
state,
}: &mut Context,
data: &[u8],
) {
let mut input = [0u32; 16];
let mut k = ((count[0] >> 3) & 0x3f) as usize;
let length = data.len() as u32;
count[0] = count[0].wrapping_add(length << 3);
if count[0] < length << 3 {
count[1] = count[1].wrapping_add(1);
}
count[1] = count[1].wrapping_add(length >> 29);
for &value in data {
buffer[k] = value;
k += 1;
if k == 0x40 {
let mut j = 0;
for v in input.iter_mut() {
// hassle-rs modification to deal with clippy
*v = ((buffer[j + 3] as u32) << 24)
| ((buffer[j + 2] as u32) << 16)
| ((buffer[j + 1] as u32) << 8)
| (buffer[j] as u32);
j += 4;
}
transform(state, &input);
k = 0;
}
}
}
fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
macro_rules! add(
($a:expr, $b:expr) => ($a.wrapping_add($b));
);
macro_rules! rotate(
($x:expr, $n:expr) => (($x << $n) | ($x >> (32 - $n)));
);
{
macro_rules! F(
($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
);
macro_rules! T(
($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
$a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
$a = rotate!($a, $s);
$a = add!($a, $b);
});
);
const S1: u32 = 7;
const S2: u32 = 12;
const S3: u32 = 17;
const S4: u32 = 22;
T!(a, b, c, d, input[0], S1, 3614090360);
T!(d, a, b, c, input[1], S2, 3905402710);
T!(c, d, a, b, input[2], S3, 606105819);
T!(b, c, d, a, input[3], S4, 3250441966);
T!(a, b, c, d, input[4], S1, 4118548399);
T!(d, a, b, c, input[5], S2, 1200080426);
T!(c, d, a, b, input[6], S3, 2821735955);
T!(b, c, d, a, input[7], S4, 4249261313);
T!(a, b, c, d, input[8], S1, 1770035416);
T!(d, a, b, c, input[9], S2, 2336552879);
T!(c, d, a, b, input[10], S3, 4294925233);
T!(b, c, d, a, input[11], S4, 2304563134);
T!(a, b, c, d, input[12], S1, 1804603682);
T!(d, a, b, c, input[13], S2, 4254626195);
T!(c, d, a, b, input[14], S3, 2792965006);
T!(b, c, d, a, input[15], S4, 1236535329);
}
{
macro_rules! F(
($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
);
macro_rules! T(
($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
$a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
$a = rotate!($a, $s);
$a = add!($a, $b);
});
);
const S1: u32 = 5;
const S2: u32 = 9;
const S3: u32 = 14;
const S4: u32 = 20;
T!(a, b, c, d, input[1], S1, 4129170786);
T!(d, a, b, c, input[6], S2, 3225465664);
T!(c, d, a, b, input[11], S3, 643717713);
T!(b, c, d, a, input[0], S4, 3921069994);
T!(a, b, c, d, input[5], S1, 3593408605);
T!(d, a, b, c, input[10], S2, 38016083);
T!(c, d, a, b, input[15], S3, 3634488961);
T!(b, c, d, a, input[4], S4, 3889429448);
T!(a, b, c, d, input[9], S1, 568446438);
T!(d, a, b, c, input[14], S2, 3275163606);
T!(c, d, a, b, input[3], S3, 4107603335);
T!(b, c, d, a, input[8], S4, 1163531501);
T!(a, b, c, d, input[13], S1, 2850285829);
T!(d, a, b, c, input[2], S2, 4243563512);
T!(c, d, a, b, input[7], S3, 1735328473);
T!(b, c, d, a, input[12], S4, 2368359562);
}
{
macro_rules! F(
($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
);
macro_rules! T(
($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
$a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
$a = rotate!($a, $s);
$a = add!($a, $b);
});
);
const S1: u32 = 4;
const S2: u32 = 11;
const S3: u32 = 16;
const S4: u32 = 23;
T!(a, b, c, d, input[5], S1, 4294588738);
T!(d, a, b, c, input[8], S2, 2272392833);
T!(c, d, a, b, input[11], S3, 1839030562);
T!(b, c, d, a, input[14], S4, 4259657740);
T!(a, b, c, d, input[1], S1, 2763975236);
T!(d, a, b, c, input[4], S2, 1272893353);
T!(c, d, a, b, input[7], S3, 4139469664);
T!(b, c, d, a, input[10], S4, 3200236656);
T!(a, b, c, d, input[13], S1, 681279174);
T!(d, a, b, c, input[0], S2, 3936430074);
T!(c, d, a, b, input[3], S3, 3572445317);
T!(b, c, d, a, input[6], S4, 76029189);
T!(a, b, c, d, input[9], S1, 3654602809);
T!(d, a, b, c, input[12], S2, 3873151461);
T!(c, d, a, b, input[15], S3, 530742520);
T!(b, c, d, a, input[2], S4, 3299628645);
}
{
macro_rules! F(
($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
);
macro_rules! T(
($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
$a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
$a = rotate!($a, $s);
$a = add!($a, $b);
});
);
const S1: u32 = 6;
const S2: u32 = 10;
const S3: u32 = 15;
const S4: u32 = 21;
T!(a, b, c, d, input[0], S1, 4096336452);
T!(d, a, b, c, input[7], S2, 1126891415);
T!(c, d, a, b, input[14], S3, 2878612391);
T!(b, c, d, a, input[5], S4, 4237533241);
T!(a, b, c, d, input[12], S1, 1700485571);
T!(d, a, b, c, input[3], S2, 2399980690);
T!(c, d, a, b, input[10], S3, 4293915773);
T!(b, c, d, a, input[1], S4, 2240044497);
T!(a, b, c, d, input[8], S1, 1873313359);
T!(d, a, b, c, input[15], S2, 4264355552);
T!(c, d, a, b, input[6], S3, 2734768916);
T!(b, c, d, a, input[13], S4, 1309151649);
T!(a, b, c, d, input[4], S1, 4149444226);
T!(d, a, b, c, input[11], S2, 3174756917);
T!(c, d, a, b, input[2], S3, 718787259);
T!(b, c, d, a, input[9], S4, 3951481745);
}
state[0] = add!(state[0], a);
state[1] = add!(state[1], b);
state[2] = add!(state[2], c);
state[3] = add!(state[3], d);
}

303
third-party/vendor/hassle-rs/src/ffi.rs vendored Normal file
View file

@ -0,0 +1,303 @@
#![allow(clippy::transmute_ptr_to_ptr)]
#![allow(clippy::too_many_arguments)]
use crate::os::{HRESULT, LPCWSTR, LPWSTR};
use com_rs::{com_interface, iid, IUnknown, IID};
use std::ffi::c_void;
pub type DxcCreateInstanceProc =
extern "system" fn(rclsid: &IID, riid: &IID, ppv: *mut *mut c_void) -> HRESULT;
pub type DxcCreateInstanceProc2 = extern "system" fn(
malloc: /* IMalloc */ *const c_void,
rclsid: &IID,
riid: &IID,
ppv: *mut *mut c_void,
) -> HRESULT;
pub const DFCC_DXIL: u32 = u32::from_le_bytes([b'D', b'X', b'I', b'L']);
iid!(pub IID_IDxcBlob = 0x8BA5_FB08, 0x5195, 0x40e2, 0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02);
com_interface! {
interface IDxcBlob: IUnknown{
iid: IID_IDxcBlob,
vtable: IDxcBlobVtbl,
fn get_buffer_pointer() -> *mut c_void;
fn get_buffer_size() -> usize;
}
}
iid!(pub IID_IDxcBlobEncoding = 0x7241_d424, 0x2646, 0x4191, 0x97, 0xc0, 0x98, 0xe9, 0x6e, 0x42, 0xfc, 0x68);
com_interface! {
interface IDxcBlobEncoding: IDxcBlob, IUnknown{
iid: IID_IDxcBlobEncoding,
vtable: IDxcBlobEncodingVtbl,
fn get_encoding(known: *mut u32, code_page: *mut u32) -> HRESULT;
}
}
iid!(pub IID_IDxcLibrary = 0xe520_4dc7, 0xd18c, 0x4c3c, 0xbd, 0xfb, 0x85, 0x16, 0x73, 0x98, 0x0f, 0xe7);
com_interface! {
interface IDxcLibrary: IUnknown{
iid: IID_IDxcLibrary,
vtable: IDxcLibraryVtbl,
fn set_malloc(malloc: *const c_void) -> HRESULT;
fn create_blob_from_blob(blob: *const IDxcBlob, offset: u32, length: u32, result_blob: *mut *mut IDxcBlob) -> HRESULT;
fn create_blob_from_file(filename: LPCWSTR, code_page: *const u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
fn create_blob_with_encoding_from_pinned(text: *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
fn create_blob_with_encoding_on_heap_copy(text: *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
fn create_blob_with_encoding_on_malloc(text: *const c_void, malloc: /* IMalloc */ *const c_void, size: u32, code_page: u32, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
fn create_include_handler(include_handler: *mut *mut IDxcIncludeHandler) -> HRESULT;
fn create_stream_from_blob_read_only(blob: *const IDxcBlob, stream: /* IStream */ *mut *mut c_void) -> HRESULT;
fn get_blob_as_utf8(blob: *const IDxcBlob, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
fn get_blob_as_utf16(blob: *const IDxcBlob, blob_encoding: *mut *mut IDxcBlobEncoding) -> HRESULT;
}
}
iid!(pub IID_IDxcOperationResult = 0xCEDB_484A, 0xD4E9, 0x445A, 0xB9, 0x91, 0xCA, 0x21, 0xCA, 0x15, 0x7D, 0xC2);
com_interface! {
interface IDxcOperationResult: IUnknown{
iid: IID_IDxcOperationResult,
vtable: IDxcOperationResultVtbl,
fn get_status(status: *mut u32) -> HRESULT;
fn get_result(result: *mut *mut IDxcBlob) -> HRESULT;
fn get_error_buffer(errors: *mut *mut IDxcBlobEncoding) -> HRESULT;
}
}
iid!(pub IID_IDxcIncludeHandler = 0x7f61_fc7d, 0x950d, 0x467f, 0xb3, 0xe3, 0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c);
com_interface! {
interface IDxcIncludeHandler: IUnknown{
iid: IID_IDxcIncludeHandler,
vtable: IDxcIncludeHandlerVtbl,
fn load_source(filename: LPCWSTR, include_source: *mut *mut IDxcBlob) -> HRESULT;
}
}
#[repr(C)]
#[derive(Debug)]
pub struct DxcDefine {
pub name: LPCWSTR,
pub value: LPCWSTR,
}
iid!(pub IID_IDxcCompiler = 0x8c21_0bf3, 0x011f, 0x4422, 0x8d, 0x70, 0x6f, 0x9a, 0xcb, 0x8d, 0xb6, 0x17);
com_interface! {
interface IDxcCompiler: IUnknown{
iid: IID_IDxcCompiler,
vtable: IDxcCompilerVtbl,
fn compile(
blob: *const IDxcBlob,
source_name: LPCWSTR,
entry_point: LPCWSTR,
target_profile: LPCWSTR,
arguments: *const LPCWSTR,
arg_count: u32,
defines: *const DxcDefine,
def_count: u32,
include_handler: *const IDxcIncludeHandler,
result: *mut *mut IDxcOperationResult) -> HRESULT;
fn preprocess(
blob: *const IDxcBlob,
source_name: LPCWSTR,
arguments: *const LPCWSTR,
arg_count: u32,
defines: *const DxcDefine,
def_count: u32,
include_handler: *const IDxcIncludeHandler,
result: *mut *mut IDxcOperationResult) -> HRESULT;
fn disassemble(
blob: *const IDxcBlob,
disassembly: *mut *mut IDxcBlobEncoding) -> HRESULT;
}
}
iid!(pub IID_IDxcCompiler2 = 0xA005_A9D9, 0xB8BB, 0x4594, 0xB5, 0xC9, 0x0E, 0x63, 0x3B, 0xEC, 0x4D, 0x37);
com_interface! {
interface IDxcCompiler2: IDxcCompiler, IUnknown{
iid: IID_IDxcCompiler2,
vtable: IDxcCompiler2Vtbl,
fn compile_with_debug(
blob: *const IDxcBlob,
source_name: LPCWSTR,
entry_point: LPCWSTR,
target_profile: LPCWSTR,
arguments: *const LPCWSTR,
arg_count: u32,
defines: *const DxcDefine,
def_count: u32,
include_handler: *const IDxcIncludeHandler,
result: *mut *mut IDxcOperationResult,
debug_blob_name: *mut LPWSTR,
debug_blob: *mut *mut IDxcBlob) -> HRESULT;
}
}
iid!(pub IID_IDxcLinker = 0xF1B5_BE2A, 0x62DD, 0x4327, 0xA1, 0xC2, 0x42, 0xAC, 0x1E, 0x1E, 0x78, 0xE6);
com_interface! {
interface IDxcLinker: IUnknown{
iid: IID_IDxcLinker,
vtable: IDxcLinkerVtbl,
fn register_library(lib_name: LPCWSTR, lib: *const IDxcBlob) -> HRESULT;
fn link(
entry_name: LPCWSTR,
target_profile: LPCWSTR,
lib_names: *const LPCWSTR,
lib_count: u32,
arguments: *const LPCWSTR,
arg_count: u32,
result: *mut *mut IDxcOperationResult) -> HRESULT;
}
}
pub const DXC_VALIDATOR_FLAGS_DEFAULT: u32 = 0;
pub const DXC_VALIDATOR_FLAGS_IN_PLACE_EDIT: u32 = 1; // Validator is allowed to update shader blob in-place.
pub const DXC_VALIDATOR_FLAGS_ROOT_SIGNATURE_ONLY: u32 = 2;
pub const DXC_VALIDATOR_FLAGS_MODULE_ONLY: u32 = 4;
pub const DXC_VALIDATOR_FLAGS_VALID_MASK: u32 = 0x7;
iid!(pub IID_IDxcValidator = 0xA6E8_2BD2, 0x1FD7, 0x4826, 0x98, 0x11, 0x28, 0x57, 0xE7, 0x97, 0xF4, 0x9A);
com_interface! {
interface IDxcValidator: IUnknown{
iid: IID_IDxcValidator,
vtable: IDxcValidatorVtbl,
fn validate(shader: *const IDxcBlob, flags: u32, result: *mut *mut IDxcOperationResult) -> HRESULT;
}
}
iid!(pub IID_IDxcContainerBuilder = 0x334b_1f50, 0x2292, 0x4b35, 0x99, 0xa1, 0x25, 0x58, 0x8d, 0x8c, 0x17, 0xfe);
com_interface! {
interface IDxcContainerBuilder: IUnknown{
iid: IID_IDxcContainerBuilder,
vtable: IDxcContainerBuilderVtbl,
fn load(dxil_container_header: *const IDxcBlob) -> HRESULT;
fn add_part(four_cc: u32, source: *const IDxcBlob) -> HRESULT;
fn remove_part(four_cc: u32) -> HRESULT;
fn seralize_container(result: *mut *mut IDxcOperationResult) -> HRESULT;
}
}
iid!(pub IID_IDxcAssembler = 0x091f_7a26, 0x1c1f, 0x4948, 0x90, 0x4b, 0xe6, 0xe3, 0xa8, 0xa7, 0x71, 0xd5);
com_interface! {
interface IDxcAssembler: IUnknown{
iid: IID_IDxcAssembler,
vtable: IDxcAssemblerVtbl,
fn assemble_to_container(shader: *const IDxcBlob, result: *mut *mut IDxcOperationResult) -> HRESULT;
}
}
iid!(pub IID_IDxcContainerReflection = 0xd2c2_1b26, 0x8350, 0x4bdc, 0x97, 0x6a, 0x33, 0x1c, 0xe6, 0xf4, 0xc5, 0x4c);
com_interface! {
interface IDxcContainerReflection: IUnknown{
iid: IID_IDxcContainerReflection,
vtable: IDxcContainerReflectionVtbl,
fn load(container: *const IDxcBlob) -> HRESULT;
fn get_part_count(result: *mut u32) -> HRESULT;
fn get_part_kind(idx: u32, result: *mut u32) -> HRESULT;
fn get_part_content(idx: u32, result: *mut *mut IDxcBlob) -> HRESULT;
fn find_first_part_kind(kind: u32, result: *mut u32) -> HRESULT;
fn get_part_reflection(idx: u32, iid: &IID, object: *mut *mut c_void) -> HRESULT;
}
}
iid!(pub IID_IDxcOptimizerPass = 0xAE2C_D79F, 0xCC22, 0x453F, 0x9B, 0x6B, 0xB1, 0x24, 0xE7, 0xA5, 0x20, 0x4C);
com_interface! {
interface IDxcOptimizerPass: IUnknown{
iid: IID_IDxcOptimizerPass,
vtable: IDxcOptimizerPassVtbl,
fn get_option_name(result: *mut LPWSTR) -> HRESULT;
fn get_description(result: *mut LPWSTR) -> HRESULT;
fn get_option_arg_count(count: *mut u32) -> HRESULT;
fn get_option_arg_name(arg_idx: u32, result: *mut LPWSTR) -> HRESULT;
fn get_option_arg_description(arg_idx: u32, result: *mut LPWSTR) -> HRESULT;
}
}
iid!(pub IID_IDxcOptimizer = 0x2574_0E2E, 0x9CBA, 0x401B, 0x91, 0x19, 0x4F, 0xB4, 0x2F, 0x39, 0xF2, 0x70);
com_interface! {
interface IDxcOptimizer: IUnknown{
iid: IID_IDxcOptimizer,
vtable: IDxcOptimizerVtbl,
fn get_available_pass_count(count: *mut u32) -> HRESULT;
fn get_available_pass(index: u32, result: *mut *mut IDxcOptimizerPass) -> HRESULT;
fn run_optimizer(
blob: *const IDxcBlob,
options: *const LPCWSTR,
option_count: u32,
output_module: *mut *mut IDxcBlob,
output_text: *mut *mut IDxcBlobEncoding) -> HRESULT;
}
}
pub const DXC_VERSION_INFO_FLAGS_NONE: u32 = 0;
pub const DXC_VERSION_INFO_FLAGS_DEBUG: u32 = 1; // Matches VS_FF_DEBUG
pub const DXC_VERSION_INFO_FLAGS_INTERNAL: u32 = 2; // Internal Validator (non-signing)
iid!(pub IID_IDxcVersionInfo = 0xb04f_5b50, 0x2059, 0x4f12, 0xa8, 0xff, 0xa1, 0xe0, 0xcd, 0xe1, 0xcc, 0x7e);
com_interface! {
interface IDxcVersionInfo: IUnknown{
iid: IID_IDxcVersionInfo,
vtable: IDxcVersionInfoVtbl,
fn get_version(major: *mut u32, minor: *mut u32) -> HRESULT;
fn get_flags(flags: *mut u32) -> HRESULT;
}
}
iid!(pub IID_IDxcVersionInfo2 = 0xfb69_04c4, 0x42f0, 0x4b62, 0x9c, 0x46, 0x98, 0x3a, 0xf7, 0xda, 0x7c, 0x83);
com_interface! {
interface IDxcVersionInfo2: IUnknown{
iid: IID_IDxcVersionInfo2,
vtable: IDxcVersionInfo2Vtbl,
fn get_commit_info(commit_count: *mut u32, commit_hash: *mut *mut u8) -> HRESULT;
}
}
iid!(pub IID_ID3D12ShaderReflection = 0x5a58_797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e);
com_interface! {
interface ID3D12ShaderReflection: IUnknown {
iid: IID_ID3D12ShaderReflection,
vtable: ID3D12ShaderReflectionVtbl,
fn get_desc(p_desc: *mut c_void) -> HRESULT;
fn get_constant_buffer_by_index(index: u32) -> *mut c_void;
fn get_constant_buffer_by_name(name: *const c_void) -> *mut c_void;
fn get_resource_binding_desc(resource_index: u32, p_desc: *mut c_void) -> HRESULT;
fn get_input_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT;
fn get_output_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT;
fn get_patch_constant_parameter_desc(parameter_index: u32, p_desc: *mut c_void) -> HRESULT;
fn get_variable_by_name(name: *const c_void) -> *mut c_void;
fn get_resource_binding_desc_by_name(name: *const c_void, p_desc: *mut c_void) -> HRESULT;
fn get_mov_instruction_count() -> u32;
fn get_movc_instruction_count() -> u32;
fn get_conversion_instruction_count() -> u32;
fn get_bitwise_instruction_count() -> u32;
fn get_gs_input_primitive() -> u32;
fn is_sample_frequency_shader() -> bool;
fn get_num_interface_slots() -> u32;
fn get_min_feature_level(p_level: *mut c_void) -> HRESULT;
fn get_thread_group_size(size_x: *mut u32, size_y: *mut u32, size_z: *mut u32) -> u32;
fn get_requires_flags() -> u64;
}
}
iid!(pub CLSID_DxcCompiler = 0x73e2_2d93, 0xe6ce, 0x47f3, 0xb5, 0xbf, 0xf0, 0x66, 0x4f, 0x39, 0xc1, 0xb0);
iid!(pub CLSID_DxcLinker = 0xef6a_8087, 0xb0ea, 0x4d56, 0x9e, 0x45, 0xd0, 0x7e, 0x1a, 0x8b, 0x78, 0x6);
iid!(pub CLSID_DxcDiaDataSource = 0xcd1f_6b73, 0x2ab0, 0x484d, 0x8e, 0xdc, 0xeb, 0xe7, 0xa4, 0x3c, 0xa0, 0x9f );
iid!(pub CLSID_DxcLibrary = 0x6245_d6af, 0x66e0, 0x48fd, 0x80, 0xb4, 0x4d, 0x27, 0x17, 0x96, 0x74, 0x8c);
iid!(pub CLSID_DxcValidator = 0x8ca3_e215, 0xf728, 0x4cf3, 0x8c, 0xdd, 0x88, 0xaf, 0x91, 0x75, 0x87, 0xa1 );
iid!(pub CLSID_DxcAssembler = 0xd728_db68, 0xf903, 0x4f80, 0x94, 0xcd, 0xdc, 0xcf, 0x76, 0xec, 0x71, 0x51);
iid!(pub CLSID_DxcContainerReflection = 0xb9f5_4489, 0x55b8, 0x400c, 0xba, 0x3a, 0x16, 0x75, 0xe4, 0x72, 0x8b, 0x91);
iid!(pub CLSID_DxcOptimizer = 0xae2c_d79f, 0xcc22, 0x453f, 0x9b, 0x6b, 0xb1, 0x24, 0xe7, 0xa5, 0x20, 0x4c);
iid!(pub CLSID_DxcContainerBuilder = 0x9413_4294, 0x411f, 0x4574, 0xb4, 0xd0, 0x87, 0x41, 0xe2, 0x52, 0x40, 0xd2 );

View file

@ -0,0 +1,539 @@
use crate::os::{BSTR, HRESULT, LPCSTR, LPSTR};
use bitflags::bitflags;
use com_rs::{com_interface, iid, IUnknown};
bitflags! {
pub struct DxcGlobalOptions : u32 {
const NONE = 0x0;
const THREAD_BACKGROUND_PRIORITY_FOR_INDEXING = 0x1;
const THREAD_BACKGROUND_PRIORITY_FOR_EDITING = 0x2;
const THREAD_BACKGROUND_PRIORITY_FOR_ALL
= DxcGlobalOptions::THREAD_BACKGROUND_PRIORITY_FOR_INDEXING.bits
| DxcGlobalOptions::THREAD_BACKGROUND_PRIORITY_FOR_EDITING.bits;
}
}
bitflags! {
pub struct DxcDiagnosticSeverity : u32 {
const IGNORED = 0;
const NOTE = 1;
const WARNING = 2;
const ERROR = 3;
const FATAL = 4;
}
}
bitflags! {
pub struct DxcTokenKind : u32 {
const PUNCTUATION = 0;
const KEYWORD = 1;
const IDENTIFIER = 2;
const LITERAL = 3;
const COMMENT = 4;
const UNKNOWN = 5;
const BUILT_IN_TYPE = 6;
}
}
bitflags! {
pub struct DxcTypeKind : u32 {
const Invalid = 0; // Represents an invalid type (e.g., where no type is available).
const Unexposed = 1; // A type whose specific kind is not exposed via this interface.
// Builtin types
const Void = 2;
const Bool = 3;
const Char_U = 4;
const UChar = 5;
const Char16 = 6;
const Char32 = 7;
const UShort = 8;
const UInt = 9;
const ULong = 10;
const ULongLong = 11;
const UInt128 = 12;
const Char_S = 13;
const SChar = 14;
const WChar = 15;
const Short = 16;
const Int = 17;
const Long = 18;
const LongLong = 19;
const Int128 = 20;
const Float = 21;
const Double = 22;
const LongDouble = 23;
const NullPtr = 24;
const Overload = 25;
const Dependent = 26;
const ObjCId = 27;
const ObjCClass = 28;
const ObjCSel = 29;
const FirstBuiltin = DxcTypeKind::Void.bits;
const LastBuiltin = DxcTypeKind::ObjCSel.bits;
const Complex = 100;
const Pointer = 101;
const BlockPointer = 102;
const LValueReference = 103;
const RValueReference = 104;
const Record = 105;
const Enum = 106;
const Typedef = 107;
const ObjCInterface = 108;
const ObjCObjectPointer = 109;
const FunctionNoProto = 110;
const FunctionProto = 111;
const ConstantArray = 112;
const Vector = 113;
const IncompleteArray = 114;
const VariableArray = 115;
const DependentSizedArray = 116;
const MemberPointer = 117;
}
}
bitflags! {
pub struct DxcCursorFormatting : u32 {
const DEFAULT = 0x0;
const USE_LANGUAGE_OPTIONS = 0x1;
const SUPPRESS_SPECIFIERS = 0x2;
const SUPPRESS_TAG_KEYWORD = 0x4;
const INCLUDE_NAMESPACE_KEYWORD = 0x8;
}
}
bitflags! {
pub struct DxcTranslationUnitFlags : u32 {
const NONE = 0x0;
const DETAILED_PREPROCESSING_RECORD = 0x01;
const INCOMPLETE = 0x02;
const PRECOMPILED_PREAMBLE = 0x04;
const CACHE_COMPLETION_RESULTS = 0x08;
const FOR_SERIALIZATION = 0x10;
const CXX_CHAINED_PCH = 0x20;
const SKIP_FUNCTION_BODIES = 0x40;
const INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 0x80;
const USE_CALLER_THREAD = 0x800;
}
}
bitflags! {
pub struct DxcDiagnosticDisplayOptions : u32 {
const DISPLAY_SOURCE_LOCATION = 0x01;
const DISPLAY_COLUMN = 0x02;
const DISPLAY_SOURCE_RANGES = 0x04;
const DISPLAY_OPTION = 0x08;
const DISPLAY_CATEGORY_ID = 0x10;
const DISPLAY_CATEGORY_NAME = 0x20;
const DISPLAY_SEVERITY = 0x200;
}
}
bitflags! {
pub struct DxcCursorKindFlags : u32 {
const NONE = 0;
const DECLARATION = 0x1;
const REFERENCE = 0x2;
const EXPRESSION = 0x4;
const STATEMENT = 0x8;
const ATTRIBUTE = 0x10;
const INVALID = 0x20;
const TRANSLATION_UNIT = 0x40;
const PREPROCESSING = 0x80;
const UNEXPOSED = 0x100;
}
}
bitflags! {
pub struct DxcCursorKind : u32 {
const UNEXPOSED_DECL = 1;
const STRUCT_DECL = 2;
const UNION_DECL = 3;
const CLASS_DECL = 4;
const ENUM_DECL = 5;
const FIELD_DECL = 6;
const ENUM_CONSTANT_DECL = 7;
const FUNCTION_DECL = 8;
const VAR_DECL = 9;
const PARM_DECL = 10;
const OBJ_C_INTERFACE_DECL = 11;
const OBJ_C_CATEGORY_DECL = 12;
const OBJ_C_PROTOCOL_DECL = 13;
const OBJ_C_PROPERTY_DECL = 14;
const OBJ_C_IVAR_DECL = 15;
const OBJ_C_INSTANCE_METHOD_DECL = 16;
const OBJ_C_CLASS_METHOD_DECL = 17;
const OBJ_C_IMPLEMENTATION_DECL = 18;
const OBJ_C_CATEGORY_IMPL_DECL = 19;
const TYPEDEF_DECL = 20;
const CXX_METHOD = 21;
const NAMESPACE = 22;
const LINKAGE_SPEC = 23;
const CONSTRUCTOR = 24;
const DESTRUCTOR = 25;
const CONVERSION_FUNCTION = 26;
const TEMPLATE_TYPE_PARAMETER = 27;
const NON_TYPE_TEMPLATE_PARAMETER = 28;
const TEMPLATE_TEMPLATE_PARAMETER = 29;
const FUNCTION_TEMPLATE = 30;
const CLASS_TEMPLATE = 31;
const CLASS_TEMPLATE_PARTIAL_SPECIALIZATION = 32;
const NAMESPACE_ALIAS = 33;
const USING_DIRECTIVE = 34;
const USING_DECLARATION = 35;
const TYPE_ALIAS_DECL = 36;
const OBJ_C_SYNTHESIZE_DECL = 37;
const OBJ_C_DYNAMIC_DECL = 38;
const CXX_ACCESS_SPECIFIER = 39;
const FIRST_DECL = DxcCursorKind::UNEXPOSED_DECL.bits;
const LAST_DECL = DxcCursorKind::CXX_ACCESS_SPECIFIER.bits;
const FIRST_REF = 40;
const OBJ_C_SUPER_CLASS_REF = 40;
const OBJ_C_PROTOCOL_REF = 41;
const OBJ_C_CLASS_REF = 42;
const TYPE_REF = 43;
const CXX_BASE_SPECIFIER = 44;
const TEMPLATE_REF = 45;
const NAMESPACE_REF = 46;
const MEMBER_REF = 47;
const LABEL_REF = 48;
const OVERLOADED_DECL_REF = 49;
const VARIABLE_REF = 50;
const LAST_REF = DxcCursorKind::VARIABLE_REF.bits;
const FIRST_INVALID = 70;
const INVALID_FILE = 70;
const NO_DECL_FOUND = 71;
const NOT_IMPLEMENTED = 72;
const INVALID_CODE = 73;
const LAST_INVALID = DxcCursorKind::INVALID_CODE.bits;
const FIRST_EXPR = 100;
const UNEXPOSED_EXPR = 100;
const DECL_REF_EXPR = 101;
const MEMBER_REF_EXPR = 102;
const CALL_EXPR = 103;
const OBJ_C_MESSAGE_EXPR = 104;
const BLOCK_EXPR = 105;
const INTEGER_LITERAL = 106;
const FLOATING_LITERAL = 107;
const IMAGINARY_LITERAL = 108;
const STRING_LITERAL = 109;
const CHARACTER_LITERAL = 110;
const PAREN_EXPR = 111;
const UNARY_OPERATOR = 112;
const ARRAY_SUBSCRIPT_EXPR = 113;
const BINARY_OPERATOR = 114;
const COMPOUND_ASSIGN_OPERATOR = 115;
const CONDITIONAL_OPERATOR = 116;
const C_STYLE_CAST_EXPR = 117;
const COMPOUND_LITERAL_EXPR = 118;
const INIT_LIST_EXPR = 119;
const ADDR_LABEL_EXPR = 120;
const STMT_EXPR = 121;
const GENERIC_SELECTION_EXPR = 122;
const GNU_NULL_EXPR = 123;
const CXX_STATIC_CAST_EXPR = 124;
const CXX_DYNAMIC_CAST_EXPR = 125;
const CXX_REINTERPRET_CAST_EXPR = 126;
const CXX_CONST_CAST_EXPR = 127;
const CXX_FUNCTIONAL_CAST_EXPR = 128;
const CXX_TYPEID_EXPR = 129;
const CXX_BOOL_LITERAL_EXPR = 130;
const CXX_NULL_PTR_LITERAL_EXPR = 131;
const CXX_THIS_EXPR = 132;
const CXX_THROW_EXPR = 133;
const CXX_NEW_EXPR = 134;
const CXX_DELETE_EXPR = 135;
const UNARY_EXPR = 136;
const OBJ_C_STRING_LITERAL = 137;
const OBJ_C_ENCODE_EXPR = 138;
const OBJ_C_SELECTOR_EXPR = 139;
const OBJ_C_PROTOCOL_EXPR = 140;
const OBJ_C_BRIDGED_CAST_EXPR = 141;
const PACK_EXPANSION_EXPR = 142;
const SIZE_OF_PACK_EXPR = 143;
const LAMBDA_EXPR = 144;
const OBJ_C_BOOL_LITERAL_EXPR = 145;
const OBJ_C_SELF_EXPR = 146;
const LAST_EXPR = DxcCursorKind::OBJ_C_SELF_EXPR.bits;
const FIRST_STMT = 200;
const UNEXPOSED_STMT = 200;
const LABEL_STMT = 201;
const COMPOUND_STMT = 202;
const CASE_STMT = 203;
const DEFAULT_STMT = 204;
const IF_STMT = 205;
const SWITCH_STMT = 206;
const WHILE_STMT = 207;
const DO_STMT = 208;
const FOR_STMT = 209;
const GOTO_STMT = 210;
const INDIRECT_GOTO_STMT = 211;
const CONTINUE_STMT = 212;
const BREAK_STMT = 213;
const RETURN_STMT = 214;
const GCC_ASM_STMT = 215;
const ASM_STMT = DxcCursorKind::GCC_ASM_STMT.bits;
const OBJ_C_AT_TRY_STMT = 216;
const OBJ_C_AT_CATCH_STMT = 217;
const OBJ_C_AT_FINALLY_STMT = 218;
const OBJ_C_AT_THROW_STMT = 219;
const OBJ_C_AT_SYNCHRONIZED_STMT = 220;
const OBJ_C_AUTORELEASE_POOL_STMT = 221;
const OBJ_C_FOR_COLLECTION_STMT = 222;
const CXX_CATCH_STMT = 223;
const CXX_TRY_STMT = 224;
const CXX_FOR_RANGE_STMT = 225;
const SEH_TRY_STMT = 226;
const SEH_EXCEPT_STMT = 227;
const SEH_FINALLY_STMT = 228;
const MS_ASM_STMT = 229;
const NULL_STMT = 230;
const DECL_STMT = 231;
const OMP_PARALLEL_DIRECTIVE = 232;
const OMP_SIMD_DIRECTIVE = 233;
const OMP_FOR_DIRECTIVE = 234;
const OMP_SECTIONS_DIRECTIVE = 235;
const OMP_SECTION_DIRECTIVE = 236;
const OMP_SINGLE_DIRECTIVE = 237;
const OMP_PARALLEL_FOR_DIRECTIVE = 238;
const OMP_PARALLEL_SECTIONS_DIRECTIVE = 239;
const OMP_TASK_DIRECTIVE = 240;
const OMP_MASTER_DIRECTIVE = 241;
const OMP_CRITICAL_DIRECTIVE = 242;
const OMP_TASKYIELD_DIRECTIVE = 243;
const OMP_BARRIER_DIRECTIVE = 244;
const OMP_TASKWAIT_DIRECTIVE = 245;
const OMP_FLUSH_DIRECTIVE = 246;
const SEH_LEAVE_STMT = 247;
const OMP_ORDERED_DIRECTIVE = 248;
const OMP_ATOMIC_DIRECTIVE = 249;
const OMP_FOR_SIMD_DIRECTIVE = 250;
const OMP_PARALLEL_FOR_SIMD_DIRECTIVE = 251;
const OMP_TARGET_DIRECTIVE = 252;
const OMP_TEAMS_DIRECTIVE = 253;
const OMP_TASKGROUP_DIRECTIVE = 254;
const OMP_CANCELLATION_POINT_DIRECTIVE = 255;
const OMP_CANCEL_DIRECTIVE = 256;
const LAST_STMT = DxcCursorKind::OMP_CANCEL_DIRECTIVE.bits;
const TRANSLATION_UNIT = 300;
const FIRST_ATTR = 400;
const UNEXPOSED_ATTR = 400;
const IB_ACTION_ATTR = 401;
const IB_OUTLET_ATTR = 402;
const IB_OUTLET_COLLECTION_ATTR = 403;
const CXX_FINAL_ATTR = 404;
const CXX_OVERRIDE_ATTR = 405;
const ANNOTATE_ATTR = 406;
const ASM_LABEL_ATTR = 407;
const PACKED_ATTR = 408;
const PURE_ATTR = 409;
const CONST_ATTR = 410;
const NO_DUPLICATE_ATTR = 411;
const CUDA_CONSTANT_ATTR = 412;
const CUDA_DEVICE_ATTR = 413;
const CUDA_GLOBAL_ATTR = 414;
const CUDA_HOST_ATTR = 415;
const CUDA_SHARED_ATTR = 416;
const LAST_ATTR = DxcCursorKind::CUDA_SHARED_ATTR.bits;
const PREPROCESSING_DIRECTIVE = 500;
const MACRO_DEFINITION = 501;
const MACRO_EXPANSION = 502;
const MACRO_INSTANTIATION = DxcCursorKind::MACRO_EXPANSION.bits;
const INCLUSION_DIRECTIVE = 503;
const FIRST_PREPROCESSING = DxcCursorKind::PREPROCESSING_DIRECTIVE.bits;
const LAST_PREPROCESSING = DxcCursorKind::INCLUSION_DIRECTIVE.bits;
const MODULE_IMPORT_DECL = 600;
const FIRST_EXTRA_DECL = DxcCursorKind::MODULE_IMPORT_DECL.bits;
const LAST_EXTRA_DECL = DxcCursorKind::MODULE_IMPORT_DECL.bits;
}
}
iid!(pub IID_IDxcDiagnostic = 0x4f76b234, 0x3659, 0x4d33, 0x99, 0xb0, 0x3b, 0x0d, 0xb9, 0x94, 0xb5, 0x64);
com_interface! {
interface IDxcDiagnostic: IUnknown{
iid: IID_IDxcDiagnostic,
vtable: IDxcDiagnosticVtbl,
fn format_diagnostic(options: DxcDiagnosticDisplayOptions, result: *mut LPSTR) -> HRESULT;
fn get_severity(result: *mut DxcDiagnosticSeverity) -> HRESULT;
fn get_location(result: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_spelling(result: *mut LPSTR) -> HRESULT;
fn get_category_text(result: *mut LPSTR) -> HRESULT;
fn get_num_ranges(result: *mut u32) -> HRESULT;
fn get_range_at(index: u32, result: *mut *mut IDxcSourceRange) -> HRESULT;
fn get_num_fix_its(result: *mut u32) -> HRESULT;
fn get_fix_it_at(index: u32, replacement_range: *mut *mut IDxcSourceRange, text: *mut LPSTR) -> HRESULT;
}
}
iid!(pub IID_IDxcInclusion = 0x0c364d65, 0xdf44, 0x4412, 0x88, 0x8e, 0x4e, 0x55, 0x2f, 0xc5, 0xe3, 0xd6);
com_interface! {
interface IDxcInclusion: IUnknown{
iid: IID_IDxcInclusion,
vtable: IDxcInclusionVtbl,
fn get_included_file(result: *mut *mut IDxcFile) -> HRESULT;
fn get_stack_length(result: *mut u32) -> HRESULT;
fn get_stack_item(index: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT;
}
}
iid!(pub IID_IDxcToken = 0x7f90b9ff, 0xa275, 0x4932, 0x97, 0xd8, 0x3c, 0xfd, 0x23, 0x44, 0x82, 0xa2);
com_interface! {
interface IDxcToken: IUnknown{
iid: IID_IDxcToken,
vtable: IDxcTokenVtbl,
fn get_kind(value: *mut DxcTokenKind) -> HRESULT;
fn get_location(value: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_extent(value: *mut *mut IDxcSourceRange) -> HRESULT;
fn get_spelling(value: *mut LPSTR) -> HRESULT;
}
}
iid!(pub IID_IDxcType = 0x2ec912fd, 0xb144, 0x4a15, 0xad, 0x0d, 0x1c, 0x54, 0x39, 0xc8, 0x1e, 0x46);
com_interface! {
interface IDxcType: IUnknown{
iid: IID_IDxcType,
vtable: IDxcTypeVtbl,
fn get_spelling(result: *mut LPSTR) -> HRESULT;
fn is_equal_to(other: *const IDxcType, result: *mut bool) -> HRESULT;
fn get_kind(result: *mut DxcTypeKind) -> HRESULT;
}
}
iid!(pub IID_IDxcSourceLocation = 0x8e7ddf1c, 0xd7d3, 0x4d69, 0xb2, 0x86, 0x85, 0xfc, 0xcb, 0xa1, 0xe0, 0xcf);
com_interface! {
interface IDxcSourceLocation: IUnknown{
iid: IID_IDxcSourceLocation,
vtable: IDxcSourceLocationVtbl,
fn is_equal_to(other: *const IDxcSourceLocation, result: *mut bool) -> HRESULT;
fn get_spelling_location(file: *mut *mut IDxcFile, line: *mut u32, col: *mut u32, offset: *mut u32) -> HRESULT;
fn is_null(result: *mut bool) -> HRESULT;
}
}
iid!(pub IID_IDxcSourceRange = 0xf1359b36, 0xa53f, 0x4e81, 0xb5, 0x14, 0xb6, 0xb8, 0x41, 0x22, 0xa1, 0x3f);
com_interface! {
interface IDxcSourceRange: IUnknown{
iid: IID_IDxcSourceRange,
vtable: IDxcSourceRangeVtbl,
fn is_null(value: *mut bool) -> HRESULT;
fn get_start(value: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_end(value: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_offsets(start_offset: *mut u32, end_offset: *mut u32) -> HRESULT;
}
}
iid!(pub IID_IDxcCursor = 0x1467b985, 0x288d, 0x4d2a, 0x80, 0xc1, 0xef, 0x89, 0xc4, 0x2c, 0x40, 0xbc);
com_interface! {
interface IDxcCursor: IUnknown{
iid: IID_IDxcCursor,
vtable: IDxcCursorVtbl,
fn get_extent(range: *mut *mut IDxcSourceRange) -> HRESULT;
fn get_location(result: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_kind(result: *mut DxcCursorKind) -> HRESULT;
fn get_kind_flags(result: *mut DxcCursorKindFlags) -> HRESULT;
fn get_semantic_parent(result: *mut*mut IDxcCursor) -> HRESULT;
fn get_lexical_parent(result:*mut*mut IDxcCursor) -> HRESULT;
fn get_cursor_type(result:*mut*mut IDxcType) -> HRESULT;
fn get_num_arguments(result:*mut i32) -> HRESULT;
fn get_argument_at(index: i32, result: *mut *mut IDxcCursor) -> HRESULT;
fn get_referenced_cursor(result:*mut *mut IDxcCursor) -> HRESULT;
fn get_definition_cursor(result:*mut *mut IDxcCursor) -> HRESULT;
fn find_references_in_file(file: *const IDxcFile, skip: u32, top:u32, result_length: *mut u32, result: *mut *mut *mut IDxcCursor) -> HRESULT;
fn get_spelling(result: *mut LPSTR) -> HRESULT;
fn is_equal_to(other: *const IDxcCursor, result:*mut bool) -> HRESULT;
fn is_null(result:*mut bool) -> HRESULT;
fn is_definition(result:*mut bool) -> HRESULT;
fn get_display_name(result:*mut BSTR) -> HRESULT;
fn get_qualified_name(include_template_args:bool, result:*mut BSTR) -> HRESULT;
fn get_formatted_name(formatting: DxcCursorFormatting, result:*mut BSTR) -> HRESULT;
fn get_children(skip: u32, top: u32, result_length:*mut u32, result:*mut*mut*mut IDxcCursor) -> HRESULT;
fn get_snapped_child(location: *const IDxcSourceLocation, result:*mut*mut IDxcCursor) -> HRESULT;
}
}
iid!(pub IID_IDxcUnsavedFile = 0x8ec00f98, 0x07d0, 0x4e60, 0x9d, 0x7c, 0x5a, 0x50, 0xb5, 0xb0, 0x01, 0x7f);
com_interface! {
interface IDxcUnsavedFile: IUnknown{
iid: IID_IDxcUnsavedFile,
vtable: IDxcUnsavedFileVtbl,
fn get_file_name(file_name: *mut LPSTR) -> HRESULT;
fn get_contents(contents: *mut LPSTR) -> HRESULT;
fn get_length(length: *mut u32) -> HRESULT;
}
}
iid!(pub IID_IDxcFile = 0xbb2fca9e, 0x1478, 0x47ba, 0xb0, 0x8c, 0x2c, 0x50, 0x2a, 0xda, 0x48, 0x95);
com_interface! {
interface IDxcFile: IUnknown{
iid: IID_IDxcFile,
vtable: IDxcFileVtbl,
fn get_name(result: *mut LPSTR) -> HRESULT;
fn is_equal_to(other: *const IDxcFile, result: *mut bool) -> HRESULT;
}
}
iid!(pub IID_IDxcTranslationUnit = 0x9677dee0, 0xc0e5, 0x46a1, 0x8b, 0x40, 0x3d, 0xb3, 0x16, 0x8b, 0xe6, 0x3d);
com_interface! {
interface IDxcTranslationUnit: IUnknown{
iid: IID_IDxcTranslationUnit,
vtable: IDxcTranslationUnitVtbl,
fn get_cursor(cursor: *mut *mut IDxcCursor) -> HRESULT;
fn tokenize(range: *const IDxcSourceRange, tokens: *mut *mut *mut IDxcToken, token_count: *mut u32) -> HRESULT;
fn get_location(file: *mut IDxcFile, line: u32, column: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_num_diagnostics(value: *mut u32) -> HRESULT;
fn get_diagnostic(index: u32, value: *mut *mut IDxcDiagnostic) -> HRESULT;
fn get_file(name: *const u8, result: *mut *mut IDxcFile) -> HRESULT;
fn get_file_name(result: *mut LPSTR) -> HRESULT;
fn reparse(unsaved_files: *mut *mut IDxcUnsavedFile, num_unsaved_files: u32) -> HRESULT;
fn get_cursor_for_location(location: *const IDxcSourceLocation, result: *mut *mut IDxcCursor) -> HRESULT;
fn get_location_for_offset(file: *const IDxcFile, offset: u32, result: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_skipped_ranges(file: *const IDxcFile, result_count: *mut u32, result: *mut *mut *mut IDxcSourceRange) -> HRESULT;
fn get_diagnostic_details(
index: u32, options: DxcDiagnosticDisplayOptions, error_code: *mut u32, error_line: *mut u32, error_column: *mut u32,
error_file: *mut BSTR, error_offset: *mut u32, error_length: *mut u32, error_message: *mut BSTR) -> HRESULT;
fn get_inclusion_list(result_count: *mut u32, result: *mut *mut *mut IDxcInclusion) -> HRESULT;
}
}
iid!(pub IID_IDxcIndex = 0x937824a0, 0x7f5a, 0x4815, 0x9b, 0xa, 0x7c, 0xc0, 0x42, 0x4f, 0x41, 0x73);
com_interface! {
interface IDxcIndex: IUnknown{
iid: IID_IDxcIndex,
vtable: IDxcIndexVtbl,
fn set_global_options(options: DxcGlobalOptions) -> HRESULT;
fn get_global_options(options: *mut DxcGlobalOptions) -> HRESULT;
fn parse_translation_unit(
source_filename: *const u8,
command_line_args: *const *const u8,
num_command_line_args: i32,
unsaved_files: *const *const IDxcUnsavedFile,
num_unsaved_files: u32,
options: DxcTranslationUnitFlags,
translation_unit: *mut *mut IDxcTranslationUnit) -> HRESULT;
}
}
iid!(pub IID_IDxcIntelliSense = 0xb1f99513, 0x46d6, 0x4112, 0x81, 0x69, 0xdd, 0x0d, 0x60, 0x53, 0xf1, 0x7d);
com_interface! {
interface IDxcIntelliSense: IUnknown{
iid: IID_IDxcIntelliSense,
vtable: IDxcIntelliSenseVtbl,
fn create_index(index: *mut *mut IDxcIndex) -> HRESULT;
fn get_null_location(location: *mut *mut IDxcSourceLocation) -> HRESULT;
fn get_null_range(location: *mut *mut IDxcSourceRange) -> HRESULT;
fn get_range( start: *const IDxcSourceLocation, end: *const IDxcSourceLocation, location: *mut *mut IDxcSourceRange) -> HRESULT;
fn get_default_diagnostic_display_options(value: *mut DxcDiagnosticDisplayOptions) -> HRESULT;
fn get_default_editing_tu_options(value: *mut DxcTranslationUnitFlags) -> HRESULT;
fn create_unsaved_file(file_name: LPCSTR, contents: LPCSTR, content_length: u32 , result: *mut *mut IDxcUnsavedFile) -> HRESULT;
}
}
iid!(pub CLSID_DxcIntelliSense = 0x3047833c, 0xd1c0, 0x4b8e, 0x9d, 0x40, 0x10, 0x28, 0x78, 0x60, 0x59, 0x85);

View file

@ -0,0 +1,5 @@
mod ffi;
mod wrapper;
pub use ffi::*;
pub use wrapper::*;

View file

@ -0,0 +1,436 @@
use crate::intellisense::ffi::*;
use crate::os::{CoTaskMemFree, BSTR, LPSTR};
use crate::utils::Result;
use crate::wrapper::Dxc;
use com_rs::ComPtr;
use std::ffi::CString;
#[derive(Debug)]
pub struct DxcIntellisense {
inner: ComPtr<IDxcIntelliSense>,
}
impl DxcIntellisense {
fn new(inner: ComPtr<IDxcIntelliSense>) -> Self {
Self { inner }
}
pub fn get_default_editing_tu_options(&self) -> Result<DxcTranslationUnitFlags> {
let mut options: DxcTranslationUnitFlags = DxcTranslationUnitFlags::NONE;
unsafe { self.inner.get_default_editing_tu_options(&mut options) }
.result_with_success(options)
}
pub fn create_index(&self) -> Result<DxcIndex> {
let mut index: ComPtr<IDxcIndex> = ComPtr::new();
unsafe { self.inner.create_index(index.as_mut_ptr()) }.result()?;
Ok(DxcIndex::new(index))
}
pub fn create_unsaved_file(&self, file_name: &str, contents: &str) -> Result<DxcUnsavedFile> {
let c_file_name = CString::new(file_name).expect("Failed to convert `file_name`");
let c_contents = CString::new(contents).expect("Failed to convert `contents`");
let mut file: ComPtr<IDxcUnsavedFile> = ComPtr::new();
unsafe {
self.inner.create_unsaved_file(
c_file_name.as_ptr(),
c_contents.as_ptr(),
contents.len() as u32,
file.as_mut_ptr(),
)
}
.result()?;
Ok(DxcUnsavedFile::new(file))
}
}
#[derive(Debug)]
pub struct DxcIndex {
inner: ComPtr<IDxcIndex>,
}
impl DxcIndex {
fn new(inner: ComPtr<IDxcIndex>) -> Self {
Self { inner }
}
}
impl DxcIndex {
pub fn parse_translation_unit(
&self,
source_filename: &str,
args: &[&str],
unsaved_files: &[&DxcUnsavedFile],
options: DxcTranslationUnitFlags,
) -> Result<DxcTranslationUnit> {
let c_source_filename =
CString::new(source_filename).expect("Failed to convert `source_filename`");
let mut uf = vec![];
for unsaved_file in unsaved_files {
uf.push(unsaved_file.inner.as_ptr());
}
let mut c_args: Vec<CString> = vec![];
let mut cliargs = vec![];
for arg in args.iter() {
let c_arg = CString::new(*arg).expect("Failed to convert `arg`");
cliargs.push(c_arg.as_ptr().cast());
c_args.push(c_arg);
}
let mut tu: ComPtr<IDxcTranslationUnit> = ComPtr::new();
unsafe {
self.inner.parse_translation_unit(
c_source_filename.as_ptr().cast(),
cliargs.as_ptr(),
cliargs.len() as i32,
uf.as_ptr(),
uf.len() as u32,
options,
tu.as_mut_ptr(),
)
}
.result()?;
Ok(DxcTranslationUnit::new(tu))
}
}
#[derive(Debug)]
pub struct DxcUnsavedFile {
inner: ComPtr<IDxcUnsavedFile>,
}
impl DxcUnsavedFile {
pub fn get_length(&self) -> Result<u32> {
let mut length: u32 = 0;
unsafe { self.inner.get_length(&mut length) }.result_with_success(length)
}
fn new(inner: ComPtr<IDxcUnsavedFile>) -> Self {
DxcUnsavedFile { inner }
}
}
#[derive(Debug)]
pub struct DxcTranslationUnit {
inner: ComPtr<IDxcTranslationUnit>,
}
impl DxcTranslationUnit {
fn new(inner: ComPtr<IDxcTranslationUnit>) -> Self {
DxcTranslationUnit { inner }
}
pub fn get_file(&self, name: &[u8]) -> Result<DxcFile> {
let mut file: ComPtr<IDxcFile> = ComPtr::new();
unsafe { self.inner.get_file(name.as_ptr(), file.as_mut_ptr()) }.result()?;
Ok(DxcFile::new(file))
}
pub fn get_cursor(&self) -> Result<DxcCursor> {
let mut cursor: ComPtr<IDxcCursor> = ComPtr::new();
unsafe { self.inner.get_cursor(cursor.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(cursor))
}
}
#[derive(Debug)]
pub struct DxcCursor {
inner: ComPtr<IDxcCursor>,
}
impl DxcCursor {
fn new(inner: ComPtr<IDxcCursor>) -> Self {
DxcCursor { inner }
}
pub fn get_children(&self, skip: u32, max_count: u32) -> Result<Vec<DxcCursor>> {
let mut result: *mut *mut IDxcCursor = std::ptr::null_mut();
let mut result_length: u32 = 0;
unsafe {
self.inner
.get_children(skip, max_count, &mut result_length, &mut result)
}
.result()?;
// get_children allocates a buffer to pass the result in.
let child_cursors = unsafe { std::slice::from_raw_parts(result, result_length as usize) }
.iter()
.map(|&ptr| {
let mut childcursor = ComPtr::<IDxcCursor>::new();
*childcursor.as_mut_ptr() = ptr;
DxcCursor::new(childcursor)
})
.collect::<Vec<_>>();
unsafe { CoTaskMemFree(result.cast()) };
Ok(child_cursors)
}
pub fn get_all_children(&self) -> Result<Vec<DxcCursor>> {
const MAX_CHILDREN_PER_CHUNK: u32 = 10;
let mut children = vec![];
loop {
let res = self.get_children(children.len() as u32, MAX_CHILDREN_PER_CHUNK)?;
let res_len = res.len();
children.extend(res);
if res_len < MAX_CHILDREN_PER_CHUNK as usize {
break Ok(children);
}
}
}
pub fn get_extent(&self) -> Result<DxcSourceRange> {
let mut range: ComPtr<IDxcSourceRange> = ComPtr::new();
unsafe { self.inner.get_extent(range.as_mut_ptr()) }.result()?;
Ok(DxcSourceRange::new(range))
}
pub fn get_location(&self) -> Result<DxcSourceLocation> {
let mut location: ComPtr<IDxcSourceLocation> = ComPtr::new();
unsafe { self.inner.get_location(location.as_mut_ptr()) }.result()?;
Ok(DxcSourceLocation::new(location))
}
pub fn get_display_name(&self) -> Result<String> {
let mut name: BSTR = std::ptr::null_mut();
unsafe { self.inner.get_display_name(&mut name) }.result()?;
Ok(crate::utils::from_bstr(name))
}
pub fn get_formatted_name(&self, formatting: DxcCursorFormatting) -> Result<String> {
let mut name: BSTR = std::ptr::null_mut();
unsafe { self.inner.get_formatted_name(formatting, &mut name) }.result()?;
Ok(crate::utils::from_bstr(name))
}
pub fn get_qualified_name(&self, include_template_args: bool) -> Result<String> {
let mut name: BSTR = std::ptr::null_mut();
unsafe {
self.inner
.get_qualified_name(include_template_args, &mut name)
}
.result()?;
Ok(crate::utils::from_bstr(name))
}
pub fn get_kind(&self) -> Result<DxcCursorKind> {
let mut cursor_kind: DxcCursorKind = DxcCursorKind::UNEXPOSED_DECL;
unsafe { self.inner.get_kind(&mut cursor_kind) }.result_with_success(cursor_kind)
}
pub fn get_kind_flags(&self) -> Result<DxcCursorKindFlags> {
let mut cursor_kind_flags: DxcCursorKindFlags = DxcCursorKindFlags::NONE;
unsafe { self.inner.get_kind_flags(&mut cursor_kind_flags) }
.result_with_success(cursor_kind_flags)
}
pub fn get_semantic_parent(&self) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe { self.inner.get_semantic_parent(inner.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(inner))
}
pub fn get_lexical_parent(&self) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe { self.inner.get_lexical_parent(inner.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(inner))
}
pub fn get_cursor_type(&self) -> Result<DxcType> {
let mut inner = ComPtr::<IDxcType>::new();
unsafe { self.inner.get_cursor_type(inner.as_mut_ptr()) }.result()?;
Ok(DxcType::new(inner))
}
pub fn get_num_arguments(&self) -> Result<i32> {
let mut result: i32 = 0;
unsafe { self.inner.get_num_arguments(&mut result) }.result_with_success(result)
}
pub fn get_argument_at(&self, index: i32) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe { self.inner.get_argument_at(index, inner.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(inner))
}
pub fn get_referenced_cursor(&self) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe { self.inner.get_referenced_cursor(inner.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(inner))
}
pub fn get_definition_cursor(&self) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe { self.inner.get_definition_cursor(inner.as_mut_ptr()) }.result()?;
Ok(DxcCursor::new(inner))
}
pub fn find_references_in_file(
&self,
file: &DxcFile,
skip: u32,
top: u32,
) -> Result<Vec<DxcCursor>> {
let mut result: *mut *mut IDxcCursor = std::ptr::null_mut();
let mut result_length: u32 = 0;
unsafe {
self.inner.find_references_in_file(
file.inner.as_ptr(),
skip,
top,
&mut result_length,
&mut result,
)
}
.result()?;
// find_references_in_file allocates a buffer to pass the result in.
let child_cursors = unsafe { std::slice::from_raw_parts(result, result_length as usize) }
.iter()
.map(|&ptr| {
let mut childcursor = ComPtr::<IDxcCursor>::new();
*childcursor.as_mut_ptr() = ptr;
DxcCursor::new(childcursor)
})
.collect::<Vec<_>>();
unsafe { CoTaskMemFree(result.cast()) };
Ok(child_cursors)
}
pub fn get_spelling(&self) -> Result<String> {
let mut spelling: LPSTR = std::ptr::null_mut();
unsafe { self.inner.get_spelling(&mut spelling) }.result()?;
Ok(crate::utils::from_lpstr(spelling))
}
pub fn is_equal_to(&self, other: &DxcCursor) -> Result<bool> {
let mut result: bool = false;
unsafe { self.inner.is_equal_to(other.inner.as_ptr(), &mut result) }
.result_with_success(result)
}
pub fn is_null(&mut self) -> Result<bool> {
let mut result: bool = false;
unsafe { IDxcCursor::is_null(&self.inner, &mut result) }.result_with_success(result)
}
pub fn is_definition(&self) -> Result<bool> {
let mut result: bool = false;
unsafe { self.inner.is_definition(&mut result) }.result_with_success(result)
}
pub fn get_snapped_child(&self, location: &DxcSourceLocation) -> Result<DxcCursor> {
let mut inner = ComPtr::<IDxcCursor>::new();
unsafe {
self.inner
.get_snapped_child(location.inner.as_ptr(), inner.as_mut_ptr())
}
.result()?;
Ok(DxcCursor::new(inner))
}
pub fn get_source<'a>(&self, source: &'a str) -> Result<&'a str> {
let range = self.get_extent()?;
let DxcSourceOffsets {
start_offset,
end_offset,
} = range.get_offsets()?;
let source_range = (start_offset as usize)..(end_offset as usize);
Ok(&source[source_range])
}
}
#[derive(Debug)]
pub struct DxcType {
inner: ComPtr<IDxcType>,
}
impl DxcType {
fn new(inner: ComPtr<IDxcType>) -> Self {
DxcType { inner }
}
pub fn get_spelling(&self) -> Result<String> {
let mut spelling: LPSTR = std::ptr::null_mut();
unsafe { self.inner.get_spelling(&mut spelling) }
.result_with_success(crate::utils::from_lpstr(spelling))
}
}
#[derive(Debug)]
pub struct DxcSourceLocation {
inner: ComPtr<IDxcSourceLocation>,
}
impl DxcSourceLocation {
fn new(inner: ComPtr<IDxcSourceLocation>) -> Self {
DxcSourceLocation { inner }
}
}
#[derive(Debug)]
pub struct DxcSourceOffsets {
pub start_offset: u32,
pub end_offset: u32,
}
#[derive(Debug)]
pub struct DxcSourceRange {
inner: ComPtr<IDxcSourceRange>,
}
impl DxcSourceRange {
pub fn get_offsets(&self) -> Result<DxcSourceOffsets> {
let mut start_offset: u32 = 0;
let mut end_offset: u32 = 0;
unsafe { self.inner.get_offsets(&mut start_offset, &mut end_offset) }.result_with_success(
DxcSourceOffsets {
start_offset,
end_offset,
},
)
}
}
impl DxcSourceRange {
fn new(inner: ComPtr<IDxcSourceRange>) -> Self {
DxcSourceRange { inner }
}
}
#[derive(Debug)]
pub struct DxcFile {
inner: ComPtr<IDxcFile>,
}
impl DxcFile {
fn new(inner: ComPtr<IDxcFile>) -> Self {
DxcFile { inner }
}
}
impl Dxc {
pub fn create_intellisense(&self) -> Result<DxcIntellisense> {
let mut intellisense: ComPtr<IDxcIntelliSense> = ComPtr::new();
self.get_dxc_create_instance()?(
&CLSID_DxcIntelliSense,
&IID_IDxcIntelliSense,
intellisense.as_mut_ptr(),
)
.result()?;
Ok(DxcIntellisense::new(intellisense))
}
}

50
third-party/vendor/hassle-rs/src/lib.rs vendored Normal file
View file

@ -0,0 +1,50 @@
#![allow(dead_code)]
#![allow(non_upper_case_globals)]
#![allow(
clippy::transmute_ptr_to_ptr, // Introduced by com-rs
clippy::too_many_arguments, // We're wrapping and API outside of our control
)]
//! # Hassle
//!
//! This crate provides an FFI layer and idiomatic rust wrappers for the new [DirectXShaderCompiler](https://github.com/Microsoft/DirectXShaderCompiler) library.
//!
//! ## Simple example
//!
//! ```rust
//! use hassle_rs::compile_hlsl;
//!
//! let code = "
//! Texture2D<float4> g_input : register(t0, space0);
//! RWTexture2D<float4> g_output : register(u0, space0);
//!
//! [numthreads(8, 8, 1)]
//! void copyCs(uint3 dispatchThreadId : SV_DispatchThreadID)
//! {
//! g_output[dispatchThreadId.xy] = g_input[dispatchThreadId.xy];
//! }";
//!
//! let ir = compile_hlsl(
//! "shader_filename.hlsl",
//! code,
//! "copyCs",
//! "cs_6_1",
//! &vec!["-spirv"],
//! &vec![
//! ("MY_DEFINE", Some("Value")),
//! ("OTHER_DEFINE", None)
//! ],
//! );
//! ```
pub mod fake_sign;
pub mod ffi;
pub mod os;
pub mod utils;
pub mod wrapper;
pub mod intellisense;
pub use crate::ffi::*;
pub use crate::utils::{compile_hlsl, fake_sign_dxil_in_place, validate_dxil, HassleError, Result};
pub use crate::wrapper::*;

121
third-party/vendor/hassle-rs/src/os.rs vendored Normal file
View file

@ -0,0 +1,121 @@
// Allow uppercase names to match Windows API:
#![allow(clippy::upper_case_acronyms)]
#[cfg(windows)]
mod os_defs {
pub use winapi::shared::{
ntdef::{HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR, WCHAR},
wtypes::BSTR,
};
pub use winapi::um::combaseapi::CoTaskMemFree;
pub use winapi::um::oleauto::{SysFreeString, SysStringLen};
}
#[cfg(not(windows))]
mod os_defs {
pub type CHAR = std::os::raw::c_char;
pub type UINT = u32;
pub type WCHAR = widestring::WideChar;
pub type OLECHAR = WCHAR;
pub type LPSTR = *mut CHAR;
pub type LPWSTR = *mut WCHAR;
pub type LPCSTR = *const CHAR;
pub type LPCWSTR = *const WCHAR;
pub type BSTR = *mut OLECHAR;
pub type LPBSTR = *mut BSTR;
pub type HRESULT = i32;
/// Returns a mutable pointer to the length prefix of the string
fn len_ptr(p: BSTR) -> *mut UINT {
// The first four bytes before the pointer contain the length prefix:
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
unsafe { p.cast::<UINT>().offset(-1) }
}
#[allow(non_snake_case)]
/// # Safety
/// `p` must be a valid pointer to an allocation made with `malloc`, or null.
pub unsafe fn CoTaskMemFree(p: *mut libc::c_void) {
// https://github.com/microsoft/DirectXShaderCompiler/blob/56e22b30c5e43632f56a1f97865f37108ec35463/include/dxc/Support/WinAdapter.h#L46
if !p.is_null() {
libc::free(p)
}
}
#[allow(non_snake_case)]
/// # Safety
/// `p` must be a valid pointer to an allocation made with `malloc`, or null.
pub unsafe fn SysFreeString(p: BSTR) {
// https://github.com/microsoft/DirectXShaderCompiler/blob/56e22b30c5e43632f56a1f97865f37108ec35463/lib/DxcSupport/WinAdapter.cpp#L50-L53
if !p.is_null() {
libc::free(len_ptr(p).cast::<_>())
}
}
#[allow(non_snake_case)]
/// Returns the size of `p` in bytes, excluding terminating NULL character
///
/// # Safety
/// `p` must be a valid pointer to a [`BSTR`] with size-prefix in the `4` leading bytes, or null.
///
/// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
pub unsafe fn SysStringByteLen(p: BSTR) -> UINT {
if p.is_null() {
0
} else {
*len_ptr(p)
}
}
#[allow(non_snake_case)]
/// Returns the size of `p` in characters, excluding terminating NULL character
///
/// # Safety
/// `p` must be a valid pointer to a [`BSTR`] with size-prefix in the `4` leading bytes, or null.
///
/// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
pub unsafe fn SysStringLen(p: BSTR) -> UINT {
SysStringByteLen(p) / std::mem::size_of::<OLECHAR>() as UINT
}
}
pub use os_defs::*;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
#[must_use]
pub struct HRESULT(pub os_defs::HRESULT);
impl HRESULT {
pub fn is_err(&self) -> bool {
self.0 < 0
}
}
impl From<i32> for HRESULT {
fn from(v: i32) -> Self {
Self(v)
}
}
impl std::fmt::Debug for HRESULT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<Self as std::fmt::Display>::fmt(self, f)
}
}
impl std::fmt::Display for HRESULT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{:#x}", self))
}
}
impl std::fmt::LowerHex for HRESULT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let prefix = if f.alternate() { "0x" } else { "" };
let bare_hex = format!("{:x}", self.0.abs());
// https://stackoverflow.com/a/44712309
f.pad_integral(self.0 >= 0, prefix, &bare_hex)
// <i32 as std::fmt::LowerHex>::fmt(&self.0, f)
}
}

View file

@ -0,0 +1,50 @@
#[cfg(not(windows))]
use crate::os::HRESULT;
use com_rs::{com_interface, IUnknown, IID};
extern "C" {
static IID_IUnknown: IID;
}
#[cfg(not(windows))]
// Steal the interface ID from IUnknown:
com_interface! {
/// Insert complete object and deleting destructor on non-Windows platforms, where Dxc shims IUnknown in WinAdapter.
/// This requires a virtual destructor (delete is actually used on the base class) which unfortunately makes the struct
/// binary incompatible.
///
/// See the third and fourth entry:
/// ```cmd
/// vtable for 'DxcLibrary' @ 0x7ffff7cbc5f8 (subobject @ 0x5555556bb9e0):
/// [0]: 0x7ffff6a56d40 <DxcLibrary::QueryInterface(_GUID const&, void**)>
/// [1]: 0x7ffff6a56d20 <DxcLibrary::AddRef()>
/// [2]: 0x7ffff6a56d30 <DxcLibrary::Release()>
/// [3]: 0x7ffff6b36bc0 <IUnknown::~IUnknown()>
/// [4]: 0x7ffff6a57130 <DxcLibrary::~DxcLibrary()>
/// [5]: 0x7ffff6a56d50 <DxcLibrary::SetMalloc(IMalloc*)>
/// [6]: 0x7ffff6a56d60 <DxcLibrary::CreateBlobFromBlob(IDxcBlob*, unsigned int, unsigned int, IDxcBlob**)>
/// [7]: 0x7ffff6a56d70 <DxcLibrary::CreateBlobFromFile(wchar_t const*, unsigned int*, IDxcBlobEncoding**)>
/// [8]: 0x7ffff6a56d80 <DxcLibrary::CreateBlobWithEncodingFromPinned(void const*, unsigned int, unsigned int, IDxcBlobEncoding**)>
/// [9]: 0x7ffff6a56d90 <DxcLibrary::CreateBlobWithEncodingOnHeapCopy(void const*, unsigned int, unsigned int, IDxcBlobEncoding**)>
/// [10]: 0x7ffff6a56da0 <DxcLibrary::CreateBlobWithEncodingOnMalloc(void const*, IMalloc*, unsigned int, unsigned int, IDxcBlobEncoding**)>
/// [11]: 0x7ffff6a56db0 <DxcLibrary::CreateIncludeHandler(IDxcIncludeHandler**)>
/// [12]: 0x7ffff6a56dc0 <DxcLibrary::CreateStreamFromBlobReadOnly(IDxcBlob*, IStream**)>
/// [13]: 0x7ffff6a56dd0 <DxcLibrary::GetBlobAsUtf8(IDxcBlob*, IDxcBlobEncoding**)>
/// [14]: 0x7ffff6a56e90 <DxcLibrary::GetBlobAsUtf16(IDxcBlob*, IDxcBlobEncoding**)>
/// ```
interface IDxcUnknownShim: IUnknown {
iid: IID_IUnknown,
vtable: IDxcUnknownShimVtbl,
fn complete_object_destructor() -> HRESULT;
fn deleting_destructor() -> HRESULT;
}
}
#[cfg(windows)]
com_interface! {
/// Forwards to IUnknown. No-op on Windows
interface IDxcUnknownShim: IUnknown {
iid: IID_IUnknown,
vtable: IDxcUnknownShimVtbl,
}
}

View file

@ -0,0 +1,179 @@
use std::path::PathBuf;
use crate::os::{SysFreeString, SysStringLen, BSTR, HRESULT, LPCSTR, LPCWSTR, WCHAR};
use crate::wrapper::*;
use thiserror::Error;
pub(crate) fn to_wide(msg: &str) -> Vec<WCHAR> {
widestring::WideCString::from_str(msg)
.unwrap()
.into_vec_with_nul()
}
pub(crate) fn from_wide(wide: LPCWSTR) -> String {
unsafe {
widestring::WideCStr::from_ptr_str(wide)
.to_string()
.expect("widestring decode failed")
}
}
pub(crate) fn from_bstr(string: BSTR) -> String {
unsafe {
let len = SysStringLen(string) as usize;
let result = widestring::WideStr::from_ptr(string, len)
.to_string()
.expect("widestring decode failed");
SysFreeString(string);
result
}
}
pub(crate) fn from_lpstr(string: LPCSTR) -> String {
unsafe {
let len = (0..).take_while(|&i| *string.offset(i) != 0).count();
let slice: &[u8] = std::slice::from_raw_parts(string.cast(), len);
std::str::from_utf8(slice).map(|s| s.to_owned()).unwrap()
}
}
struct DefaultIncludeHandler {}
impl DxcIncludeHandler for DefaultIncludeHandler {
fn load_source(&mut self, filename: String) -> Option<String> {
use std::io::Read;
match std::fs::File::open(filename) {
Ok(mut f) => {
let mut content = String::new();
f.read_to_string(&mut content).ok()?;
Some(content)
}
Err(_) => None,
}
}
}
#[derive(Error, Debug)]
pub enum HassleError {
#[error("Win32 error: {0:x}")]
Win32Error(HRESULT),
#[error("{0}")]
CompileError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Failed to load library {filename:?}: {inner:?}")]
LoadLibraryError {
filename: PathBuf,
#[source]
inner: libloading::Error,
},
#[error("LibLoading error: {0:?}")]
LibLoadingError(#[from] libloading::Error),
#[error("Windows only")]
WindowsOnly(String),
}
pub type Result<T, E = HassleError> = std::result::Result<T, E>;
impl HRESULT {
/// Turns an [`HRESULT`] from the COM [`crate::ffi`] API declaration
/// into a [`Result`] containing [`HassleError`].
pub fn result(self) -> Result<()> {
self.result_with_success(())
}
/// Turns an [`HRESULT`] from the COM [`crate::ffi`] API declaration
/// into a [`Result`] containing [`HassleError`], with the desired value.
///
/// Note that `v` is passed by value and is not a closure that is executed
/// lazily. Use the short-circuiting `?` operator for such cases:
/// ```no_run
/// let mut blob: ComPtr<IDxcBlob> = ComPtr::new();
/// unsafe { self.inner.get_result(blob.as_mut_ptr()) }.result()?;
/// Ok(DxcBlob::new(blob))
/// ```
pub fn result_with_success<T>(self, v: T) -> Result<T> {
if self.is_err() {
Err(HassleError::Win32Error(self))
} else {
Ok(v)
}
}
}
/// Helper function to directly compile a HLSL shader to an intermediate language,
/// this function expects `dxcompiler.dll` to be available in the current
/// executable environment.
///
/// Specify -spirv as one of the `args` to compile to SPIR-V
/// `dxc_path` can point to a library directly or the directory containing the library,
/// in which case the appended filename depends on the platform.
pub fn compile_hlsl(
source_name: &str,
shader_text: &str,
entry_point: &str,
target_profile: &str,
args: &[&str],
defines: &[(&str, Option<&str>)],
) -> Result<Vec<u8>> {
let dxc = Dxc::new(None)?;
let compiler = dxc.create_compiler()?;
let library = dxc.create_library()?;
let blob = library.create_blob_with_encoding_from_str(shader_text)?;
let result = compiler.compile(
&blob,
source_name,
entry_point,
target_profile,
args,
Some(&mut DefaultIncludeHandler {}),
defines,
);
match result {
Err(result) => {
let error_blob = result.0.get_error_buffer()?;
Err(HassleError::CompileError(
library.get_blob_as_string(&error_blob.into())?,
))
}
Ok(result) => {
let result_blob = result.get_result()?;
Ok(result_blob.to_vec())
}
}
}
/// Helper function to validate a DXIL binary independent from the compilation process,
/// this function expects `dxcompiler.dll` and `dxil.dll` to be available in the current
/// execution environment.
///
/// `dxil.dll` is only available on Windows.
pub fn validate_dxil(data: &[u8]) -> Result<Vec<u8>, HassleError> {
let dxc = Dxc::new(None)?;
let dxil = Dxil::new(None)?;
let validator = dxil.create_validator()?;
let library = dxc.create_library()?;
let blob_encoding = library.create_blob_with_encoding(data)?;
match validator.validate(blob_encoding.into()) {
Ok(blob) => Ok(blob.to_vec()),
Err(result) => {
let error_blob = result.0.get_error_buffer()?;
Err(HassleError::ValidationError(
library.get_blob_as_string(&error_blob.into())?,
))
}
}
}
pub use crate::fake_sign::fake_sign_dxil_in_place;

View file

@ -0,0 +1,698 @@
#![allow(
clippy::too_many_arguments,
clippy::new_without_default,
clippy::type_complexity
)]
use crate::ffi::*;
use crate::os::{HRESULT, LPCWSTR, LPWSTR, WCHAR};
use crate::utils::{from_wide, to_wide, HassleError, Result};
use com_rs::ComPtr;
use libloading::{Library, Symbol};
use std::path::{Path, PathBuf};
use std::pin::Pin;
#[derive(Debug)]
pub struct DxcBlob {
inner: ComPtr<IDxcBlob>,
}
impl DxcBlob {
fn new(inner: ComPtr<IDxcBlob>) -> Self {
Self { inner }
}
pub fn as_slice<T>(&self) -> &[T] {
unsafe {
std::slice::from_raw_parts(
self.inner.get_buffer_pointer().cast(),
self.inner.get_buffer_size() / std::mem::size_of::<T>(),
)
}
}
pub fn as_mut_slice<T>(&mut self) -> &mut [T] {
unsafe {
std::slice::from_raw_parts_mut(
self.inner.get_buffer_pointer().cast(),
self.inner.get_buffer_size() / std::mem::size_of::<T>(),
)
}
}
pub fn to_vec<T>(&self) -> Vec<T>
where
T: Clone,
{
self.as_slice().to_vec()
}
}
impl AsRef<[u8]> for DxcBlob {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsMut<[u8]> for DxcBlob {
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_slice()
}
}
#[derive(Debug)]
pub struct DxcBlobEncoding {
inner: ComPtr<IDxcBlobEncoding>,
}
impl DxcBlobEncoding {
fn new(inner: ComPtr<IDxcBlobEncoding>) -> Self {
Self { inner }
}
}
impl From<DxcBlobEncoding> for DxcBlob {
fn from(encoded_blob: DxcBlobEncoding) -> Self {
DxcBlob::new((&encoded_blob.inner).into())
}
}
#[derive(Debug)]
pub struct DxcOperationResult {
inner: ComPtr<IDxcOperationResult>,
}
impl DxcOperationResult {
fn new(inner: ComPtr<IDxcOperationResult>) -> Self {
Self { inner }
}
pub fn get_status(&self) -> Result<u32> {
let mut status: u32 = 0;
unsafe { self.inner.get_status(&mut status) }.result_with_success(status)
}
pub fn get_result(&self) -> Result<DxcBlob> {
let mut blob: ComPtr<IDxcBlob> = ComPtr::new();
unsafe { self.inner.get_result(blob.as_mut_ptr()) }.result()?;
Ok(DxcBlob::new(blob))
}
pub fn get_error_buffer(&self) -> Result<DxcBlobEncoding> {
let mut blob: ComPtr<IDxcBlobEncoding> = ComPtr::new();
unsafe { self.inner.get_error_buffer(blob.as_mut_ptr()) }.result()?;
Ok(DxcBlobEncoding::new(blob))
}
}
pub trait DxcIncludeHandler {
fn load_source(&mut self, filename: String) -> Option<String>;
}
#[repr(C)]
struct DxcIncludeHandlerWrapperVtbl {
query_interface: extern "system" fn(
*const com_rs::IUnknown,
&com_rs::IID,
*mut *mut core::ffi::c_void,
) -> HRESULT,
add_ref: extern "system" fn(*const com_rs::IUnknown) -> HRESULT,
release: extern "system" fn(*const com_rs::IUnknown) -> HRESULT,
load_source: extern "system" fn(*mut com_rs::IUnknown, LPCWSTR, *mut *mut IDxcBlob) -> HRESULT,
}
#[repr(C)]
struct DxcIncludeHandlerWrapper<'a, 'i> {
vtable: Box<DxcIncludeHandlerWrapperVtbl>,
handler: &'i mut dyn DxcIncludeHandler,
pinned: Vec<Pin<String>>,
library: &'a DxcLibrary,
}
impl<'a, 'i> DxcIncludeHandlerWrapper<'a, 'i> {
extern "system" fn query_interface(
_me: *const com_rs::IUnknown,
_rrid: &com_rs::IID,
_ppv_obj: *mut *mut core::ffi::c_void,
) -> HRESULT {
HRESULT(0) // dummy impl
}
extern "system" fn add_ref(_me: *const com_rs::IUnknown) -> HRESULT {
HRESULT(0) // dummy impl
}
extern "system" fn release(_me: *const com_rs::IUnknown) -> HRESULT {
HRESULT(0) // dummy impl
}
extern "system" fn load_source(
me: *mut com_rs::IUnknown,
filename: LPCWSTR,
include_source: *mut *mut IDxcBlob,
) -> HRESULT {
let me = me.cast::<DxcIncludeHandlerWrapper>();
let filename = crate::utils::from_wide(filename);
let source = unsafe { (*me).handler.load_source(filename) };
if let Some(source) = source {
let source = Pin::new(source);
let mut blob = unsafe {
(*me)
.library
.create_blob_with_encoding_from_str(&source)
.unwrap()
};
unsafe {
blob.inner.add_ref();
*include_source = *blob.inner.as_mut_ptr();
(*me).pinned.push(source);
}
0
} else {
-2_147_024_894 // ERROR_FILE_NOT_FOUND / 0x80070002
}
.into()
}
}
#[derive(Debug)]
pub struct DxcCompiler {
inner: ComPtr<IDxcCompiler2>,
library: DxcLibrary,
}
impl DxcCompiler {
fn new(inner: ComPtr<IDxcCompiler2>, library: DxcLibrary) -> Self {
Self { inner, library }
}
fn prep_defines(
defines: &[(&str, Option<&str>)],
wide_defines: &mut Vec<(Vec<WCHAR>, Vec<WCHAR>)>,
dxc_defines: &mut Vec<DxcDefine>,
) {
for (name, value) in defines {
if value.is_none() {
wide_defines.push((to_wide(name), to_wide("1")));
} else {
wide_defines.push((to_wide(name), to_wide(value.unwrap())));
}
}
for (ref name, ref value) in wide_defines {
dxc_defines.push(DxcDefine {
name: name.as_ptr(),
value: value.as_ptr(),
});
}
}
fn prep_args(args: &[&str], wide_args: &mut Vec<Vec<WCHAR>>, dxc_args: &mut Vec<LPCWSTR>) {
for a in args {
wide_args.push(to_wide(a));
}
for a in wide_args {
dxc_args.push(a.as_ptr());
}
}
fn prep_include_handler<'a, 'i>(
library: &'a DxcLibrary,
include_handler: Option<&'i mut dyn DxcIncludeHandler>,
) -> Option<Box<DxcIncludeHandlerWrapper<'a, 'i>>> {
if let Some(include_handler) = include_handler {
let vtable = DxcIncludeHandlerWrapperVtbl {
query_interface: DxcIncludeHandlerWrapper::query_interface,
add_ref: DxcIncludeHandlerWrapper::add_ref,
release: DxcIncludeHandlerWrapper::release,
load_source: DxcIncludeHandlerWrapper::load_source,
};
Some(Box::new(DxcIncludeHandlerWrapper {
vtable: Box::new(vtable),
handler: include_handler,
library,
pinned: vec![],
}))
} else {
None
}
}
pub fn compile(
&self,
blob: &DxcBlobEncoding,
source_name: &str,
entry_point: &str,
target_profile: &str,
args: &[&str],
include_handler: Option<&mut dyn DxcIncludeHandler>,
defines: &[(&str, Option<&str>)],
) -> Result<DxcOperationResult, (DxcOperationResult, HRESULT)> {
let mut wide_args = vec![];
let mut dxc_args = vec![];
Self::prep_args(args, &mut wide_args, &mut dxc_args);
let mut wide_defines = vec![];
let mut dxc_defines = vec![];
Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines);
let handler_wrapper = Self::prep_include_handler(&self.library, include_handler);
let mut result: ComPtr<IDxcOperationResult> = ComPtr::new();
let result_hr = unsafe {
self.inner.compile(
blob.inner.as_ptr(),
to_wide(source_name).as_ptr(),
to_wide(entry_point).as_ptr(),
to_wide(target_profile).as_ptr(),
dxc_args.as_ptr(),
dxc_args.len() as u32,
dxc_defines.as_ptr(),
dxc_defines.len() as u32,
handler_wrapper
.as_ref()
.map_or(std::ptr::null(), |v| &**v as *const _ as *const _),
result.as_mut_ptr(),
)
};
let mut compile_error = 0u32;
let status_hr = unsafe { result.get_status(&mut compile_error) };
if !result_hr.is_err() && !status_hr.is_err() && compile_error == 0 {
Ok(DxcOperationResult::new(result))
} else {
Err((DxcOperationResult::new(result), result_hr))
}
}
pub fn compile_with_debug(
&self,
blob: &DxcBlobEncoding,
source_name: &str,
entry_point: &str,
target_profile: &str,
args: &[&str],
include_handler: Option<&mut dyn DxcIncludeHandler>,
defines: &[(&str, Option<&str>)],
) -> Result<(DxcOperationResult, String, DxcBlob), (DxcOperationResult, HRESULT)> {
let mut wide_args = vec![];
let mut dxc_args = vec![];
Self::prep_args(args, &mut wide_args, &mut dxc_args);
let mut wide_defines = vec![];
let mut dxc_defines = vec![];
Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines);
let handler_wrapper = Self::prep_include_handler(&self.library, include_handler);
let mut result: ComPtr<IDxcOperationResult> = ComPtr::new();
let mut debug_blob: ComPtr<IDxcBlob> = ComPtr::new();
let mut debug_filename: LPWSTR = std::ptr::null_mut();
let result_hr = unsafe {
self.inner.compile_with_debug(
blob.inner.as_ptr(),
to_wide(source_name).as_ptr(),
to_wide(entry_point).as_ptr(),
to_wide(target_profile).as_ptr(),
dxc_args.as_ptr(),
dxc_args.len() as u32,
dxc_defines.as_ptr(),
dxc_defines.len() as u32,
handler_wrapper
.as_ref()
.map_or(std::ptr::null(), |v| &**v as *const _ as *const _),
result.as_mut_ptr(),
&mut debug_filename,
debug_blob.as_mut_ptr(),
)
};
let mut compile_error = 0u32;
let status_hr = unsafe { result.get_status(&mut compile_error) };
if !result_hr.is_err() && !status_hr.is_err() && compile_error == 0 {
Ok((
DxcOperationResult::new(result),
from_wide(debug_filename),
DxcBlob::new(debug_blob),
))
} else {
Err((DxcOperationResult::new(result), result_hr))
}
}
pub fn preprocess(
&self,
blob: &DxcBlobEncoding,
source_name: &str,
args: &[&str],
include_handler: Option<&mut dyn DxcIncludeHandler>,
defines: &[(&str, Option<&str>)],
) -> Result<DxcOperationResult, (DxcOperationResult, HRESULT)> {
let mut wide_args = vec![];
let mut dxc_args = vec![];
Self::prep_args(args, &mut wide_args, &mut dxc_args);
let mut wide_defines = vec![];
let mut dxc_defines = vec![];
Self::prep_defines(defines, &mut wide_defines, &mut dxc_defines);
let handler_wrapper = Self::prep_include_handler(&self.library, include_handler);
let mut result: ComPtr<IDxcOperationResult> = ComPtr::new();
let result_hr = unsafe {
self.inner.preprocess(
blob.inner.as_ptr(),
to_wide(source_name).as_ptr(),
dxc_args.as_ptr(),
dxc_args.len() as u32,
dxc_defines.as_ptr(),
dxc_defines.len() as u32,
handler_wrapper
.as_ref()
.map_or(std::ptr::null(), |v| &**v as *const _ as *const _),
result.as_mut_ptr(),
)
};
let mut compile_error = 0u32;
let status_hr = unsafe { result.get_status(&mut compile_error) };
if !result_hr.is_err() && !status_hr.is_err() && compile_error == 0 {
Ok(DxcOperationResult::new(result))
} else {
Err((DxcOperationResult::new(result), result_hr))
}
}
pub fn disassemble(&self, blob: &DxcBlob) -> Result<DxcBlobEncoding> {
let mut result_blob: ComPtr<IDxcBlobEncoding> = ComPtr::new();
unsafe {
self.inner
.disassemble(blob.inner.as_ptr(), result_blob.as_mut_ptr())
}
.result()?;
Ok(DxcBlobEncoding::new(result_blob))
}
}
#[derive(Debug)]
pub struct DxcLibrary {
inner: ComPtr<IDxcLibrary>,
}
impl DxcLibrary {
fn new(inner: ComPtr<IDxcLibrary>) -> Self {
Self { inner }
}
pub fn create_blob_with_encoding(&self, data: &[u8]) -> Result<DxcBlobEncoding> {
let mut blob: ComPtr<IDxcBlobEncoding> = ComPtr::new();
unsafe {
self.inner.create_blob_with_encoding_from_pinned(
data.as_ptr().cast(),
data.len() as u32,
0, // Binary; no code page
blob.as_mut_ptr(),
)
}
.result()?;
Ok(DxcBlobEncoding::new(blob))
}
pub fn create_blob_with_encoding_from_str(&self, text: &str) -> Result<DxcBlobEncoding> {
let mut blob: ComPtr<IDxcBlobEncoding> = ComPtr::new();
const CP_UTF8: u32 = 65001; // UTF-8 translation
unsafe {
self.inner.create_blob_with_encoding_from_pinned(
text.as_ptr().cast(),
text.len() as u32,
CP_UTF8,
blob.as_mut_ptr(),
)
}
.result()?;
Ok(DxcBlobEncoding::new(blob))
}
pub fn get_blob_as_string(&self, blob: &DxcBlob) -> Result<String> {
let mut blob_utf8: ComPtr<IDxcBlobEncoding> = ComPtr::new();
unsafe {
self.inner
.get_blob_as_utf8(blob.inner.as_ptr(), blob_utf8.as_mut_ptr())
}
.result()?;
Ok(String::from_utf8(DxcBlob::new((&blob_utf8).into()).to_vec()).unwrap())
}
}
#[derive(Debug)]
pub struct Dxc {
dxc_lib: Library,
}
#[cfg(target_os = "windows")]
fn dxcompiler_lib_name() -> &'static Path {
Path::new("dxcompiler.dll")
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn dxcompiler_lib_name() -> &'static Path {
Path::new("./libdxcompiler.so")
}
#[cfg(target_os = "macos")]
fn dxcompiler_lib_name() -> &'static Path {
Path::new("./libdxcompiler.dylib")
}
impl Dxc {
/// `dxc_path` can point to a library directly or the directory containing the library,
/// in which case the appended filename depends on the platform.
pub fn new(lib_path: Option<PathBuf>) -> Result<Self> {
let lib_path = if let Some(lib_path) = lib_path {
if lib_path.is_file() {
lib_path
} else {
lib_path.join(dxcompiler_lib_name())
}
} else {
dxcompiler_lib_name().to_owned()
};
let dxc_lib =
unsafe { Library::new(&lib_path) }.map_err(|e| HassleError::LoadLibraryError {
filename: lib_path,
inner: e,
})?;
Ok(Self { dxc_lib })
}
pub(crate) fn get_dxc_create_instance(&self) -> Result<Symbol<DxcCreateInstanceProc>> {
Ok(unsafe { self.dxc_lib.get(b"DxcCreateInstance\0")? })
}
pub fn create_compiler(&self) -> Result<DxcCompiler> {
let mut compiler: ComPtr<IDxcCompiler2> = ComPtr::new();
self.get_dxc_create_instance()?(
&CLSID_DxcCompiler,
&IID_IDxcCompiler2,
compiler.as_mut_ptr(),
)
.result()?;
Ok(DxcCompiler::new(compiler, self.create_library()?))
}
pub fn create_library(&self) -> Result<DxcLibrary> {
let mut library: ComPtr<IDxcLibrary> = ComPtr::new();
self.get_dxc_create_instance()?(&CLSID_DxcLibrary, &IID_IDxcLibrary, library.as_mut_ptr())
.result()?;
Ok(DxcLibrary::new(library))
}
pub fn create_reflector(&self) -> Result<DxcReflector> {
let mut reflector: ComPtr<IDxcContainerReflection> = ComPtr::new();
self.get_dxc_create_instance()?(
&CLSID_DxcContainerReflection,
&IID_IDxcContainerReflection,
reflector.as_mut_ptr(),
)
.result()?;
Ok(DxcReflector::new(reflector))
}
}
#[derive(Debug)]
pub struct DxcValidator {
inner: ComPtr<IDxcValidator>,
}
pub type DxcValidatorVersion = (u32, u32);
impl DxcValidator {
fn new(inner: ComPtr<IDxcValidator>) -> Self {
Self { inner }
}
pub fn version(&self) -> Result<DxcValidatorVersion> {
let mut version: ComPtr<IDxcVersionInfo> = ComPtr::new();
HRESULT::from(unsafe {
self.inner
.query_interface(&IID_IDxcVersionInfo, version.as_mut_ptr())
})
.result()?;
let mut major = 0;
let mut minor = 0;
unsafe { version.get_version(&mut major, &mut minor) }.result_with_success((major, minor))
}
pub fn validate(&self, blob: DxcBlob) -> Result<DxcBlob, (DxcOperationResult, HassleError)> {
let mut result: ComPtr<IDxcOperationResult> = ComPtr::new();
let result_hr = unsafe {
self.inner.validate(
blob.inner.as_ptr(),
DXC_VALIDATOR_FLAGS_IN_PLACE_EDIT,
result.as_mut_ptr(),
)
};
let mut validate_status = 0u32;
let status_hr = unsafe { result.get_status(&mut validate_status) };
if !result_hr.is_err() && !status_hr.is_err() && validate_status == 0 {
Ok(blob)
} else {
Err((
DxcOperationResult::new(result),
HassleError::Win32Error(result_hr),
))
}
}
}
pub struct Reflection {
inner: ComPtr<ID3D12ShaderReflection>,
}
impl Reflection {
fn new(inner: ComPtr<ID3D12ShaderReflection>) -> Self {
Self { inner }
}
pub fn thread_group_size(&self) -> [u32; 3] {
let (mut size_x, mut size_y, mut size_z) = (0u32, 0u32, 0u32);
unsafe {
self.inner
.get_thread_group_size(&mut size_x, &mut size_y, &mut size_z)
};
[size_x, size_y, size_z]
}
}
pub struct DxcReflector {
inner: ComPtr<IDxcContainerReflection>,
}
impl DxcReflector {
fn new(inner: ComPtr<IDxcContainerReflection>) -> Self {
Self { inner }
}
pub fn reflect(&self, blob: DxcBlob) -> Result<Reflection> {
let result_hr = unsafe { self.inner.load(blob.inner.as_ptr()) };
if result_hr.is_err() {
return Err(HassleError::Win32Error(result_hr));
}
let mut shader_idx = 0;
let result_hr = unsafe { self.inner.find_first_part_kind(DFCC_DXIL, &mut shader_idx) };
if result_hr.is_err() {
return Err(HassleError::Win32Error(result_hr));
}
let mut reflection: ComPtr<ID3D12ShaderReflection> = ComPtr::new();
let result_hr = unsafe {
self.inner.get_part_reflection(
shader_idx,
&IID_ID3D12ShaderReflection,
reflection.as_mut_ptr(),
)
};
if result_hr.is_err() {
return Err(HassleError::Win32Error(result_hr));
}
Ok(Reflection::new(reflection))
}
}
#[derive(Debug)]
pub struct Dxil {
dxil_lib: Library,
}
impl Dxil {
#[cfg(not(windows))]
pub fn new(_: Option<PathBuf>) -> Result<Self> {
Err(HassleError::WindowsOnly(
"DXIL Signing is only supported on Windows".to_string(),
))
}
/// `dxil_path` can point to a library directly or the directory containing the library,
/// in which case `dxil.dll` is appended.
#[cfg(windows)]
pub fn new(lib_path: Option<PathBuf>) -> Result<Self> {
let lib_path = if let Some(lib_path) = lib_path {
if lib_path.is_file() {
lib_path
} else {
lib_path.join("dxil.dll")
}
} else {
PathBuf::from("dxil.dll")
};
let dxil_lib =
unsafe { Library::new(&lib_path) }.map_err(|e| HassleError::LoadLibraryError {
filename: lib_path.to_owned(),
inner: e,
})?;
Ok(Self { dxil_lib })
}
fn get_dxc_create_instance(&self) -> Result<Symbol<DxcCreateInstanceProc>> {
Ok(unsafe { self.dxil_lib.get(b"DxcCreateInstance\0")? })
}
pub fn create_validator(&self) -> Result<DxcValidator> {
let mut validator: ComPtr<IDxcValidator> = ComPtr::new();
self.get_dxc_create_instance()?(
&CLSID_DxcValidator,
&IID_IDxcValidator,
validator.as_mut_ptr(),
)
.result()?;
Ok(DxcValidator::new(validator))
}
}