diff --git a/.cargo/config.in b/.cargo/config.in index 4fc8076dda4c..6d86b55d0c36 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -105,17 +105,17 @@ rev = "39f95e2f7cd6e632a379cdeee62c68e8cedd7810" [source."https://github.com/gfx-rs/naga"] git = "https://github.com/gfx-rs/naga" replace-with = "vendored-sources" -tag = "gfx-20" +tag = "gfx-22" [source."https://github.com/gfx-rs/metal-rs"] git = "https://github.com/gfx-rs/metal-rs" replace-with = "vendored-sources" -rev = "439c986eb7a9b91e88b61def2daa66e4043fcbef" +rev = "78f632d194c7c16d18b71d7373c4080847d110b0" [source."https://github.com/gfx-rs/gfx"] git = "https://github.com/gfx-rs/gfx" replace-with = "vendored-sources" -rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" +rev = "84e02f96149207b1bafecb1924b14315930c98ee" [source."https://github.com/gfx-rs/d3d12-rs"] git = "https://github.com/gfx-rs/d3d12-rs" diff --git a/Cargo.lock b/Cargo.lock index 0c8eb0c56543..9d5221fa88e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1846,7 +1846,7 @@ dependencies = [ [[package]] name = "gfx-auxil" version = "0.8.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "fxhash", "gfx-hal", @@ -1856,7 +1856,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx11" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bitflags", @@ -1877,7 +1877,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bit-set", @@ -1898,7 +1898,7 @@ dependencies = [ [[package]] name = "gfx-backend-empty" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "gfx-hal", "log", @@ -1908,7 +1908,7 @@ dependencies = [ [[package]] name = "gfx-backend-metal" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bitflags", @@ -1924,6 +1924,7 @@ dependencies = [ "naga", "objc", "parking_lot", + "profiling", "range-alloc", "raw-window-handle", "spirv_cross", @@ -1933,7 +1934,7 @@ dependencies = [ [[package]] name = "gfx-backend-vulkan" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "ash", @@ -1953,7 +1954,7 @@ dependencies = [ [[package]] name = "gfx-hal" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "bitflags", "naga", @@ -3060,7 +3061,7 @@ dependencies = [ [[package]] name = "metal" version = "0.21.0" -source = "git+https://github.com/gfx-rs/metal-rs?rev=439c986eb7a9b91e88b61def2daa66e4043fcbef#439c986eb7a9b91e88b61def2daa66e4043fcbef" +source = "git+https://github.com/gfx-rs/metal-rs?rev=78f632d194c7c16d18b71d7373c4080847d110b0#78f632d194c7c16d18b71d7373c4080847d110b0" dependencies = [ "bitflags", "block", @@ -3347,7 +3348,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" [[package]] name = "naga" version = "0.3.1" -source = "git+https://github.com/gfx-rs/naga?tag=gfx-20#0369ee181ed9cd315635fc0e3d99deecdbc72246" +source = "git+https://github.com/gfx-rs/naga?tag=gfx-22#9cd6fd9c205a57824644d0baedc6c15997be1e36" dependencies = [ "bit-set", "bitflags", @@ -4186,7 +4187,7 @@ dependencies = [ [[package]] name = "range-alloc" version = "0.1.2" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" [[package]] name = "raw-cpuid" diff --git a/dom/webgpu/RenderPassEncoder.cpp b/dom/webgpu/RenderPassEncoder.cpp index 90bc6547caf3..b1e1f8e0b9d5 100644 --- a/dom/webgpu/RenderPassEncoder.cpp +++ b/dom/webgpu/RenderPassEncoder.cpp @@ -234,11 +234,11 @@ void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width, } } -void RenderPassEncoder::SetBlendColor( +void RenderPassEncoder::SetBlendConstant( const dom::DoubleSequenceOrGPUColorDict& color) { if (mValid) { ffi::WGPUColor aColor = ConvertColor(color.GetAsGPUColorDict()); - ffi::wgpu_render_pass_set_blend_color(mPass, &aColor); + ffi::wgpu_render_pass_set_blend_constant(mPass, &aColor); } } diff --git a/dom/webgpu/RenderPassEncoder.h b/dom/webgpu/RenderPassEncoder.h index dea1f2635e3d..f9b6717321e4 100644 --- a/dom/webgpu/RenderPassEncoder.h +++ b/dom/webgpu/RenderPassEncoder.h @@ -81,7 +81,7 @@ class RenderPassEncoder final : public ObjectBase, void SetViewport(float x, float y, float width, float height, float minDepth, float maxDepth); void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height); - void SetBlendColor(const dom::DoubleSequenceOrGPUColorDict& color); + void SetBlendConstant(const dom::DoubleSequenceOrGPUColorDict& color); void SetStencilReference(uint32_t reference); void EndPass(ErrorResult& aRv); }; diff --git a/dom/webgpu/ipc/WebGPUParent.cpp b/dom/webgpu/ipc/WebGPUParent.cpp index 1aa1ae9d7dba..4a5013052520 100644 --- a/dom/webgpu/ipc/WebGPUParent.cpp +++ b/dom/webgpu/ipc/WebGPUParent.cpp @@ -696,16 +696,9 @@ ipc::IPCResult WebGPUParent::RecvShutdown() { ipc::IPCResult WebGPUParent::RecvDeviceAction(RawId aSelf, const ipc::ByteBuf& aByteBuf) { - ipc::ByteBuf byteBuf; ErrorBuffer error; ffi::wgpu_server_device_action(mContext, aSelf, ToFFI(&aByteBuf), - ToFFI(&byteBuf), error.ToFFI()); - - if (byteBuf.mData) { - if (!SendDropAction(std::move(byteBuf))) { - NS_WARNING("Unable to set a drop action!"); - } - } + error.ToFFI()); error.CheckAndForward(this, aSelf); return IPC_OK(); diff --git a/dom/webidl/WebGPU.webidl b/dom/webidl/WebGPU.webidl index 8d2574e4ccc4..8a8c2bc177dc 100644 --- a/dom/webidl/WebGPU.webidl +++ b/dom/webidl/WebGPU.webidl @@ -8,7 +8,6 @@ */ - typedef [EnforceRange] unsigned long GPUBufferDynamicOffset; typedef [EnforceRange] unsigned long GPUStencilValue; typedef [EnforceRange] unsigned long GPUSampleMask; @@ -755,17 +754,17 @@ dictionary GPUMultisampleState { enum GPUBlendFactor { "zero", "one", - "src-color", - "one-minus-src-color", + "src", + "one-minus-src", "src-alpha", "one-minus-src-alpha", - "dst-color", - "one-minus-dst-color", + "dst", + "one-minus-dst", "dst-alpha", "one-minus-dst-alpha", "src-alpha-saturated", - "blend-color", - "one-minus-blend-color", + "constant", + "one-minus-constant", }; enum GPUBlendOperation { @@ -1009,7 +1008,7 @@ interface GPURenderPassEncoder { void setScissorRect(GPUIntegerCoordinate x, GPUIntegerCoordinate y, GPUIntegerCoordinate width, GPUIntegerCoordinate height); - void setBlendColor(GPUColor color); + void setBlendConstant(GPUColor color); void setStencilReference(GPUStencilValue reference); //void beginOcclusionQuery(GPUSize32 queryIndex); @@ -1155,6 +1154,12 @@ dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase { required GPUDevice device; required GPUTextureFormat format; GPUTextureUsageFlags usage = 0x10; //GPUTextureUsage.OUTPUT_ATTACHMENT + GPUCanvasCompositingAlphaMode compositingAlphaMode = "opaque"; +}; + +enum GPUCanvasCompositingAlphaMode { + "opaque", + "premultiplied", }; [Pref="dom.webgpu.enabled", diff --git a/gfx/wgpu/Cargo.lock b/gfx/wgpu/Cargo.lock index ce5454fa605f..4ffae6f2d963 100644 --- a/gfx/wgpu/Cargo.lock +++ b/gfx/wgpu/Cargo.lock @@ -465,7 +465,7 @@ dependencies = [ [[package]] name = "gfx-auxil" version = "0.8.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "fxhash", "gfx-hal", @@ -475,7 +475,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx11" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bitflags", @@ -496,7 +496,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bit-set", @@ -517,7 +517,7 @@ dependencies = [ [[package]] name = "gfx-backend-empty" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "gfx-hal", "log", @@ -527,7 +527,7 @@ dependencies = [ [[package]] name = "gfx-backend-metal" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "bitflags", @@ -543,6 +543,7 @@ dependencies = [ "naga", "objc", "parking_lot", + "profiling", "range-alloc", "raw-window-handle", "spirv_cross", @@ -552,7 +553,7 @@ dependencies = [ [[package]] name = "gfx-backend-vulkan" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "arrayvec", "ash", @@ -572,7 +573,7 @@ dependencies = [ [[package]] name = "gfx-hal" version = "0.7.0" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" dependencies = [ "bitflags", "naga", @@ -815,7 +816,7 @@ dependencies = [ [[package]] name = "metal" version = "0.21.0" -source = "git+https://github.com/gfx-rs/metal-rs?rev=439c986eb7a9b91e88b61def2daa66e4043fcbef#439c986eb7a9b91e88b61def2daa66e4043fcbef" +source = "git+https://github.com/gfx-rs/metal-rs?rev=78f632d194c7c16d18b71d7373c4080847d110b0#78f632d194c7c16d18b71d7373c4080847d110b0" dependencies = [ "bitflags", "block", @@ -871,7 +872,7 @@ dependencies = [ [[package]] name = "naga" version = "0.3.1" -source = "git+https://github.com/gfx-rs/naga?tag=gfx-20#0369ee181ed9cd315635fc0e3d99deecdbc72246" +source = "git+https://github.com/gfx-rs/naga?tag=gfx-22#9cd6fd9c205a57824644d0baedc6c15997be1e36" dependencies = [ "bit-set", "bitflags", @@ -1126,7 +1127,7 @@ dependencies = [ [[package]] name = "range-alloc" version = "0.1.2" -source = "git+https://github.com/gfx-rs/gfx?rev=3ee1ca9ba486b166a52765024d8d149cbb28d486#3ee1ca9ba486b166a52765024d8d149cbb28d486" +source = "git+https://github.com/gfx-rs/gfx?rev=84e02f96149207b1bafecb1924b14315930c98ee#84e02f96149207b1bafecb1924b14315930c98ee" [[package]] name = "raw-window-handle" diff --git a/gfx/wgpu/player/src/lib.rs b/gfx/wgpu/player/src/lib.rs index fe2573e2c482..41719759aaf3 100644 --- a/gfx/wgpu/player/src/lib.rs +++ b/gfx/wgpu/player/src/lib.rs @@ -265,7 +265,7 @@ impl GlobalPlay for wgc::hub::Global { root_id: ic.root_id, group_ids: &ic.group_ids, }); - let (_, _, error) = + let (_, error) = self.device_create_compute_pipeline::(device, &desc, id, implicit_ids); if let Some(e) = error { panic!("{:?}", e); @@ -287,7 +287,7 @@ impl GlobalPlay for wgc::hub::Global { root_id: ic.root_id, group_ids: &ic.group_ids, }); - let (_, _, error) = + let (_, error) = self.device_create_render_pipeline::(device, &desc, id, implicit_ids); if let Some(e) = error { panic!("{:?}", e); diff --git a/gfx/wgpu/player/tests/data/quad.wgsl b/gfx/wgpu/player/tests/data/quad.wgsl index d5bca56d58ca..8998ce3cfe3e 100644 --- a/gfx/wgpu/player/tests/data/quad.wgsl +++ b/gfx/wgpu/player/tests/data/quad.wgsl @@ -1,9 +1,9 @@ [[stage(vertex)]] fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> [[builtin(position)]] vec4 { // hacky way to draw a large triangle - const tmp1 = i32(vertex_index) / 2; - const tmp2 = i32(vertex_index) & 1; - const pos = vec2( + let tmp1 = i32(vertex_index) / 2; + let tmp2 = i32(vertex_index) & 1; + let pos = vec2( f32(tmp1) * 4.0 - 1.0, f32(tmp2) * 4.0 - 1.0 ); diff --git a/gfx/wgpu/wgpu-core/Cargo.toml b/gfx/wgpu/wgpu-core/Cargo.toml index 8b1fd053a0b4..54a726f18865 100644 --- a/gfx/wgpu/wgpu-core/Cargo.toml +++ b/gfx/wgpu/wgpu-core/Cargo.toml @@ -40,28 +40,28 @@ thiserror = "1" gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc.git", rev = "2cd1ad650cdd24d1647b6041f77ced0cbf1ff2a6" } gpu-descriptor = { version = "0.1" } -hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } -gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } +hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } +gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } [target.'cfg(all(not(target_arch = "wasm32"), all(unix, not(target_os = "ios"), not(target_os = "macos"))))'.dependencies] -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486", features = ["naga"] } -#gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee", features = ["naga"] } +#gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } [target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies] -gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486", optional = true } +gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee", optional = true } [target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies] -gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } -gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486", features = ["naga"] } +gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } +gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee", features = ["naga"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -#gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "3ee1ca9ba486b166a52765024d8d149cbb28d486" } +#gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "84e02f96149207b1bafecb1924b14315930c98ee" } [dependencies.naga] git = "https://github.com/gfx-rs/naga" -tag = "gfx-20" +tag = "gfx-22" features = ["spv-in", "spv-out", "wgsl-in"] [dependencies.wgt] diff --git a/gfx/wgpu/wgpu-core/src/binding_model.rs b/gfx/wgpu/wgpu-core/src/binding_model.rs index 0d4f0ec9dc7f..fde12104c299 100644 --- a/gfx/wgpu/wgpu-core/src/binding_model.rs +++ b/gfx/wgpu/wgpu-core/src/binding_model.rs @@ -10,7 +10,7 @@ use crate::{ hub::Resource, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, memory_init_tracker::MemoryInitTrackerAction, - track::{TrackerSet, DUMMY_SELECTOR}, + track::{TrackerSet, UsageConflict, DUMMY_SELECTOR}, validation::{MissingBufferUsageError, MissingTextureUsageError}, FastHashMap, Label, LifeGuard, MultiRefCount, Stored, MAX_BIND_GROUPS, }; @@ -43,6 +43,8 @@ pub enum CreateBindGroupLayoutError { TooManyBindings(BindingTypeMaxCountError), } +//TODO: refactor this to move out `enum BindingError`. + #[derive(Clone, Debug, Error)] pub enum CreateBindGroupError { #[error(transparent)] @@ -130,12 +132,24 @@ pub enum CreateBindGroupError { layout_format: wgt::TextureFormat, view_format: wgt::TextureFormat, }, - #[error("the given sampler is/is not a comparison sampler, while the layout type indicates otherwise")] - WrongSamplerComparison, + #[error("sampler binding {binding} expects comparison = {layout_cmp}, but given a sampler with comparison = {sampler_cmp}")] + WrongSamplerComparison { + binding: u32, + layout_cmp: bool, + sampler_cmp: bool, + }, + #[error("sampler binding {binding} expects filtering = {layout_flt}, but given a sampler with filtering = {sampler_flt}")] + WrongSamplerFiltering { + binding: u32, + layout_flt: bool, + sampler_flt: bool, + }, #[error("bound texture views can not have both depth and stencil aspects enabled")] DepthStencilAspect, #[error("the adapter does not support simultaneous read + write storage texture access for the format {0:?}")] StorageReadWriteNotSupported(wgt::TextureFormat), + #[error(transparent)] + ResourceUsageConflict(#[from] UsageConflict), } #[derive(Clone, Debug, Error)] diff --git a/gfx/wgpu/wgpu-core/src/command/bundle.rs b/gfx/wgpu/wgpu-core/src/command/bundle.rs index 84b55308c900..bba9dc7a7456 100644 --- a/gfx/wgpu/wgpu-core/src/command/bundle.rs +++ b/gfx/wgpu/wgpu-core/src/command/bundle.rs @@ -478,7 +478,7 @@ impl RenderBundleEncoder { | RenderCommand::BeginPipelineStatisticsQuery { .. } | RenderCommand::EndPipelineStatisticsQuery => unimplemented!(), RenderCommand::ExecuteBundle(_) - | RenderCommand::SetBlendColor(_) + | RenderCommand::SetBlendConstant(_) | RenderCommand::SetStencilReference(_) | RenderCommand::SetViewport { .. } | RenderCommand::SetScissor(_) => unreachable!("not supported by a render bundle"), @@ -533,6 +533,8 @@ pub enum CreateRenderBundleError { pub enum ExecutionError { #[error("buffer {0:?} is destroyed")] DestroyedBuffer(id::BufferId), + #[error("using {0} in a render bundle is not implemented")] + Unimplemented(&'static str), } pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor>; @@ -733,15 +735,21 @@ impl RenderBundle { cmd_buf.draw_indexed_indirect(buffer, offset, 1, 0); } RenderCommand::MultiDrawIndirect { .. } - | RenderCommand::MultiDrawIndirectCount { .. } => unimplemented!(), - RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(), - RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(), - RenderCommand::PopDebugGroup => unimplemented!(), + | RenderCommand::MultiDrawIndirectCount { .. } => { + return Err(ExecutionError::Unimplemented("multi-draw-indirect")) + } + RenderCommand::PushDebugGroup { .. } + | RenderCommand::InsertDebugMarker { .. } + | RenderCommand::PopDebugGroup => { + return Err(ExecutionError::Unimplemented("debug-markers")) + } RenderCommand::WriteTimestamp { .. } | RenderCommand::BeginPipelineStatisticsQuery { .. } - | RenderCommand::EndPipelineStatisticsQuery => unimplemented!(), + | RenderCommand::EndPipelineStatisticsQuery => { + return Err(ExecutionError::Unimplemented("queries")) + } RenderCommand::ExecuteBundle(_) - | RenderCommand::SetBlendColor(_) + | RenderCommand::SetBlendConstant(_) | RenderCommand::SetStencilReference(_) | RenderCommand::SetViewport { .. } | RenderCommand::SetScissor(_) => unreachable!(), diff --git a/gfx/wgpu/wgpu-core/src/command/draw.rs b/gfx/wgpu/wgpu-core/src/command/draw.rs index 1df50a83ca54..7c40603df97b 100644 --- a/gfx/wgpu/wgpu-core/src/command/draw.rs +++ b/gfx/wgpu/wgpu-core/src/command/draw.rs @@ -22,8 +22,8 @@ pub type BufferError = UseExtendError; /// Error validating a draw call. #[derive(Clone, Debug, Error, PartialEq)] pub enum DrawError { - #[error("blend color needs to be set")] - MissingBlendColor, + #[error("blend constant needs to be set")] + MissingBlendConstant, #[error("render pipeline must be set")] MissingPipeline, #[error("vertex buffer {index} must be set")] @@ -95,6 +95,8 @@ pub enum RenderCommandError { InvalidViewport, #[error("Invalid ScissorRect parameters")] InvalidScissorRect, + #[error("Support for {0} is not implemented yet")] + Unimplemented(&'static str), } #[derive(Clone, Copy, Debug, Default)] @@ -142,7 +144,7 @@ pub enum RenderCommand { offset: BufferAddress, size: Option, }, - SetBlendColor(Color), + SetBlendConstant(Color), SetStencilReference(u32), SetViewport { rect: Rect, diff --git a/gfx/wgpu/wgpu-core/src/command/render.rs b/gfx/wgpu/wgpu-core/src/command/render.rs index 7a3f0032cba6..3db50d1afc0a 100644 --- a/gfx/wgpu/wgpu-core/src/command/render.rs +++ b/gfx/wgpu/wgpu-core/src/command/render.rs @@ -326,7 +326,7 @@ impl VertexState { struct State { pipeline_flags: PipelineFlags, binder: Binder, - blend_color: OptionalState, + blend_constant: OptionalState, stencil_reference: u32, pipeline: StateChange, index: IndexState, @@ -355,8 +355,8 @@ impl State { if self.pipeline.is_unset() { return Err(DrawError::MissingPipeline); } - if self.blend_color == OptionalState::Required { - return Err(DrawError::MissingBlendColor); + if self.blend_constant == OptionalState::Required { + return Err(DrawError::MissingBlendConstant); } if indexed { // Pipeline expects an index buffer @@ -972,7 +972,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { ra.selector.clone(), ra.new_use, ) - .unwrap(); + .map_err(UsageConflict::from)?; if let Some(usage) = ra.previous_use { // Make the attachment tracks to be aware of the internal @@ -1068,7 +1068,7 @@ impl Global { let mut state = State { pipeline_flags: PipelineFlags::empty(), binder: Binder::new(), - blend_color: OptionalState::Unused, + blend_constant: OptionalState::Unused, stencil_reference: 0, pipeline: StateChange::new(), index: IndexState::default(), @@ -1109,7 +1109,8 @@ impl Global { .trackers .bind_groups .use_extend(&*bind_group_guard, bind_group_id, (), ()) - .unwrap(); + .map_err(|_| RenderCommandError::InvalidBindGroup(bind_group_id)) + .map_pass_err(scope)?; bind_group .validate_dynamic_bindings(&temp_offsets) .map_pass_err(scope)?; @@ -1188,8 +1189,8 @@ impl Global { } state - .blend_color - .require(pipeline.flags.contains(PipelineFlags::BLEND_COLOR)); + .blend_constant + .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT)); unsafe { raw.bind_graphics_pipeline(&pipeline.raw); @@ -1377,8 +1378,8 @@ impl Global { } state.vertex.update_limits(); } - RenderCommand::SetBlendColor(ref color) => { - state.blend_color = OptionalState::Set; + RenderCommand::SetBlendConstant(ref color) => { + state.blend_constant = OptionalState::Set; unsafe { raw.set_blend_constants(conv::map_color_f32(color)); } @@ -1911,6 +1912,9 @@ impl Global { ExecutionError::DestroyedBuffer(id) => { RenderCommandError::DestroyedBuffer(id) } + ExecutionError::Unimplemented(what) => { + RenderCommandError::Unimplemented(what) + } }) .map_pass_err(scope)?; @@ -2036,10 +2040,10 @@ pub mod render_ffi { } #[no_mangle] - pub extern "C" fn wgpu_render_pass_set_blend_color(pass: &mut RenderPass, color: &Color) { + pub extern "C" fn wgpu_render_pass_set_blend_constant(pass: &mut RenderPass, color: &Color) { pass.base .commands - .push(RenderCommand::SetBlendColor(*color)); + .push(RenderCommand::SetBlendConstant(*color)); } #[no_mangle] diff --git a/gfx/wgpu/wgpu-core/src/conv.rs b/gfx/wgpu/wgpu-core/src/conv.rs index d670cbde0262..8ee4dc404501 100644 --- a/gfx/wgpu/wgpu-core/src/conv.rs +++ b/gfx/wgpu/wgpu-core/src/conv.rs @@ -4,6 +4,7 @@ use crate::{ command::{LoadOp, PassChannel, StoreOp}, + pipeline::ColorStateError, resource, PrivateFeatures, }; @@ -196,16 +197,24 @@ pub fn map_primitive_topology(primitive_topology: wgt::PrimitiveTopology) -> hal } } -pub fn map_color_target_state(desc: &wgt::ColorTargetState) -> hal::pso::ColorBlendDesc { +pub fn map_color_target_state( + desc: &wgt::ColorTargetState, +) -> Result { let color_mask = desc.write_mask; - let blend = desc.blend.as_ref().map(|bs| hal::pso::BlendState { - color: map_blend_component(&bs.color), - alpha: map_blend_component(&bs.alpha), - }); - hal::pso::ColorBlendDesc { + let blend = desc + .blend + .as_ref() + .map(|bs| { + Ok(hal::pso::BlendState { + color: map_blend_component(&bs.color)?, + alpha: map_blend_component(&bs.alpha)?, + }) + }) + .transpose()?; + Ok(hal::pso::ColorBlendDesc { mask: map_color_write_flags(color_mask), blend, - } + }) } fn map_color_write_flags(flags: wgt::ColorWrite) -> hal::pso::ColorMask { @@ -228,25 +237,48 @@ fn map_color_write_flags(flags: wgt::ColorWrite) -> hal::pso::ColorMask { value } -fn map_blend_component(component: &wgt::BlendComponent) -> hal::pso::BlendOp { +fn map_blend_component( + component: &wgt::BlendComponent, +) -> Result { use hal::pso::BlendOp as H; use wgt::BlendOperation as Bo; - match component.operation { - Bo::Add => H::Add { - src: map_blend_factor(component.src_factor), - dst: map_blend_factor(component.dst_factor), + Ok(match *component { + wgt::BlendComponent { + operation: Bo::Add, + src_factor, + dst_factor, + } => H::Add { + src: map_blend_factor(src_factor), + dst: map_blend_factor(dst_factor), }, - Bo::Subtract => H::Sub { - src: map_blend_factor(component.src_factor), - dst: map_blend_factor(component.dst_factor), + wgt::BlendComponent { + operation: Bo::Subtract, + src_factor, + dst_factor, + } => H::Sub { + src: map_blend_factor(src_factor), + dst: map_blend_factor(dst_factor), }, - Bo::ReverseSubtract => H::RevSub { - src: map_blend_factor(component.src_factor), - dst: map_blend_factor(component.dst_factor), + wgt::BlendComponent { + operation: Bo::ReverseSubtract, + src_factor, + dst_factor, + } => H::RevSub { + src: map_blend_factor(src_factor), + dst: map_blend_factor(dst_factor), }, - Bo::Min => H::Min, - Bo::Max => H::Max, - } + wgt::BlendComponent { + operation: Bo::Min, + src_factor: wgt::BlendFactor::One, + dst_factor: wgt::BlendFactor::One, + } => H::Min, + wgt::BlendComponent { + operation: Bo::Max, + src_factor: wgt::BlendFactor::One, + dst_factor: wgt::BlendFactor::One, + } => H::Max, + _ => return Err(ColorStateError::InvalidMinMaxBlendFactors(*component)), + }) } fn map_blend_factor(blend_factor: wgt::BlendFactor) -> hal::pso::Factor { @@ -255,17 +287,17 @@ fn map_blend_factor(blend_factor: wgt::BlendFactor) -> hal::pso::Factor { match blend_factor { Bf::Zero => H::Zero, Bf::One => H::One, - Bf::SrcColor => H::SrcColor, - Bf::OneMinusSrcColor => H::OneMinusSrcColor, + Bf::Src => H::SrcColor, + Bf::OneMinusSrc => H::OneMinusSrcColor, Bf::SrcAlpha => H::SrcAlpha, Bf::OneMinusSrcAlpha => H::OneMinusSrcAlpha, - Bf::DstColor => H::DstColor, - Bf::OneMinusDstColor => H::OneMinusDstColor, + Bf::Dst => H::DstColor, + Bf::OneMinusDst => H::OneMinusDstColor, Bf::DstAlpha => H::DstAlpha, Bf::OneMinusDstAlpha => H::OneMinusDstAlpha, Bf::SrcAlphaSaturated => H::SrcAlphaSaturate, - Bf::BlendColor => H::ConstColor, - Bf::OneMinusBlendColor => H::OneMinusConstColor, + Bf::Constant => H::ConstColor, + Bf::OneMinusConstant => H::OneMinusConstColor, } } diff --git a/gfx/wgpu/wgpu-core/src/device/mod.rs b/gfx/wgpu/wgpu-core/src/device/mod.rs index a006767ff3e1..3379a4b82161 100644 --- a/gfx/wgpu/wgpu-core/src/device/mod.rs +++ b/gfx/wgpu/wgpu-core/src/device/mod.rs @@ -11,7 +11,7 @@ use crate::{ id, instance, memory_init_tracker::{MemoryInitKind, MemoryInitTracker, MemoryInitTrackerAction}, pipeline, resource, swap_chain, - track::{BufferState, TextureSelector, TextureState, TrackerSet}, + track::{BufferState, TextureSelector, TextureState, TrackerSet, UsageConflict}, validation::{self, check_buffer_usage, check_texture_usage}, FastHashMap, Label, LabelHelpers, LifeGuard, MultiRefCount, PrivateFeatures, Stored, SubmissionIndex, MAX_BIND_GROUPS, @@ -56,6 +56,8 @@ pub const MAX_VERTEX_BUFFERS: usize = 16; pub const MAX_ANISOTROPY: u8 = 16; pub const SHADER_STAGE_COUNT: usize = 3; +const IMPLICIT_FAILURE: &str = "failed implicit"; + pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor>; pub fn all_buffer_stages() -> hal::pso::PipelineStage { @@ -864,6 +866,8 @@ impl Device { conv::map_texture_view_dimension(view_dim), conv::map_texture_format(format, self.private_features), hal::format::Swizzle::NO, + // conservatively assume the same usage + conv::map_texture_usage(texture.usage, aspects), range, ) .or(Err(resource::CreateTextureViewError::OutOfMemory))? @@ -940,10 +944,14 @@ impl Device { Some(wgt::SamplerBorderColor::OpaqueWhite) => hal::image::BorderColor::OpaqueWhite, }; + let filtering = [desc.min_filter, desc.mag_filter, desc.mipmap_filter] + .contains(&wgt::FilterMode::Linear); + let info = hal::image::SamplerDesc { min_filter: conv::map_filter(desc.min_filter), mag_filter: conv::map_filter(desc.mag_filter), mip_filter: conv::map_filter(desc.mipmap_filter), + reduction_mode: hal::image::ReductionMode::WeightedAverage, wrap_mode: ( conv::map_wrap(desc.address_modes[0]), conv::map_wrap(desc.address_modes[1]), @@ -975,6 +983,7 @@ impl Device { }, life_guard: LifeGuard::new(desc.label.borrow_or_default()), comparison: info.comparison.is_some(), + filtering, }) } @@ -1412,7 +1421,7 @@ impl Device { Br::Sampler(id) => { match decl.ty { wgt::BindingType::Sampler { - filtering: _, + filtering, comparison, } => { let sampler = used @@ -1422,7 +1431,19 @@ impl Device { // Check the actual sampler to also (not) be a comparison sampler if sampler.comparison != comparison { - return Err(Error::WrongSamplerComparison); + return Err(Error::WrongSamplerComparison { + binding, + layout_cmp: comparison, + sampler_cmp: sampler.comparison, + }); + } + // Check the actual sampler to be non-filtering, if required + if sampler.filtering && !filtering { + return Err(Error::WrongSamplerFiltering { + binding, + layout_flt: filtering, + sampler_flt: sampler.filtering, + }); } SmallVec::from([hal::pso::Descriptor::Sampler(&sampler.raw)]) @@ -1559,7 +1580,7 @@ impl Device { view.selector.clone(), internal_use, ) - .unwrap(); + .map_err(UsageConflict::from)?; check_texture_usage(texture.usage, pub_usage)?; let image_layout = conv::map_texture_state(internal_use, view.aspects).1; @@ -1623,7 +1644,7 @@ impl Device { view.selector.clone(), internal_use, ) - .unwrap(); + .map_err(UsageConflict::from)?; check_texture_usage(texture.usage, pub_usage)?; let image_layout = conv::map_texture_state(internal_use, view.aspects).1; @@ -1800,13 +1821,7 @@ impl Device { mut derived_group_layouts: ArrayVec<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>, bgl_guard: &mut Storage, id::BindGroupLayoutId>, pipeline_layout_guard: &mut Storage, id::PipelineLayoutId>, - ) -> Result< - (id::PipelineLayoutId, pipeline::ImplicitBindGroupCount), - pipeline::ImplicitLayoutError, - > { - let derived_bind_group_count = - derived_group_layouts.len() as pipeline::ImplicitBindGroupCount; - + ) -> Result { while derived_group_layouts .last() .map_or(false, |map| map.is_empty()) @@ -1821,9 +1836,7 @@ impl Device { ids.group_ids.len(), derived_group_layouts.len() ); - return Err(pipeline::ImplicitLayoutError::MissingIds( - derived_bind_group_count, - )); + return Err(pipeline::ImplicitLayoutError::MissingIds(group_count as _)); } for (bgl_id, map) in ids.group_ids.iter_mut().zip(derived_group_layouts) { @@ -1833,7 +1846,7 @@ impl Device { } None => { let bgl = self.create_bind_group_layout(self_id, None, map)?; - bgl_guard.insert(*bgl_id, bgl); + bgl_guard.force_replace(*bgl_id, bgl); } }; } @@ -1844,8 +1857,8 @@ impl Device { push_constant_ranges: Cow::Borrowed(&[]), //TODO? }; let layout = self.create_pipeline_layout(self_id, &layout_desc, bgl_guard)?; - pipeline_layout_guard.insert(ids.root_id, layout); - Ok((ids.root_id, derived_bind_group_count)) + pipeline_layout_guard.force_replace(ids.root_id, layout); + Ok(ids.root_id) } fn create_compute_pipeline( @@ -1855,14 +1868,20 @@ impl Device { implicit_context: Option, hub: &Hub, token: &mut Token, - ) -> Result< - ( - pipeline::ComputePipeline, - pipeline::ImplicitBindGroupCount, - id::PipelineLayoutId, - ), - pipeline::CreateComputePipelineError, - > { + ) -> Result, pipeline::CreateComputePipelineError> { + //TODO: only lock mutable if the layout is derived + let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(token); + let (mut bgl_guard, mut token) = hub.bind_group_layouts.write(&mut token); + + // This has to be done first, or otherwise the IDs may be pointing to entries + // that are not even in the storage. + if let Some(ref ids) = implicit_context { + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + if !self .downlevel .flags @@ -1871,10 +1890,6 @@ impl Device { return Err(pipeline::CreateComputePipelineError::ComputeShadersUnsupported); } - //TODO: only lock mutable if the layout is derived - let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(token); - let (mut bgl_guard, mut token) = hub.bind_group_layouts.write(&mut token); - let mut derived_group_layouts = ArrayVec::<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>::new(); @@ -1882,9 +1897,9 @@ impl Device { let (shader_module_guard, _) = hub.shader_modules.read(&mut token); let entry_point_name = &desc.stage.entry_point; - let shader_module = shader_module_guard.get(desc.stage.module).map_err(|_| { - pipeline::CreateComputePipelineError::Stage(validation::StageError::InvalidModule) - })?; + let shader_module = shader_module_guard + .get(desc.stage.module) + .map_err(|_| validation::StageError::InvalidModule)?; let flag = wgt::ShaderStage::COMPUTE; if let Some(ref interface) = shader_module.interface { @@ -1902,15 +1917,13 @@ impl Device { None } }; - let _ = interface - .check_stage( - provided_layouts.as_ref().map(|p| p.as_slice()), - &mut derived_group_layouts, - &entry_point_name, - flag, - io, - ) - .map_err(pipeline::CreateComputePipelineError::Stage)?; + let _ = interface.check_stage( + provided_layouts.as_ref().map(|p| p.as_slice()), + &mut derived_group_layouts, + &entry_point_name, + flag, + io, + )?; } else if desc.layout.is_none() { return Err(pipeline::ImplicitLayoutError::ReflectionError(flag).into()); } @@ -1926,8 +1939,8 @@ impl Device { // TODO let parent = hal::pso::BasePipeline::None; - let (pipeline_layout_id, derived_bind_group_count) = match desc.layout { - Some(id) => (id, 0), + let pipeline_layout_id = match desc.layout { + Some(id) => id, None => self.derive_pipeline_layout( self_id, implicit_context, @@ -1976,7 +1989,7 @@ impl Device { }, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }; - Ok((pipeline, derived_bind_group_count, pipeline_layout_id)) + Ok(pipeline) } fn create_render_pipeline( @@ -1986,18 +1999,20 @@ impl Device { implicit_context: Option, hub: &Hub, token: &mut Token, - ) -> Result< - ( - pipeline::RenderPipeline, - pipeline::ImplicitBindGroupCount, - id::PipelineLayoutId, - ), - pipeline::CreateRenderPipelineError, - > { + ) -> Result, pipeline::CreateRenderPipelineError> { //TODO: only lock mutable if the layout is derived let (mut pipeline_layout_guard, mut token) = hub.pipeline_layouts.write(token); let (mut bgl_guard, mut token) = hub.bind_group_layouts.write(&mut token); + // This has to be done first, or otherwise the IDs may be pointing to entries + // that are not even in the storage. + if let Some(ref ids) = implicit_context { + pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + for &bgl_id in ids.group_ids.iter() { + bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); + } + } + let mut derived_group_layouts = ArrayVec::<[binding_model::BindEntryMap; MAX_BIND_GROUPS]>::new(); @@ -2080,7 +2095,7 @@ impl Device { }); io.insert( attribute.shader_location, - validation::NumericType::from_vertex_format(attribute.format), + validation::InterfaceVar::vertex_attribute(attribute.format), ); } } @@ -2112,27 +2127,6 @@ impl Device { ); } - let input_assembler = conv::map_primitive_state_to_input_assembler(&desc.primitive); - - let blender = hal::pso::BlendDesc { - logic_op: None, // TODO - targets: color_states - .iter() - .map(conv::map_color_target_state) - .collect(), - }; - let depth_stencil = depth_stencil_state - .map(conv::map_depth_stencil_state) - .unwrap_or_default(); - - // TODO - let baked_states = hal::pso::BakedStates { - viewport: None, - scissor: None, - blend_color: None, - depth_bounds: None, - }; - if desc.primitive.clamp_depth && !self.features.contains(wgt::Features::DEPTH_CLAMPING) { return Err(pipeline::CreateRenderPipelineError::MissingFeature( wgt::Features::DEPTH_CLAMPING, @@ -2162,6 +2156,29 @@ impl Device { ); } + let input_assembler = conv::map_primitive_state_to_input_assembler(&desc.primitive); + + let mut blender = hal::pso::BlendDesc { + logic_op: None, + targets: Vec::with_capacity(color_states.len()), + }; + for (i, cs) in color_states.iter().enumerate() { + let bt = conv::map_color_target_state(cs) + .map_err(|error| pipeline::CreateRenderPipelineError::ColorState(i as u8, error))?; + blender.targets.push(bt); + } + + let depth_stencil = depth_stencil_state + .map(conv::map_depth_stencil_state) + .unwrap_or_default(); + + let baked_states = hal::pso::BakedStates { + viewport: None, + scissor: None, + blend_constants: None, + depth_bounds: None, + }; + if desc.layout.is_none() { for _ in 0..self.limits.max_bind_groups { derived_group_layouts.push(binding_model::BindEntryMap::default()); @@ -2226,19 +2243,22 @@ impl Device { let shader_module = shader_module_guard.get(stage.module).map_err(|_| { pipeline::CreateRenderPipelineError::Stage { - flag, + stage: flag, error: validation::StageError::InvalidModule, } })?; if let Some(ref interface) = shader_module.interface { let provided_layouts = match desc.layout { - Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( - pipeline_layout_guard + Some(pipeline_layout_id) => { + let pipeline_layout = pipeline_layout_guard .get(pipeline_layout_id) - .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?, - &*bgl_guard, - )), + .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; + Some(Device::get_introspection_bind_group_layouts( + pipeline_layout, + &*bgl_guard, + )) + } None => None, }; @@ -2250,7 +2270,10 @@ impl Device { flag, io, ) - .map_err(|error| pipeline::CreateRenderPipelineError::Stage { flag, error })?; + .map_err(|error| pipeline::CreateRenderPipelineError::Stage { + stage: flag, + error, + })?; validated_stages |= flag; } @@ -2270,7 +2293,7 @@ impl Device { shader_module_guard .get(fragment.stage.module) .map_err(|_| pipeline::CreateRenderPipelineError::Stage { - flag, + stage: flag, error: validation::StageError::InvalidModule, })?; @@ -2295,7 +2318,7 @@ impl Device { io, ) .map_err(|error| pipeline::CreateRenderPipelineError::Stage { - flag, + stage: flag, error, })?; validated_stages |= flag; @@ -2314,26 +2337,26 @@ impl Device { if validated_stages.contains(wgt::ShaderStage::FRAGMENT) { for (i, state) in color_states.iter().enumerate() { match io.get(&(i as wgt::ShaderLocation)) { - Some(output) if validation::check_texture_format(state.format, output) => {} - Some(output) => { - log::warn!( - "Incompatible fragment output[{}] from shader: {:?}, expected {:?}", - i, - output, - state.format, - ); - return Err( - pipeline::CreateRenderPipelineError::IncompatibleOutputFormat { - index: i as u8, + Some(ref output) => { + validation::check_texture_format(state.format, &output.ty).map_err( + |pipeline| { + pipeline::CreateRenderPipelineError::ColorState( + i as u8, + pipeline::ColorStateError::IncompatibleFormat { + pipeline, + shader: output.ty, + }, + ) }, - ); + )?; } None if state.write_mask.is_empty() => {} None => { log::warn!("Missing fragment output[{}], expected {:?}", i, state,); - return Err(pipeline::CreateRenderPipelineError::MissingOutput { - index: i as u8, - }); + return Err(pipeline::CreateRenderPipelineError::ColorState( + i as u8, + pipeline::ColorStateError::Missing, + )); } } } @@ -2360,8 +2383,8 @@ impl Device { // TODO let parent = hal::pso::BasePipeline::None; - let (pipeline_layout_id, derived_bind_group_count) = match desc.layout { - Some(id) => (id, 0), + let pipeline_layout_id = match desc.layout { + Some(id) => id, None => self.derive_pipeline_layout( self_id, implicit_context, @@ -2432,8 +2455,8 @@ impl Device { let mut flags = pipeline::PipelineFlags::empty(); for state in color_states.iter() { if let Some(ref bs) = state.blend { - if bs.color.uses_color() | bs.alpha.uses_color() { - flags |= pipeline::PipelineFlags::BLEND_COLOR; + if bs.color.uses_constant() | bs.alpha.uses_constant() { + flags |= pipeline::PipelineFlags::BLEND_CONSTANT; } } } @@ -2462,7 +2485,7 @@ impl Device { vertex_strides, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }; - Ok((pipeline, derived_bind_group_count, pipeline_layout_id)) + Ok(pipeline) } fn wait_for_submit( @@ -3376,7 +3399,7 @@ impl Global { let mut entry_map = FastHashMap::default(); for entry in desc.entries.iter() { - if entry_map.insert(entry.binding, entry.clone()).is_some() { + if entry_map.insert(entry.binding, *entry).is_some() { break 'outer binding_model::CreateBindGroupLayoutError::ConflictBinding( entry.binding, ); @@ -4009,7 +4032,6 @@ impl Global { implicit_pipeline_ids: Option>, ) -> ( id::RenderPipelineId, - pipeline::ImplicitBindGroupCount, Option, ) { profiling::scope!("Device::create_render_pipeline"); @@ -4035,19 +4057,23 @@ impl Global { }); } - let (pipeline, derived_bind_group_count, _layout_id) = match device - .create_render_pipeline(device_id, desc, implicit_context, &hub, &mut token) - { + let pipeline = match device.create_render_pipeline( + device_id, + desc, + implicit_context, + &hub, + &mut token, + ) { Ok(pair) => pair, Err(e) => break e, }; let id = fid.assign(pipeline, &mut token); - return (id.0, derived_bind_group_count, None); + return (id.0, None); }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); - (id, 0, Some(error)) + (id, Some(error)) } /// Get an ID of one of the bind group layouts. The ID adds a refcount, @@ -4137,7 +4163,6 @@ impl Global { implicit_pipeline_ids: Option>, ) -> ( id::ComputePipelineId, - pipeline::ImplicitBindGroupCount, Option, ) { profiling::scope!("Device::create_compute_pipeline"); @@ -4163,19 +4188,23 @@ impl Global { }); } - let (pipeline, derived_bind_group_count, _layout_id) = match device - .create_compute_pipeline(device_id, desc, implicit_context, &hub, &mut token) - { + let pipeline = match device.create_compute_pipeline( + device_id, + desc, + implicit_context, + &hub, + &mut token, + ) { Ok(pair) => pair, Err(e) => break e, }; let id = fid.assign(pipeline, &mut token); - return (id.0, derived_bind_group_count, None); + return (id.0, None); }; let id = fid.assign_error(desc.label.borrow_or_default(), &mut token); - (id, 0, Some(error)) + (id, Some(error)) } /// Get an ID of one of the bind group layouts. The ID adds a refcount, @@ -4525,9 +4554,7 @@ impl Global { HostMap::Write => (wgt::BufferUsage::MAP_WRITE, resource::BufferUse::MAP_WRITE), }; - if range.start % wgt::COPY_BUFFER_ALIGNMENT != 0 - || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 - { + if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(resource::BufferAccessError::UnalignedRange); } @@ -4597,10 +4624,10 @@ impl Global { buffer.size - offset }; - if offset % 8 != 0 { + if offset % wgt::MAP_ALIGNMENT != 0 { return Err(resource::BufferAccessError::UnalignedOffset { offset }); } - if range_size % 4 != 0 { + if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(resource::BufferAccessError::UnalignedRangeSize { range_size }); } diff --git a/gfx/wgpu/wgpu-core/src/device/queue.rs b/gfx/wgpu/wgpu-core/src/device/queue.rs index be019a517788..622019fff5e6 100644 --- a/gfx/wgpu/wgpu-core/src/device/queue.rs +++ b/gfx/wgpu/wgpu-core/src/device/queue.rs @@ -318,7 +318,7 @@ impl Global { trace.add(Action::WriteTexture { to: destination.clone(), data: data_path, - layout: data_layout.clone(), + layout: *data_layout, size: *size, }); } diff --git a/gfx/wgpu/wgpu-core/src/hub.rs b/gfx/wgpu/wgpu-core/src/hub.rs index 5e71604fbb21..5054a7f5cddf 100644 --- a/gfx/wgpu/wgpu-core/src/hub.rs +++ b/gfx/wgpu/wgpu-core/src/hub.rs @@ -180,6 +180,11 @@ impl Storage { self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } + pub(crate) fn force_replace(&mut self, id: I, value: T) { + let (index, epoch, _) = id.unzip(); + self.map[index as usize] = Element::Occupied(value, epoch); + } + pub(crate) fn remove(&mut self, id: I) -> Option { let (index, epoch, _) = id.unzip(); match std::mem::replace(&mut self.map[index as usize], Element::Vacant) { diff --git a/gfx/wgpu/wgpu-core/src/pipeline.rs b/gfx/wgpu/wgpu-core/src/pipeline.rs index e96e1510cfad..c8661e572c06 100644 --- a/gfx/wgpu/wgpu-core/src/pipeline.rs +++ b/gfx/wgpu/wgpu-core/src/pipeline.rs @@ -111,8 +111,8 @@ pub enum CreateComputePipelineError { InvalidLayout, #[error("unable to derive an implicit layout")] Implicit(#[from] ImplicitLayoutError), - #[error(transparent)] - Stage(validation::StageError), + #[error("error matching shader requirements against the pipeline")] + Stage(#[from] validation::StageError), #[error("Internal error: {0}")] Internal(String), #[error( @@ -196,6 +196,19 @@ pub struct RenderPipelineDescriptor<'a> { pub fragment: Option>, } +#[derive(Clone, Debug, Error)] +pub enum ColorStateError { + #[error("output is missing")] + Missing, + #[error("output format {pipeline} is incompatible with the shader {shader}")] + IncompatibleFormat { + pipeline: validation::NumericType, + shader: validation::NumericType, + }, + #[error("blend factors for {0:?} must be `One`")] + InvalidMinMaxBlendFactors(wgt::BlendComponent), +} + #[derive(Clone, Debug, Error)] pub enum CreateRenderPipelineError { #[error(transparent)] @@ -204,10 +217,8 @@ pub enum CreateRenderPipelineError { InvalidLayout, #[error("unable to derive an implicit layout")] Implicit(#[from] ImplicitLayoutError), - #[error("missing output at index {index}")] - MissingOutput { index: u8 }, - #[error("incompatible output format at index {index}")] - IncompatibleOutputFormat { index: u8 }, + #[error("color state [{0}] is invalid")] + ColorState(u8, #[source] ColorStateError), #[error("invalid sample count {0}")] InvalidSampleCount(u32), #[error("the number of vertex buffers {given} exceeds the limit {limit}")] @@ -235,13 +246,13 @@ pub enum CreateRenderPipelineError { ConservativeRasterizationNonFillPolygonMode, #[error("missing required device features {0:?}")] MissingFeature(wgt::Features), - #[error("error in stage {flag:?}")] + #[error("error matching {stage:?} shader requirements against the pipeline")] Stage { - flag: wgt::ShaderStage, + stage: wgt::ShaderStage, #[source] error: validation::StageError, }, - #[error("Internal error in stage {stage:?}: {error}")] + #[error("Internal error in {stage:?} shader: {error}")] Internal { stage: wgt::ShaderStage, error: String, @@ -251,7 +262,7 @@ pub enum CreateRenderPipelineError { bitflags::bitflags! { #[repr(transparent)] pub struct PipelineFlags: u32 { - const BLEND_COLOR = 1; + const BLEND_CONSTANT = 1; const STENCIL_REFERENCE = 2; const WRITES_DEPTH_STENCIL = 4; } diff --git a/gfx/wgpu/wgpu-core/src/resource.rs b/gfx/wgpu/wgpu-core/src/resource.rs index 4a9c649ff270..398166e90c29 100644 --- a/gfx/wgpu/wgpu-core/src/resource.rs +++ b/gfx/wgpu/wgpu-core/src/resource.rs @@ -142,7 +142,9 @@ pub enum BufferAccessError { MissingBufferUsage(#[from] MissingBufferUsageError), #[error("buffer is not mapped")] NotMapped, - #[error("buffer map range does not respect `COPY_BUFFER_ALIGNMENT`")] + #[error( + "buffer map range must start aligned to `MAP_ALIGNMENT` and end to `COPY_BUFFER_ALIGNMENT`" + )] UnalignedRange, #[error("buffer offset invalid: offset {offset} must be multiple of 8")] UnalignedOffset { offset: wgt::BufferAddress }, @@ -444,6 +446,8 @@ pub struct Sampler { pub(crate) life_guard: LifeGuard, /// `true` if this is a comparison sampler pub(crate) comparison: bool, + /// `true` if this is a filtering sampler + pub(crate) filtering: bool, } #[derive(Clone, Debug, Error)] diff --git a/gfx/wgpu/wgpu-core/src/track/mod.rs b/gfx/wgpu/wgpu-core/src/track/mod.rs index bf9c39050880..9313fc17df11 100644 --- a/gfx/wgpu/wgpu-core/src/track/mod.rs +++ b/gfx/wgpu/wgpu-core/src/track/mod.rs @@ -142,6 +142,15 @@ impl PendingTransition { } } +impl From> for UsageConflict { + fn from(e: PendingTransition) -> Self { + Self::Buffer { + id: e.id.0, + combined_use: e.usage.end, + } + } +} + impl PendingTransition { /// Produce the gfx-hal barrier corresponding to the transition. pub fn into_hal<'a, B: hal::Backend>( @@ -167,6 +176,17 @@ impl PendingTransition { } } +impl From> for UsageConflict { + fn from(e: PendingTransition) -> Self { + Self::Texture { + id: e.id.0, + mip_levels: e.selector.levels.start as u32..e.selector.levels.end as u32, + array_layers: e.selector.layers.start as u32..e.selector.layers.end as u32, + combined_use: e.usage.end, + } + } +} + #[derive(Clone, Debug, Error)] pub enum UseExtendError { #[error("resource is invalid")] @@ -607,20 +627,8 @@ impl TrackerSet { /// Merge all the trackers of another instance by extending /// the usage. Panics on a conflict. pub fn merge_extend(&mut self, other: &Self) -> Result<(), UsageConflict> { - self.buffers - .merge_extend(&other.buffers) - .map_err(|e| UsageConflict::Buffer { - id: e.id.0, - combined_use: e.usage.end, - })?; - self.textures - .merge_extend(&other.textures) - .map_err(|e| UsageConflict::Texture { - id: e.id.0, - mip_levels: e.selector.levels.start as u32..e.selector.levels.end as u32, - array_layers: e.selector.layers.start as u32..e.selector.layers.end as u32, - combined_use: e.usage.end, - })?; + self.buffers.merge_extend(&other.buffers)?; + self.textures.merge_extend(&other.textures)?; self.views.merge_extend(&other.views).unwrap(); self.bind_groups.merge_extend(&other.bind_groups).unwrap(); self.samplers.merge_extend(&other.samplers).unwrap(); diff --git a/gfx/wgpu/wgpu-core/src/validation.rs b/gfx/wgpu/wgpu-core/src/validation.rs index e96a127efdcd..ddd588f07496 100644 --- a/gfx/wgpu/wgpu-core/src/validation.rs +++ b/gfx/wgpu/wgpu-core/src/validation.rs @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::{binding_model::BindEntryMap, FastHashMap}; +use crate::{binding_model::BindEntryMap, FastHashMap, FastHashSet}; use naga::valid::GlobalUse; -use std::collections::hash_map::Entry; +use std::{collections::hash_map::Entry, fmt}; use thiserror::Error; use wgt::{BindGroupLayoutEntry, BindingType}; @@ -25,8 +25,8 @@ enum ResourceType { #[derive(Debug)] struct Resource { - group: u32, - binding: u32, + name: Option, + bind: naga::ResourceBinding, ty: ResourceType, class: naga::StorageClass, } @@ -38,6 +38,16 @@ enum NumericDimension { Matrix(naga::VectorSize, naga::VectorSize), } +impl fmt::Display for NumericDimension { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Scalar => write!(f, ""), + Self::Vector(size) => write!(f, "x{}", size as u8), + Self::Matrix(columns, rows) => write!(f, "x{}{}", columns as u8, rows as u8), + } + } +} + #[derive(Clone, Copy, Debug)] pub struct NumericType { dim: NumericDimension, @@ -45,9 +55,42 @@ pub struct NumericType { width: naga::Bytes, } +impl fmt::Display for NumericType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}{}{}", self.kind, self.width * 8, self.dim) + } +} + +#[derive(Clone, Debug)] +pub struct InterfaceVar { + pub ty: NumericType, + interpolation: Option, + sampling: Option, +} + +impl InterfaceVar { + pub fn vertex_attribute(format: wgt::VertexFormat) -> Self { + InterfaceVar { + ty: NumericType::from_vertex_format(format), + interpolation: None, + sampling: None, + } + } +} + +impl fmt::Display for InterfaceVar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{} interpolated as {:?} with sampling {:?}", + self.ty, self.interpolation, self.sampling + ) + } +} + #[derive(Debug)] enum Varying { - Local { location: u32, ty: NumericType }, + Local { location: u32, iv: InterfaceVar }, BuiltIn(naga::BuiltIn), } @@ -63,6 +106,7 @@ struct EntryPoint { outputs: Vec, resources: Vec<(naga::Handle, GlobalUse)>, spec_constants: Vec, + sampling_pairs: FastHashSet<(naga::Handle, naga::Handle)>, } #[derive(Debug)] @@ -117,8 +161,11 @@ pub enum BindingError { Missing, #[error("visibility flags don't include the shader stage")] Invisible, - #[error("load/store access flags {0:?} don't match the shader")] - WrongUsage(GlobalUse), + #[error("The shader requires the load/store access flags {required:?} but only {allowed:?} is allowed")] + WrongUsage { + required: GlobalUse, + allowed: GlobalUse, + }, #[error("type on the shader side does not match the pipeline binding")] WrongType, #[error("buffer structure size {0}, added to one element of an unbound array, if it's the last field, ended up greater than the given `min_binding_size`")] @@ -142,12 +189,24 @@ pub enum BindingError { BadStorageFormat(wgt::TextureFormat), } +#[derive(Clone, Debug, Error)] +pub enum FilteringError { + #[error("integer textures can't be sampled")] + Integer, + #[error("non-filterable float texture")] + NonFilterable, +} + #[derive(Clone, Debug, Error)] pub enum InputError { #[error("input is not provided by the earlier stage in the pipeline")] Missing, - #[error("input type is not compatible with the provided")] - WrongType, + #[error("input type is not compatible with the provided {0}")] + WrongType(NumericType), + #[error("input interpolation doesn't match provided {0:?}")] + InterpolationMismatch(Option), + #[error("input sampling doesn't match provided {0:?}")] + SamplingMismatch(Option), } /// Errors produced when validating a programmable stage of a pipeline. @@ -155,19 +214,22 @@ pub enum InputError { pub enum StageError { #[error("shader module is invalid")] InvalidModule, - #[error("unable to find an entry point at {0:?} stage")] + #[error("unable to find entry point '{0:?}'")] MissingEntryPoint(String), - #[error("error matching global binding at index {binding} in group {group} against the pipeline layout: {error}")] - Binding { - group: u32, - binding: u32, - error: BindingError, + #[error("shader global {0:?} is not available in the layout pipeline layout")] + Binding(naga::ResourceBinding, #[source] BindingError), + #[error("unable to filter the texture ({texture:?}) by the sampler ({sampler:?})")] + Filtering { + texture: naga::ResourceBinding, + sampler: naga::ResourceBinding, + #[source] + error: FilteringError, }, - #[error( - "error matching the stage input at {location} against the previous stage outputs: {error}" - )] + #[error("location[{location}] {var} is not provided by the previous stage outputs")] Input { location: wgt::ShaderLocation, + var: InterfaceVar, + #[source] error: InputError, }, } @@ -253,7 +315,7 @@ impl Resource { let global_use = match ty { wgt::BufferBindingType::Uniform | wgt::BufferBindingType::Storage { read_only: true } => { - GlobalUse::READ + GlobalUse::READ | GlobalUse::QUERY } wgt::BufferBindingType::Storage { read_only: _ } => GlobalUse::all(), }; @@ -346,7 +408,7 @@ impl Resource { }, wgt::TextureSampleType::Depth => naga::ImageClass::Depth, }; - (class, GlobalUse::READ) + (class, GlobalUse::READ | GlobalUse::QUERY) } BindingType::StorageTexture { access, @@ -356,8 +418,12 @@ impl Resource { let naga_format = map_storage_format_to_naga(format) .ok_or(BindingError::BadStorageFormat(format))?; let usage = match access { - wgt::StorageTextureAccess::ReadOnly => GlobalUse::READ, - wgt::StorageTextureAccess::WriteOnly => GlobalUse::WRITE, + wgt::StorageTextureAccess::ReadOnly => { + GlobalUse::READ | GlobalUse::QUERY + } + wgt::StorageTextureAccess::WriteOnly => { + GlobalUse::WRITE | GlobalUse::QUERY + } wgt::StorageTextureAccess::ReadWrite => GlobalUse::all(), }; (naga::ImageClass::Storage(naga_format), usage) @@ -377,7 +443,10 @@ impl Resource { if allowed_usage.contains(shader_usage) { Ok(()) } else { - Err(BindingError::WrongUsage(shader_usage)) + Err(BindingError::WrongUsage { + required: shader_usage, + allowed: allowed_usage, + }) } } @@ -451,7 +520,7 @@ impl Resource { } impl NumericType { - pub fn from_vertex_format(format: wgt::VertexFormat) -> Self { + fn from_vertex_format(format: wgt::VertexFormat) -> Self { use naga::{ScalarKind as Sk, VectorSize as Vs}; use wgt::VertexFormat as Vf; @@ -615,14 +684,35 @@ impl NumericType { _ => false, } } + + fn is_compatible_with(&self, other: &NumericType) -> bool { + if self.kind != other.kind { + return false; + } + match (self.dim, other.dim) { + (NumericDimension::Scalar, NumericDimension::Scalar) => true, + (NumericDimension::Scalar, NumericDimension::Vector(_)) => true, + (NumericDimension::Vector(_), NumericDimension::Vector(_)) => true, + (NumericDimension::Matrix(..), NumericDimension::Matrix(..)) => true, + _ => false, + } + } } /// Return true if the fragment `format` is covered by the provided `output`. -pub fn check_texture_format(format: wgt::TextureFormat, output: &NumericType) -> bool { - NumericType::from_texture_format(format).is_subtype_of(output) +pub fn check_texture_format( + format: wgt::TextureFormat, + output: &NumericType, +) -> Result<(), NumericType> { + let nt = NumericType::from_texture_format(format); + if nt.is_subtype_of(output) { + Ok(()) + } else { + Err(nt) + } } -pub type StageIo = FastHashMap; +pub type StageIo = FastHashMap; impl Interface { fn populate( @@ -651,10 +741,7 @@ impl Interface { kind: naga::ScalarKind::Float, width, }, - naga::TypeInner::Struct { - block: _, - ref members, - } => { + naga::TypeInner::Struct { ref members, .. } => { for member in members { Self::populate(list, member.binding.as_ref(), member.ty, arena); } @@ -667,9 +754,17 @@ impl Interface { }; let varying = match binding { - Some(&naga::Binding::Location(location, _)) => Varying::Local { + Some(&naga::Binding::Location { location, - ty: numeric_ty, + interpolation, + sampling, + }) => Varying::Local { + location, + iv: InterfaceVar { + ty: numeric_ty, + interpolation, + sampling, + }, }, Some(&naga::Binding::BuiltIn(built_in)) => Varying::BuiltIn(built_in), None => { @@ -684,20 +779,18 @@ impl Interface { let mut resources = naga::Arena::new(); let mut resource_mapping = FastHashMap::default(); for (var_handle, var) in module.global_variables.iter() { - let (group, binding) = match var.binding { - Some(ref br) => (br.group, br.binding), + let bind = match var.binding { + Some(ref br) => br.clone(), _ => continue, }; let ty = match module.types[var.ty].inner { naga::TypeInner::Struct { - block: true, + level: naga::StructLevel::Root, members: _, - } => { - let actual_size = info.layouter[var.ty].size; - ResourceType::Buffer { - size: wgt::BufferSize::new(actual_size as u64).unwrap(), - } - } + span, + } => ResourceType::Buffer { + size: wgt::BufferSize::new(span as u64).unwrap(), + }, naga::TypeInner::Image { dim, arrayed, @@ -714,8 +807,8 @@ impl Interface { } }; let handle = resources.append(Resource { - group, - binding, + name: var.name.clone(), + bind, ty, class: var.class, }); @@ -780,12 +873,13 @@ impl Interface { .get(&pair) .ok_or(StageError::MissingEntryPoint(pair.1))?; + // check resources visibility for &(handle, usage) in entry_point.resources.iter() { let res = &self.resources[handle]; let result = match given_layouts { Some(layouts) => layouts - .get(res.group as usize) - .and_then(|map| map.get(&res.binding)) + .get(res.bind.group as usize) + .and_then(|map| map.get(&res.bind.binding)) .ok_or(BindingError::Missing) .and_then(|entry| { if entry.visibility.contains(stage_bit) { @@ -796,11 +890,11 @@ impl Interface { }) .and_then(|entry| res.check_binding_use(entry, usage)), None => derived_layouts - .get_mut(res.group as usize) + .get_mut(res.bind.group as usize) .ok_or(BindingError::Missing) .and_then(|set| { let ty = res.derive_binding_type(usage)?; - match set.entry(res.binding) { + match set.entry(res.bind.binding) { Entry::Occupied(e) if e.get().ty != ty => { return Err(BindingError::InconsistentlyDerivedType) } @@ -809,7 +903,7 @@ impl Interface { } Entry::Vacant(e) => { e.insert(BindGroupLayoutEntry { - binding: res.binding, + binding: res.bind.binding, ty, visibility: stage_bit, count: None, @@ -820,30 +914,93 @@ impl Interface { }), }; if let Err(error) = result { - return Err(StageError::Binding { - group: res.group, - binding: res.binding, - error, - }); + return Err(StageError::Binding(res.bind.clone(), error)); } } + // check the compatibility between textures and samplers + if let Some(layouts) = given_layouts { + for &(texture_handle, sampler_handle) in entry_point.sampling_pairs.iter() { + let texture_bind = &self.resources[texture_handle].bind; + let sampler_bind = &self.resources[sampler_handle].bind; + let texture_layout = &layouts[texture_bind.group as usize][&texture_bind.binding]; + let sampler_layout = &layouts[sampler_bind.group as usize][&sampler_bind.binding]; + assert!(texture_layout.visibility.contains(stage_bit)); + assert!(sampler_layout.visibility.contains(stage_bit)); + + let error = match texture_layout.ty { + wgt::BindingType::Texture { + sample_type: wgt::TextureSampleType::Float { filterable }, + .. + } => match sampler_layout.ty { + wgt::BindingType::Sampler { + filtering: true, .. + } if !filterable => Some(FilteringError::NonFilterable), + _ => None, + }, + wgt::BindingType::Texture { + sample_type: wgt::TextureSampleType::Sint, + .. + } + | wgt::BindingType::Texture { + sample_type: wgt::TextureSampleType::Uint, + .. + } => Some(FilteringError::Integer), + _ => None, // unreachable, really + }; + + if let Some(error) = error { + return Err(StageError::Filtering { + texture: texture_bind.clone(), + sampler: sampler_bind.clone(), + error, + }); + } + } + } + + // check inputs compatibility for input in entry_point.inputs.iter() { match *input { - Varying::Local { location, ty } => { + Varying::Local { location, ref iv } => { let result = inputs .get(&location) .ok_or(InputError::Missing) .and_then(|provided| { - if ty.is_subtype_of(provided) { + let compatible = match shader_stage { + // For vertex attributes, there are defaults filled out + // by the driver if data is not provided. + naga::ShaderStage::Vertex => { + iv.ty.is_compatible_with(&provided.ty) + } + naga::ShaderStage::Fragment => { + if iv.interpolation != provided.interpolation { + return Err(InputError::InterpolationMismatch( + provided.interpolation, + )); + } + if iv.sampling != provided.sampling { + return Err(InputError::SamplingMismatch( + provided.sampling, + )); + } + iv.ty.is_subtype_of(&provided.ty) + } + naga::ShaderStage::Compute => false, + }; + if compatible { Ok(()) } else { - Err(InputError::WrongType) + Err(InputError::WrongType(provided.ty)) } }); if let Err(error) = result { - return Err(StageError::Input { location, error }); + return Err(StageError::Input { + location, + var: iv.clone(), + error, + }); } } Varying::BuiltIn(_) => {} @@ -854,7 +1011,7 @@ impl Interface { .outputs .iter() .filter_map(|output| match *output { - Varying::Local { location, ty } => Some((location, ty)), + Varying::Local { location, ref iv } => Some((location, iv.clone())), Varying::BuiltIn(_) => None, }) .collect(); diff --git a/gfx/wgpu/wgpu-types/src/lib.rs b/gfx/wgpu/wgpu-types/src/lib.rs index 48224f9f14eb..a1f2762ec030 100644 --- a/gfx/wgpu/wgpu-types/src/lib.rs +++ b/gfx/wgpu/wgpu-types/src/lib.rs @@ -40,6 +40,8 @@ pub const COPY_BYTES_PER_ROW_ALIGNMENT: u32 = 256; pub const BIND_BUFFER_ALIGNMENT: BufferAddress = 256; /// Buffer to buffer copy offsets and sizes must be aligned to this number. pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4; +/// Size to align mappings. +pub const MAP_ALIGNMENT: BufferAddress = 8; /// Vertex buffer strides have to be aligned to this number. pub const VERTEX_STRIDE_ALIGNMENT: BufferAddress = 4; /// Alignment all push constants need @@ -604,7 +606,7 @@ pub enum ShaderModel { /// Supported physical device types. #[repr(u8)] -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] pub enum DeviceType { @@ -755,18 +757,18 @@ pub enum BlendFactor { Zero = 0, /// 1.0 One = 1, - /// S.color - SrcColor = 2, - /// 1.0 - S.color - OneMinusSrcColor = 3, + /// S.component + Src = 2, + /// 1.0 - S.component + OneMinusSrc = 3, /// S.alpha SrcAlpha = 4, /// 1.0 - S.alpha OneMinusSrcAlpha = 5, - /// D.color - DstColor = 6, - /// 1.0 - D.color - OneMinusDstColor = 7, + /// D.component + Dst = 6, + /// 1.0 - D.component + OneMinusDst = 7, /// D.alpha DstAlpha = 8, /// 1.0 - D.alpha @@ -774,9 +776,9 @@ pub enum BlendFactor { /// min(S.alpha, 1.0 - D.alpha) SrcAlphaSaturated = 10, /// Constant - BlendColor = 11, + Constant = 11, /// 1.0 - Constant - OneMinusBlendColor = 12, + OneMinusConstant = 12, } /// Alpha blend operation. @@ -807,7 +809,7 @@ impl Default for BlendOperation { /// Describes the blend component of a pipeline. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BlendComponent { @@ -822,14 +824,14 @@ pub struct BlendComponent { impl BlendComponent { /// Default blending state that replaces destination with the source. - pub const REPLACE: Self = BlendComponent { + pub const REPLACE: Self = Self { src_factor: BlendFactor::One, dst_factor: BlendFactor::Zero, operation: BlendOperation::Add, }; /// Blend state of (1 * src) + ((1 - src_alpha) * dst) - pub const OVER: Self = BlendComponent { + pub const OVER: Self = Self { src_factor: BlendFactor::One, dst_factor: BlendFactor::OneMinusSrcAlpha, operation: BlendOperation::Add, @@ -837,12 +839,12 @@ impl BlendComponent { /// Returns true if the state relies on the constant color, which is /// set independently on a render command encoder. - pub fn uses_color(&self) -> bool { + pub fn uses_constant(&self) -> bool { match (self.src_factor, self.dst_factor) { - (BlendFactor::BlendColor, _) - | (BlendFactor::OneMinusBlendColor, _) - | (_, BlendFactor::BlendColor) - | (_, BlendFactor::OneMinusBlendColor) => true, + (BlendFactor::Constant, _) + | (BlendFactor::OneMinusConstant, _) + | (_, BlendFactor::Constant) + | (_, BlendFactor::OneMinusConstant) => true, (_, _) => false, } } @@ -858,7 +860,7 @@ impl Default for BlendComponent { /// /// See the OpenGL or Vulkan spec for more information. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BlendState { @@ -1007,7 +1009,7 @@ impl Default for PolygonMode { /// Describes the state of primitive assembly and rasterization in a render pipeline. #[repr(C)] -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct PrimitiveState { @@ -1042,7 +1044,7 @@ pub struct PrimitiveState { /// Describes the multi-sampling state of a render pipeline. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct MultisampleState { @@ -1718,7 +1720,7 @@ impl StencilState { /// Describes the biasing setting for the depth target. #[repr(C)] -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct DepthBiasState { @@ -1820,7 +1822,7 @@ impl Default for StencilOperation { /// /// If you are not using stencil state, set this to [`StencilFaceState::IGNORE`]. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct StencilFaceState { @@ -1906,7 +1908,7 @@ impl Default for InputStepMode { /// /// Arrays of these can be made with the [`vertex_attr_array`] macro. Vertex attributes are assumed to be tightly packed. #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct VertexAttribute { @@ -2594,7 +2596,7 @@ impl Default for RenderBundleDescriptor> { /// Layout of a texture in a buffer's memory. #[repr(C)] -#[derive(Clone, Debug, Default)] +#[derive(Clone, Copy, Debug, Default)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] pub struct ImageDataLayout { @@ -2835,7 +2837,7 @@ impl BindingType { } /// Describes a single binding inside a bind group. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BindGroupLayoutEntry { @@ -2970,7 +2972,7 @@ bitflags::bitflags! { /// Argument buffer layout for draw_indirect commands. #[repr(C)] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct DrawIndirectArgs { /// The number of vertices to draw. pub vertex_count: u32, @@ -2984,7 +2986,7 @@ pub struct DrawIndirectArgs { /// Argument buffer layout for draw_indexed_indirect commands. #[repr(C)] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct DrawIndexedIndirectArgs { /// The number of indices to draw. pub index_count: u32, @@ -3000,7 +3002,7 @@ pub struct DrawIndexedIndirectArgs { /// Argument buffer layout for dispatch_indirect commands. #[repr(C)] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub struct DispatchIndirectArgs { /// X dimension of the grid of workgroups to dispatch. pub group_size_x: u32, diff --git a/gfx/wgpu_bindings/src/server.rs b/gfx/wgpu_bindings/src/server.rs index 87bb70eb6b58..bb3fcd3e8c1c 100644 --- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -234,7 +234,7 @@ trait GlobalExt { self_id: id::DeviceId, action: DeviceAction, error_buf: ErrorBuffer, - ) -> Vec; + ); fn texture_action( &self, self_id: id::TextureId, @@ -255,8 +255,7 @@ impl GlobalExt for Global { self_id: id::DeviceId, action: DeviceAction, mut error_buf: ErrorBuffer, - ) -> Vec { - let mut drop_actions = Vec::new(); + ) { match action { DeviceAction::CreateBuffer(id, desc) => { let (_, error) = self.device_create_buffer::(self_id, &desc, id); @@ -313,20 +312,11 @@ impl GlobalExt for Global { root_id: imp.pipeline, group_ids: &imp.bind_groups, }); - let (_, group_count, error) = + let (_, error) = self.device_create_compute_pipeline::(self_id, &desc, id, implicit_ids); if let Some(err) = error { error_buf.init(err); } - if let Some(ref imp) = implicit { - for &bgl_id in imp.bind_groups[group_count as usize..].iter() { - bincode::serialize_into( - &mut drop_actions, - &DropAction::BindGroupLayout(bgl_id), - ) - .unwrap(); - } - } } DeviceAction::CreateRenderPipeline(id, desc, implicit) => { let implicit_ids = implicit @@ -335,20 +325,11 @@ impl GlobalExt for Global { root_id: imp.pipeline, group_ids: &imp.bind_groups, }); - let (_, group_count, error) = + let (_, error) = self.device_create_render_pipeline::(self_id, &desc, id, implicit_ids); if let Some(err) = error { error_buf.init(err); } - if let Some(ref imp) = implicit { - for &bgl_id in imp.bind_groups[group_count as usize..].iter() { - bincode::serialize_into( - &mut drop_actions, - &DropAction::BindGroupLayout(bgl_id), - ) - .unwrap(); - } - } } DeviceAction::CreateRenderBundle(_id, desc, _base) => { wgc::command::RenderBundleEncoder::new(&desc, self_id, None).unwrap(); @@ -360,7 +341,6 @@ impl GlobalExt for Global { } } } - drop_actions } fn texture_action( @@ -478,12 +458,10 @@ pub unsafe extern "C" fn wgpu_server_device_action( global: &Global, self_id: id::DeviceId, byte_buf: &ByteBuf, - drop_byte_buf: &mut ByteBuf, error_buf: ErrorBuffer, ) { let action = bincode::deserialize(byte_buf.as_slice()).unwrap(); - let drop_actions = gfx_select!(self_id => global.device_action(self_id, action, error_buf)); - *drop_byte_buf = ByteBuf::from_vec(drop_actions); + gfx_select!(self_id => global.device_action(self_id, action, error_buf)); } #[no_mangle] diff --git a/third_party/rust/ahash/smhasher/clone_smhasher.sh b/third_party/rust/ahash/smhasher/clone_smhasher.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/ext/debug_marker.rs b/third_party/rust/ash/src/extensions/ext/debug_marker.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/ext/debug_report.rs b/third_party/rust/ash/src/extensions/ext/debug_report.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/ext/debug_utils.rs b/third_party/rust/ash/src/extensions/ext/debug_utils.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/android_surface.rs b/third_party/rust/ash/src/extensions/khr/android_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/display.rs b/third_party/rust/ash/src/extensions/khr/display.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/display_swapchain.rs b/third_party/rust/ash/src/extensions/khr/display_swapchain.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/surface.rs b/third_party/rust/ash/src/extensions/khr/surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/swapchain.rs b/third_party/rust/ash/src/extensions/khr/swapchain.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/wayland_surface.rs b/third_party/rust/ash/src/extensions/khr/wayland_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/win32_surface.rs b/third_party/rust/ash/src/extensions/khr/win32_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/xcb_surface.rs b/third_party/rust/ash/src/extensions/khr/xcb_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/khr/xlib_surface.rs b/third_party/rust/ash/src/extensions/khr/xlib_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/mvk/ios_surface.rs b/third_party/rust/ash/src/extensions/mvk/ios_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/mvk/macos_surface.rs b/third_party/rust/ash/src/extensions/mvk/macos_surface.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/nv/mesh_shader.rs b/third_party/rust/ash/src/extensions/nv/mesh_shader.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/ash/src/extensions/nv/ray_tracing.rs b/third_party/rust/ash/src/extensions/nv/ray_tracing.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/authenticator/testing/run_cross.sh b/third_party/rust/authenticator/testing/run_cross.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/bindgen/src/codegen/bitfield_unit.rs b/third_party/rust/bindgen/src/codegen/bitfield_unit.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/bit-set/deploy-docs.sh b/third_party/rust/bit-set/deploy-docs.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/bit-vec/crusader.sh b/third_party/rust/bit-vec/crusader.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/bit-vec/deploy-docs.sh b/third_party/rust/bit-vec/deploy-docs.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/bytemuck/scripts/travis.sh b/third_party/rust/bytemuck/scripts/travis.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cose/tools/certs/certs.sh b/third_party/rust/cose/tools/certs/certs.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/.githooks/pre-push b/third_party/rust/cubeb-coreaudio/.githooks/pre-push old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/install_git_hook.sh b/third_party/rust/cubeb-coreaudio/install_git_hook.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/install_rustfmt_clippy.sh b/third_party/rust/cubeb-coreaudio/install_rustfmt_clippy.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/run_device_tests.sh b/third_party/rust/cubeb-coreaudio/run_device_tests.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/run_sanitizers.sh b/third_party/rust/cubeb-coreaudio/run_sanitizers.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-coreaudio/run_tests.sh b/third_party/rust/cubeb-coreaudio/run_tests.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/cmake/sanitizers-cmake/cmake/asan-wrapper b/third_party/rust/cubeb-sys/libcubeb/cmake/sanitizers-cmake/cmake/asan-wrapper old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/fuse_gtest_files.py b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/fuse_gtest_files.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/gen_gtest_pred_impl.py b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/gen_gtest_pred_impl.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/gtest-config.in b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/gtest-config.in old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/pump.py b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/pump.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/upload.py b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/upload.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/upload_gtest.py b/third_party/rust/cubeb-sys/libcubeb/googletest/scripts/upload_gtest.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_break_on_failure_unittest.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_break_on_failure_unittest.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_catch_exceptions_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_catch_exceptions_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_color_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_color_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_env_var_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_env_var_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_filter_unittest.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_filter_unittest.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_help_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_help_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_list_tests_unittest.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_list_tests_unittest.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_output_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_output_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_shuffle_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_shuffle_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_test_utils.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_test_utils.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_throw_on_failure_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_throw_on_failure_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_uninitialized_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_uninitialized_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_outfiles_test.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_outfiles_test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_output_unittest.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_output_unittest.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_test_utils.py b/third_party/rust/cubeb-sys/libcubeb/googletest/test/gtest_xml_test_utils.py old mode 100644 new mode 100755 diff --git a/third_party/rust/cubeb-sys/libcubeb/scan-build-install.sh b/third_party/rust/cubeb-sys/libcubeb/scan-build-install.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/failure/build-docs.sh b/third_party/rust/failure/build-docs.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/freetype/configure b/third_party/rust/freetype/configure old mode 100644 new mode 100755 diff --git a/third_party/rust/freetype/etc/bindgen.sh b/third_party/rust/freetype/etc/bindgen.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/fuchsia-zircon/tools/gen_status.py b/third_party/rust/fuchsia-zircon/tools/gen_status.py old mode 100644 new mode 100755 diff --git a/third_party/rust/gfx-auxil/.cargo-checksum.json b/third_party/rust/gfx-auxil/.cargo-checksum.json index 006a864f18c3..77e46243278e 100644 --- a/third_party/rust/gfx-auxil/.cargo-checksum.json +++ b/third_party/rust/gfx-auxil/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"90303c618ad2c02733e2f4f995d3af4fc34616c2bf4a3afb7829c7a8f1ecf1fd","src/lib.rs":"575e61823dc942028e5b71bf30900180bcdb51ec28832b51d4bb78b41818a4c5"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"90303c618ad2c02733e2f4f995d3af4fc34616c2bf4a3afb7829c7a8f1ecf1fd","src/lib.rs":"f64e02aec86b3c391e85c41ea4f4cb9eb0c5868f67e5461261e15e866df5ee4d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-auxil/src/lib.rs b/third_party/rust/gfx-auxil/src/lib.rs index 30170e686708..b7a357529f0d 100644 --- a/third_party/rust/gfx-auxil/src/lib.rs +++ b/third_party/rust/gfx-auxil/src/lib.rs @@ -65,7 +65,7 @@ pub fn read_spirv(mut x: R) -> io::Result> { "input length not divisible by 4", )); } - if size > usize::max_value() as u64 { + if size > usize::MAX as u64 { return Err(io::Error::new(io::ErrorKind::InvalidData, "input too long")); } let words = (size / 4) as usize; diff --git a/third_party/rust/gfx-backend-dx11/.cargo-checksum.json b/third_party/rust/gfx-backend-dx11/.cargo-checksum.json index 018bd07dc831..cce72a5e1884 100644 --- a/third_party/rust/gfx-backend-dx11/.cargo-checksum.json +++ b/third_party/rust/gfx-backend-dx11/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d42fde1925a161b942a1c563246e29b6866aed9a86a613fd3b12b2324e1a4c97","README.md":"13b17f879e00fec29de8d7ba7c24163e9eddc9c5ce173464c48762653b3041ce","shaders/blit.hlsl":"92a8b404ee956ceff2728ec8dd68969fba4c32a79f4d879f069a294f245a867c","shaders/clear.hlsl":"b715a0d8ccebd858531de845fdb3f1b31f25d3f62266238cd1d417006a07957c","shaders/copy.hlsl":"c71b2df8691068d450d3216b54a5a0315f1e17bcd75aec3b4f46b5e3521945c3","src/conv.rs":"436fa263d869024018e54e4f6fd5c0bcaec2424deed871bc97f9854779dac53e","src/debug.rs":"60a2a7cac9cbced6385f560d7b171c4a8eb9a644d8ac219671e1e0fcc8a2439f","src/device.rs":"ac413afabc9191352260b33486b32aaff201a0fa384cc13fd48d48221224aa09","src/dxgi.rs":"7265f4a24b48013c67aac33d456c2aae210b9d597170721738833015fba974bf","src/internal.rs":"0f5ebadf821a532c3820bd86d344bd9db09e466a70aa8cc50c4776058674a5ff","src/lib.rs":"e2d4123643222c637be5c63ab4a0f7ad908e364acf1aa8a068cc66034fbbfd83","src/shader.rs":"0c3c2475578cd322ab6c737732dec00d0893924f3d397f3d326e53f3bc90e9e5"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"d42fde1925a161b942a1c563246e29b6866aed9a86a613fd3b12b2324e1a4c97","README.md":"13b17f879e00fec29de8d7ba7c24163e9eddc9c5ce173464c48762653b3041ce","shaders/blit.hlsl":"92a8b404ee956ceff2728ec8dd68969fba4c32a79f4d879f069a294f245a867c","shaders/clear.hlsl":"b715a0d8ccebd858531de845fdb3f1b31f25d3f62266238cd1d417006a07957c","shaders/copy.hlsl":"c71b2df8691068d450d3216b54a5a0315f1e17bcd75aec3b4f46b5e3521945c3","src/conv.rs":"436fa263d869024018e54e4f6fd5c0bcaec2424deed871bc97f9854779dac53e","src/debug.rs":"60a2a7cac9cbced6385f560d7b171c4a8eb9a644d8ac219671e1e0fcc8a2439f","src/device.rs":"453186b234d8b85e8d3b7c3e298ed5046d6935c5affd5091e90143040145c4bd","src/dxgi.rs":"7265f4a24b48013c67aac33d456c2aae210b9d597170721738833015fba974bf","src/internal.rs":"0f5ebadf821a532c3820bd86d344bd9db09e466a70aa8cc50c4776058674a5ff","src/lib.rs":"97b94c1b0011162a411448954d3768f182e5ecd49f54d82c7067f7c68bf5b48a","src/shader.rs":"0c3c2475578cd322ab6c737732dec00d0893924f3d397f3d326e53f3bc90e9e5"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-backend-dx11/src/device.rs b/third_party/rust/gfx-backend-dx11/src/device.rs index 432c05c5748b..a6c796a40b83 100644 --- a/third_party/rust/gfx-backend-dx11/src/device.rs +++ b/third_party/rust/gfx-backend-dx11/src/device.rs @@ -768,13 +768,17 @@ impl Device { } } } - image::ViewKind::D1 | image::ViewKind::D1Array | image::ViewKind::D3 | image::ViewKind::Cube | image::ViewKind::CubeArray => { + image::ViewKind::D1 + | image::ViewKind::D1Array + | image::ViewKind::D3 + | image::ViewKind::Cube + | image::ViewKind::CubeArray => { warn!( "3D and cube views are not supported for the image, kind: {:?}", info.kind ); return Err(image::ViewCreationError::BadKind(info.view_kind)); - }, + } } let mut dsv = ptr::null_mut(); @@ -1790,6 +1794,7 @@ impl device::Device for Device { view_kind: image::ViewKind, format: format::Format, _swizzle: format::Swizzle, + usage: image::Usage, range: image::SubresourceRange, ) -> Result { let is_array = image.kind.num_layers() > 1; @@ -1827,7 +1832,7 @@ impl device::Device for Device { range.level_start as _, ), format, - srv_handle: if image.usage.intersects(image::Usage::SAMPLED) { + srv_handle: if usage.intersects(image::Usage::SAMPLED) { let srv = self.view_image_as_shader_resource(&srv_info)?; if let Some(ref mut name) = debug_name { @@ -1838,7 +1843,7 @@ impl device::Device for Device { } else { None }, - rtv_handle: if image.usage.contains(image::Usage::COLOR_ATTACHMENT) { + rtv_handle: if usage.contains(image::Usage::COLOR_ATTACHMENT) { let rtv = self.view_image_as_render_target(&info)?; if let Some(ref mut name) = debug_name { @@ -1849,7 +1854,7 @@ impl device::Device for Device { } else { None }, - uav_handle: if image.usage.contains(image::Usage::STORAGE) { + uav_handle: if usage.contains(image::Usage::STORAGE) { let uav = self.view_image_as_unordered_access(&info)?; if let Some(ref mut name) = debug_name { @@ -1860,7 +1865,7 @@ impl device::Device for Device { } else { None }, - dsv_handle: if image.usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) { + dsv_handle: if usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) { if let Some(dsv) = self.view_image_as_depth_stencil(&info, None).ok() { if let Some(ref mut name) = debug_name { set_debug_name_with_suffix(&dsv, name, " -- DSV"); @@ -1873,11 +1878,13 @@ impl device::Device for Device { } else { None }, - rodsv_handle: if image.usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) + rodsv_handle: if usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) && self.internal.downlevel.read_only_depth_stencil { - if let Some(rodsv) = - self.view_image_as_depth_stencil(&info, Some(image.format.is_stencil())).ok() { + if let Some(rodsv) = self + .view_image_as_depth_stencil(&info, Some(image.format.is_stencil())) + .ok() + { if let Some(ref mut name) = debug_name { set_debug_name_with_suffix(&rodsv, name, " -- DSV"); } diff --git a/third_party/rust/gfx-backend-dx11/src/lib.rs b/third_party/rust/gfx-backend-dx11/src/lib.rs index c4176690d022..e8ff1f82704b 100644 --- a/third_party/rust/gfx-backend-dx11/src/lib.rs +++ b/third_party/rust/gfx-backend-dx11/src/lib.rs @@ -622,7 +622,7 @@ impl hal::Instance for Instance { limits, dynamic_pipeline_states: hal::DynamicStates::VIEWPORT | hal::DynamicStates::SCISSOR - | hal::DynamicStates::BLEND_COLOR + | hal::DynamicStates::BLEND_CONSTANTS | hal::DynamicStates::DEPTH_BOUNDS | hal::DynamicStates::STENCIL_REFERENCE, downlevel, @@ -1686,7 +1686,7 @@ impl CommandBufferState { let blend_color = if let Some(ref pipeline) = self.graphics_pipeline { pipeline .baked_states - .blend_color + .blend_constants .or(self.blend_factor) .unwrap_or([0f32; 4]) } else { diff --git a/third_party/rust/gfx-backend-dx12/.cargo-checksum.json b/third_party/rust/gfx-backend-dx12/.cargo-checksum.json index 37c82cc36baf..0c2b90b3c630 100644 --- a/third_party/rust/gfx-backend-dx12/.cargo-checksum.json +++ b/third_party/rust/gfx-backend-dx12/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"35330be366ddac11c8650d97bd2a0e7960d25ed3d516055d68ab1d77641abd86","README.md":"de987fd4e01bc95d01094ba75140d92b0c34041768616b69e615c0a3b7dd4968","shaders/blit.hlsl":"0c95317cd14b0ae71459d74c3e5658acac0baf8476525d2063c143e300180fe6","src/command.rs":"afa24d666dc4c2d4d838b07c684215be6b56ec633e30cc5d475f9e4b54f61bf1","src/conv.rs":"89b47062783a91ccb5be00453d1a0ece9d0fee521cfd784570922899d22f6ebc","src/descriptors_cpu.rs":"3aea4aa606ddf2240aa96ca8df7d9c531cb41e04f3e9e67690e124d1571b33b8","src/device.rs":"a24a3c261c61d1b24067d30369780be52ed818f5680e620db0097c7c5a921749","src/internal.rs":"6f45623b7c6ca293310d295c87810fe4f2b7343189a88ad92b8d882ffedbe76b","src/lib.rs":"a070e65126dc95c283cbee03063b550934622738ef937dc838a5c05250bc6602","src/pool.rs":"8f611e9b1c61ade025d7c787df375c6c927b196ebcffc34b429c978132b71022","src/resource.rs":"7fbe010306b4388c40ccf0538dc6d611cbe6d39d88435cd0e6a0db8c41206454","src/root_constants.rs":"1f74217772e9702a5493e6e6b43c17eaf0462e3f4cee4fa9a5f93318397953f4","src/window.rs":"07042a60a0d0a972bf1c9a3b28868cf1abaa673188dbdfb6f202a50577c60ae0"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"35330be366ddac11c8650d97bd2a0e7960d25ed3d516055d68ab1d77641abd86","README.md":"de987fd4e01bc95d01094ba75140d92b0c34041768616b69e615c0a3b7dd4968","shaders/blit.hlsl":"0c95317cd14b0ae71459d74c3e5658acac0baf8476525d2063c143e300180fe6","src/command.rs":"d22111d9e6ba43e1e9701701645792307d8f31ef89e5d43ada3f08ec209f625b","src/conv.rs":"89b47062783a91ccb5be00453d1a0ece9d0fee521cfd784570922899d22f6ebc","src/descriptors_cpu.rs":"3aea4aa606ddf2240aa96ca8df7d9c531cb41e04f3e9e67690e124d1571b33b8","src/device.rs":"9417c5d388194d8cdb6d373ed335f3d7c9fd403e2fc72ca6a3ff01b3b077856f","src/internal.rs":"6f45623b7c6ca293310d295c87810fe4f2b7343189a88ad92b8d882ffedbe76b","src/lib.rs":"6ecd14730d9d61aeadf133becf182eb15d501725c0f0c36003034a6500f09d7c","src/pool.rs":"8f611e9b1c61ade025d7c787df375c6c927b196ebcffc34b429c978132b71022","src/resource.rs":"461c3ffbc6c0f8f8b78ffc1f8b66358b26b09538bb5cdf215283d25a47af32a2","src/root_constants.rs":"1f74217772e9702a5493e6e6b43c17eaf0462e3f4cee4fa9a5f93318397953f4","src/window.rs":"52e3567332c7cd48d4cf0e0c9877d843ff6dede068334289612871a45c5255b2"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-backend-dx12/src/command.rs b/third_party/rust/gfx-backend-dx12/src/command.rs index c7466560cc24..3c86af38f588 100644 --- a/third_party/rust/gfx-backend-dx12/src/command.rs +++ b/third_party/rust/gfx-backend-dx12/src/command.rs @@ -2080,7 +2080,7 @@ impl com::CommandBuffer for CommandBuffer { if let Some(ref rect) = pipeline.baked_states.scissor { self.set_scissors(0, iter::once(rect.clone())); } - if let Some(color) = pipeline.baked_states.blend_color { + if let Some(color) = pipeline.baked_states.blend_constants { self.set_blend_constants(color); } if let Some(ref bounds) = pipeline.baked_states.depth_bounds { diff --git a/third_party/rust/gfx-backend-dx12/src/device.rs b/third_party/rust/gfx-backend-dx12/src/device.rs index 16ead23603c8..a6fb66ff3c80 100644 --- a/third_party/rust/gfx-backend-dx12/src/device.rs +++ b/third_party/rust/gfx-backend-dx12/src/device.rs @@ -1113,6 +1113,7 @@ impl Device { if !winerror::SUCCEEDED(hr) { error!("error on swapchain creation 0x{:x}", hr); + return Err(w::SwapchainError::Unknown); } let (swap_chain3, hr3) = swap_chain1.cast::(); @@ -1217,7 +1218,6 @@ impl Device { surface_type: image_unbound.format.base_format().0, kind: image_unbound.kind, mip_levels: image_unbound.mip_levels, - usage: image_unbound.usage, default_view_format: image_unbound.view_format, view_caps: image_unbound.view_caps, descriptor: image_unbound.desc, @@ -2191,7 +2191,7 @@ impl d::Device for Device { }, SampleMask: match desc.multisampling { Some(ref ms) => ms.sample_mask as u32, - None => UINT::max_value(), + None => UINT::MAX, }, RasterizerState: conv::map_rasterizer(&desc.rasterizer, desc.multisampling.is_some()), DepthStencilState: conv::map_depth_stencil(&desc.depth_stencil), @@ -2781,6 +2781,7 @@ impl d::Device for Device { view_kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, + usage: image::Usage, range: image::SubresourceRange, ) -> Result { let image = image.expect_bound(); @@ -2815,12 +2816,12 @@ impl d::Device for Device { //Note: we allow RTV/DSV/SRV/UAV views to fail to be created here, // because we don't know if the user will even need to use them. + //Update: now we have `usage`, but some of the users (like `wgpu`) + // still don't know ahead of time what it needs to be. Ok(r::ImageView { resource: image.resource, - handle_srv: if image - .usage - .intersects(image::Usage::SAMPLED | image::Usage::INPUT_ATTACHMENT) + handle_srv: if usage.intersects(image::Usage::SAMPLED | image::Usage::INPUT_ATTACHMENT) { let info = if range.aspects.contains(format::Aspects::DEPTH) { conv::map_format_shader_depth(surface_format).map(|format| ViewInfo { @@ -2847,7 +2848,7 @@ impl d::Device for Device { } else { None }, - handle_rtv: if image.usage.contains(image::Usage::COLOR_ATTACHMENT) { + handle_rtv: if usage.contains(image::Usage::COLOR_ATTACHMENT) { // This view is not necessarily going to be rendered to, even // if the image supports that in general. match self.view_image_as_render_target(&info) { @@ -2857,12 +2858,12 @@ impl d::Device for Device { } else { r::RenderTargetHandle::None }, - handle_uav: if image.usage.contains(image::Usage::STORAGE) { + handle_uav: if usage.contains(image::Usage::STORAGE) { self.view_image_as_storage(&info).ok() } else { None }, - handle_dsv: if image.usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) { + handle_dsv: if usage.contains(image::Usage::DEPTH_STENCIL_ATTACHMENT) { match conv::map_format_dsv(surface_format) { Some(dsv_format) => self .view_image_as_depth_stencil(&ViewInfo { @@ -3374,8 +3375,8 @@ impl d::Device for Device { // This block handles overflow when converting to u32 and always rounds up // The Vulkan specification allows to wait more than specified let timeout_ms = { - if timeout_ns > (::max_value() as u64) * 1_000_000 { - ::max_value() + if timeout_ns > (::MAX as u64) * 1_000_000 { + ::MAX } else { ((timeout_ns + 999_999) / 1_000_000) as u32 } diff --git a/third_party/rust/gfx-backend-dx12/src/lib.rs b/third_party/rust/gfx-backend-dx12/src/lib.rs index 49d616ec661f..c63f59acd3ba 100644 --- a/third_party/rust/gfx-backend-dx12/src/lib.rs +++ b/third_party/rust/gfx-backend-dx12/src/lib.rs @@ -1448,7 +1448,7 @@ impl hal::Instance for Instance { }, dynamic_pipeline_states: hal::DynamicStates::VIEWPORT | hal::DynamicStates::SCISSOR - | hal::DynamicStates::BLEND_COLOR + | hal::DynamicStates::BLEND_CONSTANTS | hal::DynamicStates::STENCIL_REFERENCE, downlevel: hal::DownlevelProperties::all_enabled(), ..PhysicalDeviceProperties::default() diff --git a/third_party/rust/gfx-backend-dx12/src/resource.rs b/third_party/rust/gfx-backend-dx12/src/resource.rs index 9c752e5f6de6..d97d68494906 100644 --- a/third_party/rust/gfx-backend-dx12/src/resource.rs +++ b/third_party/rust/gfx-backend-dx12/src/resource.rs @@ -251,7 +251,6 @@ pub struct ImageBound { pub(crate) surface_type: format::SurfaceType, pub(crate) kind: image::Kind, pub(crate) mip_levels: image::Level, - pub(crate) usage: image::Usage, pub(crate) default_view_format: Option, pub(crate) view_caps: image::ViewCapabilities, pub(crate) descriptor: d3d12::D3D12_RESOURCE_DESC, diff --git a/third_party/rust/gfx-backend-dx12/src/window.rs b/third_party/rust/gfx-backend-dx12/src/window.rs index 50d9447b4d15..bf31c9cbfc73 100644 --- a/third_party/rust/gfx-backend-dx12/src/window.rs +++ b/third_party/rust/gfx-backend-dx12/src/window.rs @@ -277,7 +277,6 @@ impl w::PresentationSurface for Surface { surface_type: base_format.0, kind, mip_levels: 1, - usage: sc.usage, default_view_format: None, view_caps: i::ViewCapabilities::empty(), descriptor, diff --git a/third_party/rust/gfx-backend-empty/.cargo-checksum.json b/third_party/rust/gfx-backend-empty/.cargo-checksum.json index 79d71da0ea7d..5b263dd22d70 100644 --- a/third_party/rust/gfx-backend-empty/.cargo-checksum.json +++ b/third_party/rust/gfx-backend-empty/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ea56292266b10d8449fbf4d9d5c5a9cc8cd1902731d145f284ac2210b89e9518","src/buffer.rs":"1a275e7a1d4bebe594256709e7ee166222518178bd6112cd45c29d4aa6d002dd","src/descriptor.rs":"0689f381dcb0a8603167495373d6cfae9d50f2b5017ab3e364bc838949548827","src/image.rs":"83dba8bae97e06ced4f8030f208566dd773b773be14bc56f10da92dedec041f0","src/lib.rs":"85310f1e3ee61f13ef292c8765dbeb7fe75e99b567699b53d714c1e6daa12ec4","src/memory.rs":"abba2a8943dccf79cc67de3ce33dc534606fe3838220504a1330f773c7bf0ac6"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"ea56292266b10d8449fbf4d9d5c5a9cc8cd1902731d145f284ac2210b89e9518","src/buffer.rs":"1a275e7a1d4bebe594256709e7ee166222518178bd6112cd45c29d4aa6d002dd","src/descriptor.rs":"0689f381dcb0a8603167495373d6cfae9d50f2b5017ab3e364bc838949548827","src/image.rs":"83dba8bae97e06ced4f8030f208566dd773b773be14bc56f10da92dedec041f0","src/lib.rs":"fa80d2e782f95798488931648c6e26c83470dbf3f8f942c0b3362d723dd3e0e0","src/memory.rs":"abba2a8943dccf79cc67de3ce33dc534606fe3838220504a1330f773c7bf0ac6"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-backend-empty/src/lib.rs b/third_party/rust/gfx-backend-empty/src/lib.rs index 05e37860403d..64aca3569510 100644 --- a/third_party/rust/gfx-backend-empty/src/lib.rs +++ b/third_party/rust/gfx-backend-empty/src/lib.rs @@ -368,6 +368,7 @@ impl device::Device for Device { _: hal::image::ViewKind, _: format::Format, _: format::Swizzle, + _: hal::image::Usage, _: hal::image::SubresourceRange, ) -> Result<(), hal::image::ViewCreationError> { Ok(()) diff --git a/third_party/rust/gfx-backend-metal/.cargo-checksum.json b/third_party/rust/gfx-backend-metal/.cargo-checksum.json index 728636d0b316..6d6d2430b7a0 100644 --- a/third_party/rust/gfx-backend-metal/.cargo-checksum.json +++ b/third_party/rust/gfx-backend-metal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"00019d96a907b42d29a25efa1ee01b4d9b43b3e3746c776842367fd4da414d9b","README.md":"e08409da89ea3f102953c99fb62661f4e434cdb925e69b8964faf0a93861c338","shaders/blit.metal":"b243873ac0d7ded37b199d17d1a7b53d5332b4a57bfa22f99dcf60273730be45","shaders/clear.metal":"796a612c1cb48e46fc94b7227feaab993d7ddeed293b69e9f09b2dd88e6a1189","shaders/fill.metal":"2642b5df62f8eb2246a442137d083010d2a3132110d9be4eb25b479123098d25","shaders/gfx-shaders-ios-simulator.metallib":"561a9b5d91e03e904bae3ffff20f5325cc2ba0653315ae9b8b790ce91597152c","shaders/gfx-shaders-ios.metallib":"e1aad872cf5a5dc1e7dd22cb37124d22a4dac9f9f682b8cce3a490c8ea90589f","shaders/gfx-shaders-macos.metallib":"c07140adb3699dad71b3d7117c3caba7c1823089067391c8b6c9d308ce077785","shaders/macros.h":"a4550ac7c180935c2edb57aa7a5f8442b53f1f3dc65df8cc800d0afb8289cdeb","src/command.rs":"a6aad67798dcea7cc989744768567ed974a734c2c3eeaff1ff6df2a25e12a5dd","src/conversions.rs":"29c3eada40ab90759124e7967a6b587aec45bdac67e6c5129f21453b2510128e","src/device.rs":"938c4e2206ef0a5b181c8524e34fff713fb8ddde868114a568e3022948fe47ef","src/internal.rs":"042a64ac4f47d915d6c8e3c981641bb7bacefe83080f0058353d36ce92f60f42","src/lib.rs":"d743b7460b187b5c906b248f188f6c211f8a5ff12cf14d2e9509cc754e77ea0f","src/native.rs":"441700ed4f669bdcd32fd0061227b0956ffe52bca1a23f42187d6f02f2a231b0","src/soft.rs":"dd22363485a638922c977539ce3a1642d551576c58df456ab9c1f26d4d7e1dd3","src/window.rs":"9aab7b6bd579f0b8db9e5767151f5a17388fb4e51119b2b74927823724f54ee8"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"9d1f5920647f988741edd575468c4cd32c8415d9ee56b8052d34644bf7741694","README.md":"e08409da89ea3f102953c99fb62661f4e434cdb925e69b8964faf0a93861c338","shaders/blit.metal":"b243873ac0d7ded37b199d17d1a7b53d5332b4a57bfa22f99dcf60273730be45","shaders/clear.metal":"796a612c1cb48e46fc94b7227feaab993d7ddeed293b69e9f09b2dd88e6a1189","shaders/fill.metal":"2642b5df62f8eb2246a442137d083010d2a3132110d9be4eb25b479123098d25","shaders/gfx-shaders-ios-simulator.metallib":"561a9b5d91e03e904bae3ffff20f5325cc2ba0653315ae9b8b790ce91597152c","shaders/gfx-shaders-ios.metallib":"e1aad872cf5a5dc1e7dd22cb37124d22a4dac9f9f682b8cce3a490c8ea90589f","shaders/gfx-shaders-macos.metallib":"c07140adb3699dad71b3d7117c3caba7c1823089067391c8b6c9d308ce077785","shaders/macros.h":"a4550ac7c180935c2edb57aa7a5f8442b53f1f3dc65df8cc800d0afb8289cdeb","src/command.rs":"bac7ac76f1e802dfcbc58c569e6b33860e8722a85fc4772a2a029628b5b1ea0d","src/conversions.rs":"2aa8a7237b5fcc035fff4cdc7e9e46e18fdb2c099eedcba3a2a8bcd63d4c6c74","src/device.rs":"a0cd493bea8bc123977ca3eff47480777b198290022535bdb44422b9d2edf191","src/internal.rs":"042a64ac4f47d915d6c8e3c981641bb7bacefe83080f0058353d36ce92f60f42","src/lib.rs":"8c60edad2e18f8066babafac93583d6deaa1e17a3a990eb447ac9e1bfe9ec9f4","src/native.rs":"cdf69e7ee978fac6f440b75d2bbce637901611efdbd93904e34136dc4d16508c","src/pipeline_cache.rs":"7acaa09d28307d893f978710c6970f9826bfa51c374a5c2c9d9765f6b1ef4970","src/soft.rs":"efc89c1755cef9cebc74665105286d5f12b8486bdc95c6a6613398b9eee673b8","src/window.rs":"85a7c55e0a80f95e1104eebb54f34cb3f1f4ce86b4d00d16462e3e583105572f"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-backend-metal/Cargo.toml b/third_party/rust/gfx-backend-metal/Cargo.toml index 025b200d71d8..bedbf11c906d 100644 --- a/third_party/rust/gfx-backend-metal/Cargo.toml +++ b/third_party/rust/gfx-backend-metal/Cargo.toml @@ -16,6 +16,7 @@ edition = "2018" default = [] signpost = [] cross = ["spirv_cross", "auxil", "naga/spv-out"] +pipeline-cache = ["tempfile", "serde", "bincode", "naga/serialize", "naga/deserialize", "naga/spv-out"] [lib] name = "gfx_backend_metal" @@ -29,7 +30,7 @@ copyless = "0.1.4" fxhash = "0.2.1" log = { version = "0.4" } dispatch = { version = "0.2", optional = true } -metal = { git = "https://github.com/gfx-rs/metal-rs", rev="439c986eb7a9b91e88b61def2daa66e4043fcbef", features = ["private"] } +metal = { git = "https://github.com/gfx-rs/metal-rs", rev="78f632d194c7c16d18b71d7373c4080847d110b0", features = ["private"] } foreign-types = "0.3" objc = "0.2.5" block = "0.1" @@ -37,6 +38,10 @@ cocoa-foundation = "0.1" parking_lot = "0.11" storage-map = "0.3" raw-window-handle = "0.3" +profiling = { version = "0.1.10", default-features = false } +tempfile = { version = "3.2", optional = true } +serde = { version = "1", features = ["serde_derive"], optional = true } +bincode = { version = "1", optional = true } [dependencies.auxil] package = "gfx-auxil" @@ -52,7 +57,7 @@ optional = true [dependencies.naga] git = "https://github.com/gfx-rs/naga" -tag = "gfx-20" +tag = "gfx-22" features = ["spv-in", "msl-out"] # This forces docs.rs to build the crate on mac, otherwise the build fails diff --git a/third_party/rust/gfx-backend-metal/src/command.rs b/third_party/rust/gfx-backend-metal/src/command.rs index a6e5f4653a42..e024c98a6068 100644 --- a/third_party/rust/gfx-backend-metal/src/command.rs +++ b/third_party/rust/gfx-backend-metal/src/command.rs @@ -203,14 +203,17 @@ impl RenderPassDescriptorCache { let desc = rp_desc.color_attachments().object_at(i as _).unwrap(); desc.set_texture(None); desc.set_resolve_texture(None); + desc.set_level(0); desc.set_slice(0); } if let Some(desc) = rp_desc.depth_attachment() { desc.set_texture(None); + desc.set_level(0); desc.set_slice(0); } if let Some(desc) = rp_desc.stencil_attachment() { desc.set_texture(None); + desc.set_level(0); desc.set_slice(0); } self.spare_descriptors.push(rp_desc); @@ -1924,6 +1927,15 @@ where offset, ); } + Cmd::InsertDebugMarker { ref name } => { + encoder.insert_debug_signpost(name.as_ref()); + } + Cmd::PushDebugMarker { ref name } => { + encoder.push_debug_group(name.as_ref()); + } + Cmd::PopDebugGroup => { + encoder.pop_debug_group(); + } } } @@ -2209,6 +2221,7 @@ impl hal::queue::Queue for Queue { Iw: Iterator, Is: Iterator, { + profiling::scope!("submit"); debug!("submitting with fence {:?}", fence); self.wait(wait_semaphores.map(|(s, _)| s)); @@ -2229,6 +2242,7 @@ impl hal::queue::Queue for Queue { let mut release_sinks = Vec::new(); for cmd_buffer in command_buffers { + profiling::scope!("submit command buffer"); let mut inner = cmd_buffer.inner.borrow_mut(); let CommandBufferInner { ref sink, @@ -2411,6 +2425,7 @@ impl hal::queue::Queue for Queue { image: window::SwapchainImage, wait_semaphore: Option<&mut native::Semaphore>, ) -> Result, PresentError> { + profiling::scope!("present"); if let Some(semaphore) = wait_semaphore { if let Some(ref system) = semaphore.system { system.wait(!0); @@ -3672,6 +3687,7 @@ impl com::CommandBuffer for CommandBuffer { } unsafe fn bind_graphics_pipeline(&mut self, pipeline: &native::GraphicsPipeline) { + profiling::scope!("bind_graphics_pipeline"); let mut inner = self.inner.borrow_mut(); let mut pre = inner.sink().pre_render(); @@ -3775,7 +3791,7 @@ impl com::CommandBuffer for CommandBuffer { pre.issue(com); } } - if let Some(ref color) = pipeline.baked_states.blend_color { + if let Some(ref color) = pipeline.baked_states.blend_constants { pre.issue(self.state.set_blend_color(color)); } } @@ -3790,6 +3806,8 @@ impl com::CommandBuffer for CommandBuffer { I: Iterator, J: Iterator, { + profiling::scope!("bind_graphics_descriptor_sets"); + let vbuf_count = self .state .render_pso @@ -3823,6 +3841,8 @@ impl com::CommandBuffer for CommandBuffer { layouts: _, ref resources, } => { + profiling::scope!("bind descriptor set"); + let end_offsets = self.state.bind_set( pso::ShaderStageFlags::VERTEX | pso::ShaderStageFlags::FRAGMENT, &*pool.read(), @@ -3943,6 +3963,7 @@ impl com::CommandBuffer for CommandBuffer { } unsafe fn bind_compute_pipeline(&mut self, pipeline: &native::ComputePipeline) { + profiling::scope!("bind_compute_pipeline"); self.state.compute_pso = Some(pipeline.raw.clone()); self.state.work_group_size = pipeline.work_group_size; @@ -3970,6 +3991,7 @@ impl com::CommandBuffer for CommandBuffer { I: Iterator, J: Iterator, { + profiling::scope!("bind_compute_descriptor_sets"); self.state.resources_cs.pre_allocate(&pipe_layout.total.cs); let mut dynamic_offset_iter = dynamic_offsets; @@ -3987,6 +4009,8 @@ impl com::CommandBuffer for CommandBuffer { layouts: _, ref resources, } => { + profiling::scope!("bind descriptor set"); + let end_offsets = self.state.bind_set( pso::ShaderStageFlags::COMPUTE, &*pool.read(), @@ -4871,13 +4895,27 @@ impl com::CommandBuffer for CommandBuffer { } } - unsafe fn insert_debug_marker(&mut self, _name: &str, _color: u32) { - //TODO + unsafe fn insert_debug_marker(&mut self, name: &str, _color: u32) { + self.inner + .borrow_mut() + .sink() + .pre_render() + .issue(soft::RenderCommand::InsertDebugMarker { name }) } - unsafe fn begin_debug_marker(&mut self, _name: &str, _color: u32) { - //TODO + + unsafe fn begin_debug_marker(&mut self, name: &str, _color: u32) { + self.inner + .borrow_mut() + .sink() + .pre_render() + .issue(soft::RenderCommand::PushDebugMarker { name }) } + unsafe fn end_debug_marker(&mut self) { - //TODO + self.inner + .borrow_mut() + .sink() + .pre_render() + .issue(soft::RenderCommand::PopDebugGroup) } } diff --git a/third_party/rust/gfx-backend-metal/src/conversions.rs b/third_party/rust/gfx-backend-metal/src/conversions.rs index ca1c267b07f2..0247cadaf704 100644 --- a/third_party/rust/gfx-backend-metal/src/conversions.rs +++ b/third_party/rust/gfx-backend-metal/src/conversions.rs @@ -9,6 +9,7 @@ use hal::{ IndexType, }; use metal::*; +use std::num::NonZeroU32; impl PrivateCapabilities { pub fn map_format(&self, format: Format) -> Option { @@ -803,3 +804,141 @@ pub fn map_naga_stage_to_cross(stage: naga::ShaderStage) -> spirv_cross::spirv:: naga::ShaderStage::Compute => Em::GlCompute, } } + +#[cfg(feature = "cross")] +pub fn map_sampler_data_to_cross(info: &image::SamplerDesc) -> spirv_cross::msl::SamplerData { + use spirv_cross::msl; + fn map_address(wrap: image::WrapMode) -> msl::SamplerAddress { + match wrap { + image::WrapMode::Tile => msl::SamplerAddress::Repeat, + image::WrapMode::Mirror => msl::SamplerAddress::MirroredRepeat, + image::WrapMode::Clamp => msl::SamplerAddress::ClampToEdge, + image::WrapMode::Border => msl::SamplerAddress::ClampToBorder, + image::WrapMode::MirrorClamp => { + unimplemented!("https://github.com/grovesNL/spirv_cross/issues/138") + } + } + } + + let lods = info.lod_range.start.0..info.lod_range.end.0; + msl::SamplerData { + coord: if info.normalized { + msl::SamplerCoord::Normalized + } else { + msl::SamplerCoord::Pixel + }, + min_filter: match info.min_filter { + image::Filter::Nearest => msl::SamplerFilter::Nearest, + image::Filter::Linear => msl::SamplerFilter::Linear, + }, + mag_filter: match info.mag_filter { + image::Filter::Nearest => msl::SamplerFilter::Nearest, + image::Filter::Linear => msl::SamplerFilter::Linear, + }, + mip_filter: match info.min_filter { + image::Filter::Nearest if info.lod_range.end.0 < 0.5 => msl::SamplerMipFilter::None, + image::Filter::Nearest => msl::SamplerMipFilter::Nearest, + image::Filter::Linear => msl::SamplerMipFilter::Linear, + }, + s_address: map_address(info.wrap_mode.0), + t_address: map_address(info.wrap_mode.1), + r_address: map_address(info.wrap_mode.2), + compare_func: match info.comparison { + Some(func) => unsafe { std::mem::transmute(map_compare_function(func) as u32) }, + None => msl::SamplerCompareFunc::Always, + }, + border_color: match info.border { + image::BorderColor::TransparentBlack => msl::SamplerBorderColor::TransparentBlack, + image::BorderColor::OpaqueBlack => msl::SamplerBorderColor::OpaqueBlack, + image::BorderColor::OpaqueWhite => msl::SamplerBorderColor::OpaqueWhite, + }, + lod_clamp_min: lods.start.into(), + lod_clamp_max: lods.end.into(), + max_anisotropy: info.anisotropy_clamp.map_or(0, |aniso| aniso as i32), + planes: 0, + resolution: msl::FormatResolution::_444, + chroma_filter: msl::SamplerFilter::Nearest, + x_chroma_offset: msl::ChromaLocation::CositedEven, + y_chroma_offset: msl::ChromaLocation::CositedEven, + swizzle: [ + msl::ComponentSwizzle::Identity, + msl::ComponentSwizzle::Identity, + msl::ComponentSwizzle::Identity, + msl::ComponentSwizzle::Identity, + ], + ycbcr_conversion_enable: false, + ycbcr_model: msl::SamplerYCbCrModelConversion::RgbIdentity, + ycbcr_range: msl::SamplerYCbCrRange::ItuFull, + bpc: 8, + } +} + +pub fn map_sampler_data_to_naga( + info: &image::SamplerDesc, +) -> naga::back::msl::sampler::InlineSampler { + use naga::back::msl::sampler as sm; + fn map_address(wrap: image::WrapMode) -> sm::Address { + match wrap { + image::WrapMode::Tile => sm::Address::Repeat, + image::WrapMode::Mirror => sm::Address::MirroredRepeat, + image::WrapMode::Clamp => sm::Address::ClampToEdge, + image::WrapMode::Border => sm::Address::ClampToBorder, + image::WrapMode::MirrorClamp => { + error!("Unsupported address mode - MirrorClamp"); + sm::Address::ClampToEdge + } + } + } + + sm::InlineSampler { + coord: if info.normalized { + sm::Coord::Normalized + } else { + sm::Coord::Pixel + }, + min_filter: match info.min_filter { + image::Filter::Nearest => sm::Filter::Nearest, + image::Filter::Linear => sm::Filter::Linear, + }, + mag_filter: match info.mag_filter { + image::Filter::Nearest => sm::Filter::Nearest, + image::Filter::Linear => sm::Filter::Linear, + }, + mip_filter: match info.min_filter { + image::Filter::Nearest if info.lod_range.end.0 < 0.5 => None, + image::Filter::Nearest => Some(sm::Filter::Nearest), + image::Filter::Linear => Some(sm::Filter::Linear), + }, + address: [ + map_address(info.wrap_mode.0), + map_address(info.wrap_mode.1), + map_address(info.wrap_mode.2), + ], + compare_func: match info.comparison { + Some(func) => match func { + Comparison::Never => sm::CompareFunc::Never, + Comparison::Less => sm::CompareFunc::Less, + Comparison::LessEqual => sm::CompareFunc::LessEqual, + Comparison::Equal => sm::CompareFunc::Equal, + Comparison::GreaterEqual => sm::CompareFunc::GreaterEqual, + Comparison::Greater => sm::CompareFunc::Greater, + Comparison::NotEqual => sm::CompareFunc::NotEqual, + Comparison::Always => sm::CompareFunc::Always, + }, + None => sm::CompareFunc::Never, + }, + border_color: match info.border { + image::BorderColor::TransparentBlack => sm::BorderColor::TransparentBlack, + image::BorderColor::OpaqueBlack => sm::BorderColor::OpaqueBlack, + image::BorderColor::OpaqueWhite => sm::BorderColor::OpaqueWhite, + }, + lod_clamp: if info.lod_range.start.0 > 0.0 || info.lod_range.end.0 < 100.0 { + Some(info.lod_range.start.0..info.lod_range.end.0) + } else { + None + }, + max_anisotropy: info + .anisotropy_clamp + .and_then(|aniso| NonZeroU32::new(aniso as u32)), + } +} diff --git a/third_party/rust/gfx-backend-metal/src/device.rs b/third_party/rust/gfx-backend-metal/src/device.rs index 39761a543261..3015e17c9701 100644 --- a/third_party/rust/gfx-backend-metal/src/device.rs +++ b/third_party/rust/gfx-backend-metal/src/device.rs @@ -1,5 +1,5 @@ -#[cfg(feature = "cross")] -use crate::internal::FastStorageMap; +#[cfg(feature = "pipeline-cache")] +use crate::pipeline_cache; use crate::{ command, conversions as conv, internal::Channel, native as n, AsNative, Backend, FastHashMap, OnlineRecording, QueueFamily, ResourceIndex, Shared, VisibilityShared, @@ -31,8 +31,9 @@ use objc::{ }; use parking_lot::Mutex; -#[cfg(feature = "cross")] -use std::collections::{hash_map::Entry, BTreeMap}; +use std::collections::BTreeMap; +#[cfg(feature = "pipeline-cache")] +use std::io::Write; use std::{ cmp, iter, mem, ops::Range, @@ -61,6 +62,7 @@ fn get_final_function( function_specialization: bool, ) -> Result { type MTLFunctionConstant = Object; + profiling::scope!("get_final_function"); let mut mtl_function = library.get_function(entry, None).map_err(|e| { error!( @@ -140,7 +142,7 @@ pub struct Device { features: hal::Features, pub online_recording: OnlineRecording, pub always_prefer_naga: bool, - #[cfg(feature = "cross")] + #[cfg(any(feature = "pipeline-cache", feature = "cross"))] spv_options: naga::back::spv::Options, } unsafe impl Send for Device {} @@ -259,7 +261,7 @@ impl adapter::PhysicalDevice for PhysicalDevice { queue_group.add_queue(command::Queue::new(self.shared.clone())); } - #[cfg(feature = "cross")] + #[cfg(any(feature = "pipeline-cache", feature = "cross"))] let spv_options = { use naga::back::spv; let capabilities = [ @@ -297,7 +299,7 @@ impl adapter::PhysicalDevice for PhysicalDevice { features: requested_features, online_recording: OnlineRecording::default(), always_prefer_naga: false, - #[cfg(feature = "cross")] + #[cfg(any(feature = "pipeline-cache", feature = "cross"))] spv_options, }; @@ -588,17 +590,19 @@ impl Device { stage: naga::ShaderStage, ) -> Result { use spirv_cross::ErrorCode as Ec; - - let module = spirv_cross::spirv::Module::from_words(raw_data); + profiling::scope!("compile_shader_library_cross"); // now parse again using the new overrides - let mut ast = + let mut ast = { + profiling::scope!("spvc::parse"); + let module = spirv_cross::spirv::Module::from_words(raw_data); spirv_cross::spirv::Ast::::parse(&module).map_err(|err| { match err { Ec::CompilationError(msg) => msg, Ec::Unhandled => "Unexpected parse error".into(), } - })?; + })? + }; auxil::spirv_cross_specialize_ast(&mut ast, specialization)?; @@ -613,10 +617,13 @@ impl Device { Ec::Unhandled => "Unexpected entry point error".into(), })?; - let shader_code = ast.compile().map_err(|err| match err { - Ec::CompilationError(msg) => msg, - Ec::Unhandled => "Unknown compile error".into(), - })?; + let shader_code = { + profiling::scope!("spvc::compile"); + ast.compile().map_err(|err| match err { + Ec::CompilationError(msg) => msg, + Ec::Unhandled => "Unknown compile error".into(), + })? + }; let mut entry_point_map = n::EntryPointMap::default(); for entry_point in entry_points { @@ -650,10 +657,13 @@ impl Device { let options = metal::CompileOptions::new(); options.set_language_version(msl_version); - let library = device - .lock() - .new_library_with_source(shader_code.as_ref(), &options) - .map_err(|err| err.to_string())?; + let library = { + profiling::scope!("Metal::new_library_with_source"); + device + .lock() + .new_library_with_source(shader_code.as_ref(), &options) + .map_err(|err| err.to_string())? + }; Ok(n::ModuleInfo { library, @@ -666,9 +676,21 @@ impl Device { device: &Mutex, shader: &d::NagaShader, naga_options: &naga::back::msl::Options, + pipeline_options: &naga::back::msl::PipelineOptions, + #[cfg(feature = "pipeline-cache")] spv_hash: u64, + #[cfg(feature = "pipeline-cache")] spv_to_msl_cache: Option<&pipeline_cache::SpvToMsl>, ) -> Result { - let (source, info) = - match naga::back::msl::write_string(&shader.module, &shader.info, naga_options) { + profiling::scope!("compile_shader_library_naga"); + + let get_module_info = || { + profiling::scope!("naga::write_string"); + + let (source, info) = match naga::back::msl::write_string( + &shader.module, + &shader.info, + naga_options, + pipeline_options, + ) { Ok(pair) => pair, Err(e) => { warn!("Naga: {:?}", e); @@ -676,23 +698,48 @@ impl Device { } }; - let mut entry_point_map = n::EntryPointMap::default(); - for (ep, internal_name) in shader - .module - .entry_points - .iter() - .zip(info.entry_point_names) - { - entry_point_map.insert( - (ep.stage, ep.name.clone()), - n::EntryPoint { - internal_name, - work_group_size: ep.workgroup_size, - }, - ); - } + let mut entry_point_map = n::EntryPointMap::default(); + for (ep, internal_name) in shader + .module + .entry_points + .iter() + .zip(info.entry_point_names) + { + entry_point_map.insert( + (ep.stage, ep.name.clone()), + n::EntryPoint { + internal_name, + work_group_size: ep.workgroup_size, + }, + ); + } - debug!("Naga generated shader:\n{}", source); + debug!("Naga generated shader:\n{}", source); + + Ok(n::SerializableModuleInfo { + source, + entry_point_map, + rasterization_enabled: true, //TODO + }) + }; + + #[cfg(feature = "pipeline-cache")] + let module_info = if let Some(spv_to_msl_cache) = spv_to_msl_cache { + let key = pipeline_cache::SpvToMslKey { + options: naga_options.clone(), + pipeline_options: pipeline_options.clone(), + spv_hash, + }; + + spv_to_msl_cache + .get_or_create_with(&key, || get_module_info().unwrap()) + .clone() + } else { + get_module_info()? + }; + + #[cfg(not(feature = "pipeline-cache"))] + let module_info = get_module_info()?; let options = metal::CompileOptions::new(); let msl_version = match naga_options.lang_version { @@ -707,22 +754,26 @@ impl Device { }; options.set_language_version(msl_version); - let library = device - .lock() - .new_library_with_source(source.as_ref(), &options) - .map_err(|err| { - warn!("Naga generated shader:\n{}", source); - warn!("Failed to compile: {}", err); - format!("{:?}", err) - })?; + let library = { + profiling::scope!("Metal::new_library_with_source"); + device + .lock() + .new_library_with_source(module_info.source.as_ref(), &options) + .map_err(|err| { + warn!("Naga generated shader:\n{}", module_info.source); + warn!("Failed to compile: {}", err); + format!("{:?}", err) + })? + }; Ok(n::ModuleInfo { library, - entry_point_map, - rasterization_enabled: true, //TODO + entry_point_map: module_info.entry_point_map, + rasterization_enabled: module_info.rasterization_enabled, }) } + #[cfg_attr(not(feature = "pipeline-cache"), allow(unused_variables))] fn load_shader( &self, ep: &pso::EntryPoint, @@ -731,10 +782,14 @@ impl Device { pipeline_cache: Option<&n::PipelineCache>, stage: naga::ShaderStage, ) -> Result<(metal::Library, metal::Function, metal::MTLSize, bool), pso::CreationError> { + let _profiling_tag = match stage { + naga::ShaderStage::Vertex => "vertex", + naga::ShaderStage::Fragment => "fragment", + naga::ShaderStage::Compute => "compute", + }; + profiling::scope!("load_shader", [_profiling_tag]); + let device = &self.shared.device; - #[cfg(feature = "cross")] - let (module_map, info_guard); - let info_owned; #[cfg(feature = "cross")] let mut compiler_options = layout.spirv_cross_options.clone(); @@ -745,72 +800,60 @@ impl Device { compiler_options.enable_point_size_builtin = primitive_class == MTLPrimitiveTopologyClass::Point; } - let options_clone; - let naga_options = match primitive_class { - MTLPrimitiveTopologyClass::Point => { - options_clone = naga::back::msl::Options { - allow_point_size: true, - ..layout.naga_options.clone() - }; - &options_clone - } - _ => &layout.naga_options, + let pipeline_options = naga::back::msl::PipelineOptions { + allow_point_size: match primitive_class { + MTLPrimitiveTopologyClass::Point => true, + _ => false, + }, }; - let info = match pipeline_cache { + let info = { + let mut result = Err(String::new()); + if ep.module.prefer_naga { + result = match ep.module.naga { + Ok(ref shader) => Self::compile_shader_library_naga( + device, + shader, + &layout.naga_options, + &pipeline_options, + #[cfg(feature = "pipeline-cache")] + ep.module.spv_hash, + #[cfg(feature = "pipeline-cache")] + pipeline_cache.as_ref().map(|cache| &cache.spv_to_msl), + ), + Err(ref e) => Err(e.clone()), + } + } #[cfg(feature = "cross")] - Some(cache) => { - module_map = cache - .modules - .get_or_create_with(&compiler_options, FastStorageMap::default); - info_guard = module_map.get_or_create_with(&ep.module.spv, || { - Self::compile_shader_library_cross( - device, - &ep.module.spv, - &compiler_options, - self.shared.private_caps.msl_version, - &ep.specialization, - stage, - ) - .unwrap() - }); - &*info_guard + if result.is_err() { + result = Self::compile_shader_library_cross( + device, + &ep.module.spv, + &compiler_options, + self.shared.private_caps.msl_version, + &ep.specialization, + stage, + ); } - _ => { - let mut result = Err(String::new()); - if ep.module.prefer_naga { - result = match ep.module.naga { - Ok(ref shader) => { - Self::compile_shader_library_naga(device, shader, naga_options) - } - Err(ref e) => Err(e.clone()), - } - } - #[cfg(feature = "cross")] - if result.is_err() { - result = Self::compile_shader_library_cross( + if result.is_err() && !ep.module.prefer_naga { + result = match ep.module.naga { + Ok(ref shader) => Self::compile_shader_library_naga( device, - &ep.module.spv, - &compiler_options, - self.shared.private_caps.msl_version, - &ep.specialization, - stage, - ); + shader, + &layout.naga_options, + &pipeline_options, + #[cfg(feature = "pipeline-cache")] + ep.module.spv_hash, + #[cfg(feature = "pipeline-cache")] + pipeline_cache.as_ref().map(|cache| &cache.spv_to_msl), + ), + Err(ref e) => Err(e.clone()), } - if result.is_err() && !ep.module.prefer_naga { - result = match ep.module.naga { - Ok(ref shader) => { - Self::compile_shader_library_naga(device, shader, naga_options) - } - Err(ref e) => Err(e.clone()), - } - } - info_owned = result.map_err(|e| { - let error = format!("Error compiling the shader {:?}", e); - pso::CreationError::ShaderCreationError(stage.into(), error) - })?; - &info_owned } + result.map_err(|e| { + let error = format!("Error compiling the shader {:?}", e); + pso::CreationError::ShaderCreationError(stage.into(), error) + })? }; let lib = info.library.clone(); @@ -923,74 +966,6 @@ impl Device { Some(descriptor) } - - #[cfg(feature = "cross")] - fn make_sampler_data(info: &image::SamplerDesc) -> spirv_cross::msl::SamplerData { - use spirv_cross::msl; - fn map_address(wrap: image::WrapMode) -> msl::SamplerAddress { - match wrap { - image::WrapMode::Tile => msl::SamplerAddress::Repeat, - image::WrapMode::Mirror => msl::SamplerAddress::MirroredRepeat, - image::WrapMode::Clamp => msl::SamplerAddress::ClampToEdge, - image::WrapMode::Border => msl::SamplerAddress::ClampToBorder, - image::WrapMode::MirrorClamp => { - unimplemented!("https://github.com/grovesNL/spirv_cross/issues/138") - } - } - } - - let lods = info.lod_range.start.0..info.lod_range.end.0; - msl::SamplerData { - coord: if info.normalized { - msl::SamplerCoord::Normalized - } else { - msl::SamplerCoord::Pixel - }, - min_filter: match info.min_filter { - image::Filter::Nearest => msl::SamplerFilter::Nearest, - image::Filter::Linear => msl::SamplerFilter::Linear, - }, - mag_filter: match info.mag_filter { - image::Filter::Nearest => msl::SamplerFilter::Nearest, - image::Filter::Linear => msl::SamplerFilter::Linear, - }, - mip_filter: match info.min_filter { - image::Filter::Nearest if info.lod_range.end.0 < 0.5 => msl::SamplerMipFilter::None, - image::Filter::Nearest => msl::SamplerMipFilter::Nearest, - image::Filter::Linear => msl::SamplerMipFilter::Linear, - }, - s_address: map_address(info.wrap_mode.0), - t_address: map_address(info.wrap_mode.1), - r_address: map_address(info.wrap_mode.2), - compare_func: match info.comparison { - Some(func) => unsafe { mem::transmute(conv::map_compare_function(func) as u32) }, - None => msl::SamplerCompareFunc::Always, - }, - border_color: match info.border { - image::BorderColor::TransparentBlack => msl::SamplerBorderColor::TransparentBlack, - image::BorderColor::OpaqueBlack => msl::SamplerBorderColor::OpaqueBlack, - image::BorderColor::OpaqueWhite => msl::SamplerBorderColor::OpaqueWhite, - }, - lod_clamp_min: lods.start.into(), - lod_clamp_max: lods.end.into(), - max_anisotropy: info.anisotropy_clamp.map_or(0, |aniso| aniso as i32), - planes: 0, - resolution: msl::FormatResolution::_444, - chroma_filter: msl::SamplerFilter::Nearest, - x_chroma_offset: msl::ChromaLocation::CositedEven, - y_chroma_offset: msl::ChromaLocation::CositedEven, - swizzle: [ - msl::ComponentSwizzle::Identity, - msl::ComponentSwizzle::Identity, - msl::ComponentSwizzle::Identity, - msl::ComponentSwizzle::Identity, - ], - ycbcr_conversion_enable: false, - ycbcr_model: msl::SamplerYCbCrModelConversion::RgbIdentity, - ycbcr_range: msl::SamplerYCbCrRange::ItuFull, - bpc: 8, - } - } } impl hal::device::Device for Device { @@ -1152,10 +1127,11 @@ impl hal::device::Device for Device { push_constant_buffer: None, }, ]; - let mut binding_map = FastHashMap::default(); + let mut binding_map = BTreeMap::default(); let mut argument_buffer_bindings = FastHashMap::default(); + let mut inline_samplers = Vec::new(); #[cfg(feature = "cross")] - let mut const_samplers = BTreeMap::new(); + let mut cross_const_samplers = BTreeMap::new(); let mut infos = Vec::new(); // First, place the push constants @@ -1199,14 +1175,13 @@ impl hal::device::Device for Device { match *set_layout { n::DescriptorSetLayout::Emulated { layouts: ref desc_layouts, - #[cfg(feature = "cross")] ref immutable_samplers, .. } => { #[cfg(feature = "cross")] for (&binding, immutable_sampler) in immutable_samplers.iter() { //TODO: array support? - const_samplers.insert( + cross_const_samplers.insert( spirv_cross::msl::SamplerLocation { desc_set: set_index as u32, binding, @@ -1252,8 +1227,19 @@ impl hal::device::Device for Device { } else { None }, - sampler: if layout.content.contains(n::DescriptorContent::SAMPLER) { - Some(info.counters.samplers as _) + sampler: if layout + .content + .contains(n::DescriptorContent::IMMUTABLE_SAMPLER) + { + let immutable_sampler = &immutable_samplers[&layout.binding]; + let handle = inline_samplers.len() + as naga::back::msl::InlineSamplerIndex; + inline_samplers.push(immutable_sampler.data.clone()); + Some(naga::back::msl::BindSamplerTarget::Inline(handle)) + } else if layout.content.contains(n::DescriptorContent::SAMPLER) { + Some(naga::back::msl::BindSamplerTarget::Resource( + info.counters.samplers as _, + )) } else { None }, @@ -1330,7 +1316,10 @@ impl hal::device::Device for Device { msl::ResourceBinding { buffer_id: target.buffer.map_or(!0, |id| id as u32), texture_id: target.texture.map_or(!0, |id| id as u32), - sampler_id: target.sampler.map_or(!0, |id| id as u32), + sampler_id: match target.sampler { + Some(naga::back::msl::BindSamplerTarget::Resource(id)) => id as u32, + _ => !0, + }, count: 0, }, ); @@ -1373,7 +1362,7 @@ impl hal::device::Device for Device { ); } // other properties - compiler_options.const_samplers = const_samplers; + compiler_options.const_samplers = cross_const_samplers; compiler_options.enable_argument_buffers = self.shared.private_caps.argument_buffers; compiler_options.force_zero_initialized_variables = true; compiler_options.force_native_arrays = true; @@ -1394,9 +1383,20 @@ impl hal::device::Device for Device { MTLLanguageVersion::V2_3 => (2, 3), }, binding_map, + inline_samplers, spirv_cross_compatibility: cfg!(feature = "cross"), fake_missing_bindings: false, - allow_point_size: false, + push_constants_map: naga::back::msl::PushConstantsMap { + vs_buffer: stage_infos[0] + .push_constant_buffer + .map(|buffer_index| buffer_index as naga::back::msl::Slot), + fs_buffer: stage_infos[1] + .push_constant_buffer + .map(|buffer_index| buffer_index as naga::back::msl::Slot), + cs_buffer: stage_infos[2] + .push_constant_buffer + .map(|buffer_index| buffer_index as naga::back::msl::Slot), + }, }; Ok(n::PipelineLayout { @@ -1433,71 +1433,133 @@ impl hal::device::Device for Device { }) } + #[cfg(not(feature = "pipeline-cache"))] unsafe fn create_pipeline_cache( &self, _data: Option<&[u8]>, ) -> Result { - Ok(n::PipelineCache { - #[cfg(feature = "cross")] - modules: FastStorageMap::default(), - }) + Ok(()) } + #[cfg(feature = "pipeline-cache")] + unsafe fn create_pipeline_cache( + &self, + data: Option<&[u8]>, + ) -> Result { + let device = self.shared.device.lock(); + + let create_binary_archive = |data: &[u8]| { + if self.shared.private_caps.supports_binary_archives { + let descriptor = metal::BinaryArchiveDescriptor::new(); + + // We need to keep the temp file alive so that it doesn't get deleted until after a + // binary archive has been created. + let _temp_file = if !data.is_empty() { + // It would be nice to use a `data:text/plain;base64` url here and just pass in a + // base64-encoded version of the data, but metal validation doesn't like that: + // -[MTLDebugDevice newBinaryArchiveWithDescriptor:error:]:1046: failed assertion `url, if not nil, must be a file URL.' + + let temp_file = tempfile::NamedTempFile::new().unwrap(); + temp_file.as_file().write_all(&data).unwrap(); + + let url = metal::URL::new_with_string(&format!( + "file://{}", + temp_file.path().display() + )); + descriptor.set_url(&url); + + Some(temp_file) + } else { + None + }; + + Ok(Some(pipeline_cache::BinaryArchive { + inner: device + .new_binary_archive_with_descriptor(&descriptor) + .map_err(|_| d::OutOfMemory::Device)?, + is_empty: AtomicBool::new(data.is_empty()), + })) + } else { + Ok(None) + } + }; + + if let Some(data) = data.filter(|data| !data.is_empty()) { + let pipeline_cache: pipeline_cache::SerializablePipelineCache = + bincode::deserialize(data).unwrap(); + + Ok(n::PipelineCache { + binary_archive: create_binary_archive(&pipeline_cache.binary_archive)?, + spv_to_msl: pipeline_cache::load_spv_to_msl_cache(pipeline_cache.spv_to_msl), + }) + } else { + Ok(n::PipelineCache { + binary_archive: create_binary_archive(&[])?, + spv_to_msl: Default::default(), + }) + } + } + + #[cfg(not(feature = "pipeline-cache"))] unsafe fn get_pipeline_cache_data( &self, _cache: &n::PipelineCache, ) -> Result, d::OutOfMemory> { - //empty Ok(Vec::new()) } + #[cfg(feature = "pipeline-cache")] + unsafe fn get_pipeline_cache_data( + &self, + cache: &n::PipelineCache, + ) -> Result, d::OutOfMemory> { + let binary_archive = || { + let binary_archive = match cache.binary_archive { + Some(ref binary_archive) => binary_archive, + None => return Ok(Vec::new()), + }; + + // Without this, we get an extremely vague "Serialization of binaries to file failed" + // error when serializing an empty binary archive. + if binary_archive.is_empty.load(Ordering::Relaxed) { + return Ok(Vec::new()); + } + + let temp_path = tempfile::NamedTempFile::new().unwrap().into_temp_path(); + let tmp_file_url = + metal::URL::new_with_string(&format!("file://{}", temp_path.display())); + + binary_archive + .inner + .serialize_to_url(&tmp_file_url) + .unwrap(); + + let bytes = std::fs::read(&temp_path).unwrap(); + Ok(bytes) + }; + + Ok( + bincode::serialize(&pipeline_cache::SerializablePipelineCache { + binary_archive: &binary_archive()?, + spv_to_msl: pipeline_cache::serialize_spv_to_msl_cache(&cache.spv_to_msl), + }) + .unwrap(), + ) + } + unsafe fn destroy_pipeline_cache(&self, _cache: n::PipelineCache) { //drop } - #[cfg_attr(not(feature = "cross"), allow(unused_variables))] unsafe fn merge_pipeline_caches<'a, I>( &self, - target: &mut n::PipelineCache, - sources: I, + _target: &mut n::PipelineCache, + _sources: I, ) -> Result<(), d::OutOfMemory> where I: Iterator, { - #[cfg(feature = "cross")] - { - //TODO: reduce the locking here - let mut dst = target.modules.whole_write(); - for source in sources { - let src = source.modules.whole_write(); - for (key, value) in src.iter() { - let storage = dst - .entry(key.clone()) - .or_insert_with(FastStorageMap::default); - let mut dst_module = storage.whole_write(); - let src_module = value.whole_write(); - for (key_module, value_module) in src_module.iter() { - match dst_module.entry(key_module.clone()) { - Entry::Vacant(em) => { - em.insert(value_module.clone()); - } - Entry::Occupied(em) => { - if em.get().library.as_ptr() != value_module.library.as_ptr() - || em.get().entry_point_map != value_module.entry_point_map - { - warn!( - "Merged module don't match, target: {:?}, source: {:?}", - em.get(), - value_module - ); - } - } - } - } - } - } - } - + warn!("`merge_pipeline_caches` is not currently implemented on the Metal backend."); Ok(()) } @@ -1506,7 +1568,9 @@ impl hal::device::Device for Device { pipeline_desc: &pso::GraphicsPipelineDesc<'a, Backend>, cache: Option<&n::PipelineCache>, ) -> Result { - debug!("create_graphics_pipeline {:#?}", pipeline_desc); + profiling::scope!("create_graphics_pipeline"); + trace!("create_graphics_pipeline {:#?}", pipeline_desc); + let pipeline = metal::RenderPipelineDescriptor::new(); let pipeline_layout = &pipeline_desc.layout; let (rp_attachments, subpass) = { @@ -1798,7 +1862,16 @@ impl hal::device::Device for Device { pipeline.set_label(name); } - device + profiling::scope!("Metal::new_render_pipeline_state"); + + #[cfg(feature = "pipeline-cache")] + if let Some(binary_archive) = pipeline_cache::pipeline_cache_to_binary_archive(cache) { + pipeline.set_binary_archives(&[&binary_archive.inner]); + } + + let pipeline_state = device + // Replace this with `new_render_pipeline_state_with_fail_on_binary_archive_miss` + // to debug that the cache is actually working. .new_render_pipeline_state(&pipeline) .map(|raw| n::GraphicsPipeline { vs_lib, @@ -1818,7 +1891,21 @@ impl hal::device::Device for Device { .map_err(|err| { error!("PSO creation failed: {}", err); pso::CreationError::Other - }) + })?; + + // We need to add the pipline descriptor to the binary archive after creating the + // pipeline, otherwise `new_render_pipeline_state_with_fail_on_binary_archive_miss` + // succeeds when it shouldn't. + #[cfg(feature = "pipeline-cache")] + if let Some(binary_archive) = pipeline_cache::pipeline_cache_to_binary_archive(cache) { + binary_archive + .inner + .add_render_pipeline_functions_with_descriptor(&pipeline) + .unwrap(); + binary_archive.is_empty.store(false, Ordering::Relaxed); + } + + Ok(pipeline_state) } unsafe fn create_compute_pipeline<'a>( @@ -1826,7 +1913,8 @@ impl hal::device::Device for Device { pipeline_desc: &pso::ComputePipelineDesc<'a, Backend>, cache: Option<&n::PipelineCache>, ) -> Result { - debug!("create_compute_pipeline {:?}", pipeline_desc); + profiling::scope!("create_compute_pipeline"); + trace!("create_compute_pipeline {:?}", pipeline_desc); let pipeline = metal::ComputePipelineDescriptor::new(); let (cs_lib, cs_function, work_group_size, _) = self.load_shader( @@ -1841,7 +1929,15 @@ impl hal::device::Device for Device { pipeline.set_label(name); } - self.shared + profiling::scope!("Metal::new_compute_pipeline_state"); + + #[cfg(feature = "pipeline-cache")] + if let Some(binary_archive) = pipeline_cache::pipeline_cache_to_binary_archive(cache) { + pipeline.set_binary_archives(&[&binary_archive.inner]); + } + + let pipeline_state = self + .shared .device .lock() .new_compute_pipeline_state(&pipeline) @@ -1854,7 +1950,20 @@ impl hal::device::Device for Device { .map_err(|err| { error!("PSO creation failed: {}", err); pso::CreationError::Other - }) + })?; + + // We need to add the pipline descriptor to the binary archive after creating the + // pipeline, see `create_graphics_pipeline`. + #[cfg(feature = "pipeline-cache")] + if let Some(binary_archive) = pipeline_cache::pipeline_cache_to_binary_archive(cache) { + binary_archive + .inner + .add_compute_pipeline_functions_with_descriptor(&pipeline) + .unwrap(); + binary_archive.is_empty.store(false, Ordering::Relaxed) + } + + Ok(pipeline_state) } unsafe fn create_framebuffer( @@ -1870,10 +1979,13 @@ impl hal::device::Device for Device { &self, raw_data: &[u32], ) -> Result { + profiling::scope!("create_shader_module"); Ok(n::ShaderModule { prefer_naga: self.always_prefer_naga, #[cfg(feature = "cross")] spv: raw_data.to_vec(), + #[cfg(feature = "pipeline-cache")] + spv_hash: fxhash::hash64(raw_data), naga: { let options = naga::front::spv::Options { adjust_coordinate_space: !self.features.contains(hal::Features::NDC_Y_UP), @@ -1900,15 +2012,21 @@ impl hal::device::Device for Device { &self, shader: d::NagaShader, ) -> Result { + profiling::scope!("create_shader_module_from_naga"); + + #[cfg(any(feature = "pipeline-cache", feature = "cross"))] + let spv = match naga::back::spv::write_vec(&shader.module, &shader.info, &self.spv_options) + { + Ok(spv) => spv, + Err(e) => return Err((d::ShaderError::CompilationFailed(format!("{}", e)), shader)), + }; + Ok(n::ShaderModule { prefer_naga: true, + #[cfg(feature = "pipeline-cache")] + spv_hash: fxhash::hash64(&spv), #[cfg(feature = "cross")] - spv: match naga::back::spv::write_vec(&shader.module, &shader.info, &self.spv_options) { - Ok(spv) => spv, - Err(e) => { - return Err((d::ShaderError::CompilationFailed(format!("{}", e)), shader)) - } - }, + spv, naga: Ok(shader), }) } @@ -1918,12 +2036,13 @@ impl hal::device::Device for Device { info: &image::SamplerDesc, ) -> Result { Ok(n::Sampler { - raw: match self.make_sampler_descriptor(&info) { + raw: match self.make_sampler_descriptor(info) { Some(ref descriptor) => Some(self.shared.device.lock().new_sampler(descriptor)), None => None, }, + data: conv::map_sampler_data_to_naga(info), #[cfg(feature = "cross")] - data: Self::make_sampler_data(&info), + cross_data: conv::map_sampler_data_to_cross(info), }) } @@ -2126,17 +2245,26 @@ impl hal::device::Device for Device { let usage = n::ArgumentArray::describe_usage(desc.ty); let bind_target = naga::back::msl::BindTarget { buffer: if content.contains(n::DescriptorContent::BUFFER) { - Some(arguments.push(metal::MTLDataType::Pointer, desc.count, usage) as u8) + Some( + arguments.push(metal::MTLDataType::Pointer, desc.count, usage) + as naga::back::msl::Slot, + ) } else { None }, texture: if content.contains(n::DescriptorContent::TEXTURE) { - Some(arguments.push(metal::MTLDataType::Texture, desc.count, usage) as u8) + Some( + arguments.push(metal::MTLDataType::Texture, desc.count, usage) + as naga::back::msl::Slot, + ) } else { None }, sampler: if content.contains(n::DescriptorContent::SAMPLER) { - Some(arguments.push(metal::MTLDataType::Sampler, desc.count, usage) as u8) + let slot = arguments.push(metal::MTLDataType::Sampler, desc.count, usage); + Some(naga::back::msl::BindSamplerTarget::Resource( + slot as naga::back::msl::Slot, + )) } else { None }, @@ -2145,7 +2273,10 @@ impl hal::device::Device for Device { let res_offset = bind_target .buffer .or(bind_target.texture) - .or(bind_target.sampler) + .or(bind_target.sampler.as_ref().and_then(|bst| match *bst { + naga::back::msl::BindSamplerTarget::Resource(slot) => Some(slot), + naga::back::msl::BindSamplerTarget::Inline(_) => None, + })) .unwrap() as u32; bindings.insert( desc.binding, @@ -2192,8 +2323,9 @@ impl hal::device::Device for Device { .enumerate() .map(|(array_index, sm)| TempSampler { data: n::ImmutableSampler { + data: sm.data.clone(), #[cfg(feature = "cross")] - cross_data: sm.data.clone(), + cross_data: sm.cross_data.clone(), }, binding: slb.binding, array_index, @@ -2915,6 +3047,7 @@ impl hal::device::Device for Device { kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, + _usage: image::Usage, range: image::SubresourceRange, ) -> Result { let mtl_format = match self diff --git a/third_party/rust/gfx-backend-metal/src/lib.rs b/third_party/rust/gfx-backend-metal/src/lib.rs index 568708a189aa..8a17f5e1d854 100644 --- a/third_party/rust/gfx-backend-metal/src/lib.rs +++ b/third_party/rust/gfx-backend-metal/src/lib.rs @@ -69,6 +69,7 @@ use cocoa_foundation::foundation::NSInteger; use dispatch; use foreign_types::ForeignTypeRef; use metal::MTLFeatureSet; +use metal::MTLGPUFamily; use metal::MTLLanguageVersion; use metal::{CGFloat, CGSize, MetalLayer, MetalLayerRef}; use objc::{ @@ -91,6 +92,8 @@ mod conversions; mod device; mod internal; mod native; +#[cfg(feature = "pipeline-cache")] +mod pipeline_cache; mod soft; mod window; @@ -746,6 +749,7 @@ struct PrivateCapabilities { max_total_threadgroup_memory: u32, sample_count_mask: u8, supports_debug_markers: bool, + supports_binary_archives: bool, } impl PrivateCapabilities { @@ -1042,6 +1046,8 @@ impl PrivateCapabilities { MTLFeatureSet::tvOS_GPUFamily2_v1, ], ), + supports_binary_archives: device.supports_family(MTLGPUFamily::Apple3) + || device.supports_family(MTLGPUFamily::Mac1), } } diff --git a/third_party/rust/gfx-backend-metal/src/native.rs b/third_party/rust/gfx-backend-metal/src/native.rs index a23c613ddb83..b925cc595e51 100644 --- a/third_party/rust/gfx-backend-metal/src/native.rs +++ b/third_party/rust/gfx-backend-metal/src/native.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "cross")] -use crate::internal::FastStorageMap; use crate::{ internal::Channel, Backend, BufferPtr, FastHashMap, ResourceIndex, SamplerPtr, TexturePtr, MAX_COLOR_ATTACHMENTS, @@ -28,6 +26,10 @@ use std::{ }; #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + feature = "pipeline-cache", + derive(serde::Serialize, serde::Deserialize) +)] pub struct EntryPoint { pub internal_name: Result, pub work_group_size: [u32; 3], @@ -41,6 +43,8 @@ pub struct ShaderModule { pub(crate) prefer_naga: bool, #[cfg(feature = "cross")] pub(crate) spv: Vec, + #[cfg(feature = "pipeline-cache")] + pub(crate) spv_hash: u64, pub(crate) naga: Result, } @@ -204,17 +208,22 @@ pub struct ModuleInfo { pub rasterization_enabled: bool, } -pub struct PipelineCache { - #[cfg(feature = "cross")] //TODO: Naga path - pub(crate) modules: - FastStorageMap, ModuleInfo>>, +#[derive(Clone, Debug)] +#[cfg_attr( + feature = "pipeline-cache", + derive(serde::Serialize, serde::Deserialize) +)] +pub struct SerializableModuleInfo { + pub source: String, + pub entry_point_map: EntryPointMap, + pub rasterization_enabled: bool, } -impl fmt::Debug for PipelineCache { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "PipelineCache") - } -} +#[cfg(not(feature = "pipeline-cache"))] +pub type PipelineCache = (); + +#[cfg(feature = "pipeline-cache")] +pub use crate::pipeline_cache::PipelineCache; #[derive(Clone, Debug, PartialEq)] pub struct RasterizerState { @@ -395,7 +404,8 @@ unsafe impl Sync for ImageView {} pub struct Sampler { pub(crate) raw: Option, #[cfg(feature = "cross")] - pub(crate) data: spirv_cross::msl::SamplerData, + pub(crate) cross_data: spirv_cross::msl::SamplerData, + pub(crate) data: naga::back::msl::sampler::InlineSampler, } unsafe impl Send for Sampler {} @@ -875,6 +885,7 @@ pub struct ArgumentLayout { #[derive(Debug)] pub struct ImmutableSampler { + pub(crate) data: naga::back::msl::sampler::InlineSampler, #[cfg(feature = "cross")] pub(crate) cross_data: spirv_cross::msl::SamplerData, } diff --git a/third_party/rust/gfx-backend-metal/src/pipeline_cache.rs b/third_party/rust/gfx-backend-metal/src/pipeline_cache.rs new file mode 100644 index 000000000000..f2ddeb44601a --- /dev/null +++ b/third_party/rust/gfx-backend-metal/src/pipeline_cache.rs @@ -0,0 +1,64 @@ +use crate::internal::FastStorageMap; +use crate::native::SerializableModuleInfo; +use std::fmt; +use std::sync::atomic::AtomicBool; + +pub(crate) struct BinaryArchive { + pub(crate) inner: metal::BinaryArchive, + pub(crate) is_empty: AtomicBool, +} + +unsafe impl Send for BinaryArchive {} + +unsafe impl Sync for BinaryArchive {} + +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq, Hash)] +pub(crate) struct SpvToMslKey { + pub(crate) options: naga::back::msl::Options, + pub(crate) pipeline_options: naga::back::msl::PipelineOptions, + pub(crate) spv_hash: u64, +} + +pub(crate) type SpvToMsl = FastStorageMap; + +pub(crate) type SerializableSpvToMsl = Vec<(SpvToMslKey, SerializableModuleInfo)>; + +pub(crate) fn load_spv_to_msl_cache(serializable: SerializableSpvToMsl) -> SpvToMsl { + let cache = FastStorageMap::default(); + for (options, values) in serializable.into_iter() { + cache.get_or_create_with(&options, || values); + } + + cache +} + +pub(crate) fn serialize_spv_to_msl_cache(cache: &SpvToMsl) -> SerializableSpvToMsl { + cache + .whole_write() + .iter() + .map(|(options, values)| (options.clone(), values.clone())) + .collect() +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub(crate) struct SerializablePipelineCache<'a> { + pub(crate) binary_archive: &'a [u8], + pub(crate) spv_to_msl: SerializableSpvToMsl, +} + +pub struct PipelineCache { + pub(crate) binary_archive: Option, + pub(crate) spv_to_msl: SpvToMsl, +} + +impl fmt::Debug for PipelineCache { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "PipelineCache") + } +} + +pub(crate) fn pipeline_cache_to_binary_archive( + pipeline_cache: Option<&PipelineCache>, +) -> Option<&BinaryArchive> { + pipeline_cache.and_then(|cache| cache.binary_archive.as_ref()) +} diff --git a/third_party/rust/gfx-backend-metal/src/soft.rs b/third_party/rust/gfx-backend-metal/src/soft.rs index 5064880ef990..f2e5ebc5a00e 100644 --- a/third_party/rust/gfx-backend-metal/src/soft.rs +++ b/third_party/rust/gfx-backend-metal/src/soft.rs @@ -18,6 +18,7 @@ pub trait Resources: Debug { type DepthStencil: Debug; type RenderPipeline: Debug; type ComputePipeline: Debug; + type Marker: Debug + AsRef; } #[derive(Clone, Debug, Default)] @@ -36,6 +37,7 @@ impl Resources for Own { type DepthStencil = metal::DepthStencilState; type RenderPipeline = metal::RenderPipelineState; type ComputePipeline = metal::ComputePipelineState; + type Marker = String; } #[derive(Debug)] @@ -48,6 +50,7 @@ impl<'a> Resources for &'a Ref { type DepthStencil = &'a metal::DepthStencilStateRef; type RenderPipeline = &'a metal::RenderPipelineStateRef; type ComputePipeline = &'a metal::ComputePipelineStateRef; + type Marker = &'a str; } //TODO: Remove `Clone` from here, blocked by arguments of `quick_render` and @@ -116,6 +119,13 @@ pub enum RenderCommand { buffer: BufferPtr, offset: hal::buffer::Offset, }, + InsertDebugMarker { + name: R::Marker, + }, + PushDebugMarker { + name: R::Marker, + }, + PopDebugGroup, } #[derive(Clone, Debug)] @@ -318,6 +328,13 @@ impl Own { buffer, offset, }, + InsertDebugMarker { name } => InsertDebugMarker { + name: name.to_owned(), + }, + PushDebugMarker { name } => PushDebugMarker { + name: name.to_owned(), + }, + PopDebugGroup => PopDebugGroup, } } @@ -416,7 +433,10 @@ impl Own { | Draw { .. } | DrawIndexed { .. } | DrawIndirect { .. } - | DrawIndexedIndirect { .. } => {} + | DrawIndexedIndirect { .. } + | InsertDebugMarker { .. } + | PushDebugMarker { .. } + | PopDebugGroup => {} } } diff --git a/third_party/rust/gfx-backend-metal/src/window.rs b/third_party/rust/gfx-backend-metal/src/window.rs index f3dcc68922d7..33dd4ca14f07 100644 --- a/third_party/rust/gfx-backend-metal/src/window.rs +++ b/third_party/rust/gfx-backend-metal/src/window.rs @@ -241,7 +241,9 @@ impl w::PresentationSurface for Surface { device: &Device, config: w::SwapchainConfig, ) -> Result<(), w::SwapchainError> { - assert!(image::Usage::COLOR_ATTACHMENT.contains(config.image_usage)); + if !image::Usage::COLOR_ATTACHMENT.contains(config.image_usage) { + warn!("Swapchain usage {:?} is not expected", config.image_usage); + } self.swapchain_format = self.configure(&device.shared, &config); Ok(()) } diff --git a/third_party/rust/gfx-backend-vulkan/.cargo-checksum.json b/third_party/rust/gfx-backend-vulkan/.cargo-checksum.json index f3dc6bba5a48..2ad7849d3341 100644 --- a/third_party/rust/gfx-backend-vulkan/.cargo-checksum.json +++ b/third_party/rust/gfx-backend-vulkan/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e4172417636bb8d4267ea04b482242d9dc0b0f63a5b260ecccd6be3ebb4d7a63","README.md":"18c8b36bca25cef6642315221fe0713e23054430377cd465fdb2c4fe7f332daf","src/command.rs":"5834a642982bccc7b524702beda8ecbd69b2831f7daa0516387e77fed21fc8a0","src/conv.rs":"4e749a0bf3eeb541e80daddf352e25644b57b0fb7fd1e1c8a38a3d5fd18ad2f6","src/device.rs":"876fcc7e31274b898bffdf0723003dcff466bec6df24d816104b0cfd9a489519","src/info.rs":"4a21b54f85ff73c538ca2f57f4d371eb862b5a28f126cd0ecafd37fc6dfd1318","src/lib.rs":"53caf342c14d23fede11c34f987bc5084db375a43927b60930e82062d207c165","src/native.rs":"72099d0499e72625496bea64d968f650a6d43fe24840ace9b0c419bd60e3a3c6","src/physical_device.rs":"4e6b4b300782054f7514a4414b27f6b64f457f787035c3d20c294ad2198dd2da","src/pool.rs":"16d174bb274c2dd2f4b94379835269825695dca581436a57b8942b27811255fc","src/window.rs":"5e4763bb3a56d31b5d8ac9c0b3783c03b2cc86af14fb99a9d36a986f12b6760f"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"b59d8e87966e67aa22cbfa4f16611f5430c55a8a583d355cbd93995f954035ed","README.md":"18c8b36bca25cef6642315221fe0713e23054430377cd465fdb2c4fe7f332daf","src/command.rs":"5834a642982bccc7b524702beda8ecbd69b2831f7daa0516387e77fed21fc8a0","src/conv.rs":"04ce2a815fd65b53b52b3f54fa243f4b27a0e9b3ab8809d9b11615b190b198fc","src/device.rs":"8ddbc8330049b2132b52931d034775d6d8d352837a5f0ceb86247e406e15408c","src/info.rs":"4a21b54f85ff73c538ca2f57f4d371eb862b5a28f126cd0ecafd37fc6dfd1318","src/lib.rs":"ea5aa64409d2942acdbec747f7de4c20d82bd544735e4dee4ffdc44e07e31127","src/native.rs":"72099d0499e72625496bea64d968f650a6d43fe24840ace9b0c419bd60e3a3c6","src/physical_device.rs":"e9537adb7cf13899be5f36571eae56c5a1b9a25997cd52504a87e9882b0eb06c","src/pool.rs":"16d174bb274c2dd2f4b94379835269825695dca581436a57b8942b27811255fc","src/window.rs":"6bcc4bec8308bcc747391fcbd8395d78943bf2a97bc0ae1cf9e66c5383da7fd6"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-backend-vulkan/Cargo.toml b/third_party/rust/gfx-backend-vulkan/Cargo.toml index 47cd5dfa6dce..c056429f1e23 100644 --- a/third_party/rust/gfx-backend-vulkan/Cargo.toml +++ b/third_party/rust/gfx-backend-vulkan/Cargo.toml @@ -33,7 +33,7 @@ inplace_it = "0.3.3" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -tag = "gfx-20" +tag = "gfx-22" features = ["spv-out"] optional = true diff --git a/third_party/rust/gfx-backend-vulkan/src/conv.rs b/third_party/rust/gfx-backend-vulkan/src/conv.rs index f982ae06f7e7..69b96c55b2f9 100644 --- a/third_party/rust/gfx-backend-vulkan/src/conv.rs +++ b/third_party/rust/gfx-backend-vulkan/src/conv.rs @@ -225,6 +225,15 @@ pub fn map_wrap(wrap: image::WrapMode) -> vk::SamplerAddressMode { } } +pub fn map_reduction(reduction: image::ReductionMode) -> vk::SamplerReductionMode { + use hal::image::ReductionMode as Rm; + match reduction { + Rm::WeightedAverage => vk::SamplerReductionMode::WEIGHTED_AVERAGE, + Rm::Minimum => vk::SamplerReductionMode::MIN, + Rm::Maximum => vk::SamplerReductionMode::MAX, + } +} + pub fn map_border_color(border_color: image::BorderColor) -> vk::BorderColor { match border_color { image::BorderColor::TransparentBlack => vk::BorderColor::FLOAT_TRANSPARENT_BLACK, diff --git a/third_party/rust/gfx-backend-vulkan/src/device.rs b/third_party/rust/gfx-backend-vulkan/src/device.rs index e2e8db28ed8a..307bcf427786 100644 --- a/third_party/rust/gfx-backend-vulkan/src/device.rs +++ b/third_party/rust/gfx-backend-vulkan/src/device.rs @@ -403,7 +403,7 @@ impl<'a> GraphicsPipelineInfoBuf<'a> { .logic_op_enable(false) // TODO .logic_op(vk::LogicOp::CLEAR) .attachments(&this.blend_states) // TODO: - .blend_constants(match desc.baked_states.blend_color { + .blend_constants(match desc.baked_states.blend_constants { Some(value) => value, None => { this.dynamic_states.push(vk::DynamicState::BLEND_CONSTANTS); @@ -987,7 +987,9 @@ impl d::Device for super::Device { (false, 1.0) } }); - let info = vk::SamplerCreateInfo::builder() + + let mut reduction_info; + let mut info = vk::SamplerCreateInfo::builder() .flags(vk::SamplerCreateFlags::empty()) .mag_filter(conv::map_filter(desc.mag_filter)) .min_filter(conv::map_filter(desc.min_filter)) @@ -1007,6 +1009,13 @@ impl d::Device for super::Device { .border_color(conv::map_border_color(desc.border)) .unnormalized_coordinates(!desc.normalized); + if self.shared.features.contains(Features::SAMPLER_REDUCTION) { + reduction_info = vk::SamplerReductionModeCreateInfo::builder() + .reduction_mode(conv::map_reduction(desc.reduction_mode)) + .build(); + info = info.push_next(&mut reduction_info); + } + let result = self.shared.raw.create_sampler(&info, None); match result { @@ -1200,12 +1209,14 @@ impl d::Device for super::Device { kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, + usage: image::Usage, range: image::SubresourceRange, ) -> Result { let is_cube = image .flags .intersects(vk::ImageCreateFlags::CUBE_COMPATIBLE); - let info = vk::ImageViewCreateInfo::builder() + let mut image_view_info; + let mut info = vk::ImageViewCreateInfo::builder() .flags(vk::ImageViewCreateFlags::empty()) .image(image.raw) .view_type(match conv::map_view_kind(kind, image.ty, is_cube) { @@ -1216,6 +1227,13 @@ impl d::Device for super::Device { .components(conv::map_swizzle(swizzle)) .subresource_range(conv::map_subresource_range(&range)); + if self.shared.image_view_usage { + image_view_info = vk::ImageViewUsageCreateInfo::builder() + .usage(conv::map_image_usage(usage)) + .build(); + info = info.push_next(&mut image_view_info); + } + let result = self.shared.raw.create_image_view(&info, None); match result { @@ -1962,7 +1980,10 @@ impl super::Device { Err(vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR) => { return Err(hal::window::SwapchainError::WindowInUse) } - _ => unreachable!("Unexpected result - driver bug? {:?}", result), + Err(other) => { + error!("Unexpected result - driver bug? {:?}", other); + return Err(hal::window::SwapchainError::Unknown); + } }; let result = functor.get_swapchain_images(swapchain_raw); diff --git a/third_party/rust/gfx-backend-vulkan/src/lib.rs b/third_party/rust/gfx-backend-vulkan/src/lib.rs index 885a5257fd7b..b3be64b81173 100644 --- a/third_party/rust/gfx-backend-vulkan/src/lib.rs +++ b/third_party/rust/gfx-backend-vulkan/src/lib.rs @@ -708,6 +708,7 @@ pub struct RawDevice { /// This flag is `true` if the device has `VK_KHR_maintenance1`/1.1+ and `false` otherwise (i.e. in the case of `VK_AMD_negative_viewport_height`). flip_y_requires_shift: bool, imageless_framebuffers: bool, + image_view_usage: bool, timestamp_period: f32, } diff --git a/third_party/rust/gfx-backend-vulkan/src/physical_device.rs b/third_party/rust/gfx-backend-vulkan/src/physical_device.rs index 9eef17236606..20ab5458df97 100644 --- a/third_party/rust/gfx-backend-vulkan/src/physical_device.rs +++ b/third_party/rust/gfx-backend-vulkan/src/physical_device.rs @@ -1,5 +1,5 @@ use ash::{ - extensions::{self, khr::DrawIndirectCount, khr::Swapchain, nv::MeshShader}, + extensions::{khr::DrawIndirectCount, khr::Swapchain, nv::MeshShader}, version::{DeviceV1_0, InstanceV1_0}, vk, }; @@ -66,7 +66,6 @@ impl PhysicalDeviceFeatures { enabled_extensions: &[&'static CStr], requested_features: Features, supports_vulkan12_imageless_framebuffer: bool, - supports_vulkan12_sampler_filter_minmax: bool, ) -> PhysicalDeviceFeatures { // This must follow the "Valid Usage" requirements of [`VkDeviceCreateInfo`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkDeviceCreateInfo.html). let features = requested_features; @@ -183,7 +182,7 @@ impl PhysicalDeviceFeatures { .runtime_descriptor_array( features.contains(Features::UNSIZED_DESCRIPTOR_ARRAY), ) - .sampler_filter_minmax(supports_vulkan12_sampler_filter_minmax) + .sampler_filter_minmax(features.contains(Features::SAMPLER_REDUCTION)) .imageless_framebuffer(supports_vulkan12_imageless_framebuffer) .build(), ) @@ -424,14 +423,15 @@ impl PhysicalDeviceFeatures { bits |= Features::NDC_Y_UP; } - if info.supports_extension(vk::KhrSamplerMirrorClampToEdgeFn::name()) - || info.api_version() >= Version::V1_2 - { + if info.supports_extension(vk::KhrSamplerMirrorClampToEdgeFn::name()) { bits |= Features::SAMPLER_MIRROR_CLAMP_EDGE; } - if info.supports_extension(DrawIndirectCount::name()) || info.api_version() >= Version::V1_2 - { + if info.supports_extension(vk::ExtSamplerFilterMinmaxFn::name()) { + bits |= Features::SAMPLER_REDUCTION; + } + + if info.supports_extension(DrawIndirectCount::name()) { bits |= Features::DRAW_INDIRECT_COUNT } @@ -458,6 +458,9 @@ impl PhysicalDeviceFeatures { if vulkan_1_2.sampler_mirror_clamp_to_edge != 0 { bits |= Features::SAMPLER_MIRROR_CLAMP_EDGE; } + if vulkan_1_2.sampler_filter_minmax != 0 { + bits |= Features::SAMPLER_REDUCTION + } if vulkan_1_2.draw_indirect_count != 0 { bits |= Features::DRAW_INDIRECT_COUNT } @@ -515,7 +518,7 @@ impl PhysicalDeviceInfo { fn get_required_extensions(&self, requested_features: Features) -> Vec<&'static CStr> { let mut requested_extensions = Vec::new(); - requested_extensions.push(extensions::khr::Swapchain::name()); + requested_extensions.push(Swapchain::name()); if self.api_version() < Version::V1_1 { requested_extensions.push(vk::KhrMaintenance1Fn::name()); @@ -558,6 +561,12 @@ impl PhysicalDeviceInfo { requested_extensions.push(vk::KhrSamplerMirrorClampToEdgeFn::name()); } + if self.api_version() < Version::V1_2 + && requested_features.contains(Features::SAMPLER_REDUCTION) + { + requested_extensions.push(vk::ExtSamplerFilterMinmaxFn::name()); + } + if requested_features.intersects(Features::MESH_SHADER_MASK) { requested_extensions.push(MeshShader::name()); } @@ -666,6 +675,7 @@ pub struct PhysicalDevice { known_memory_flags: vk::MemoryPropertyFlags, device_info: PhysicalDeviceInfo, device_features: PhysicalDeviceFeatures, + available_features: Features, } pub(crate) fn load_adapter( @@ -693,6 +703,23 @@ pub(crate) fn load_adapter( }, }; + let available_features = { + let mut bits = device_features.to_hal_features(&device_info); + + // see https://github.com/gfx-rs/gfx/issues/1930 + let is_windows_intel_dual_src_bug = cfg!(windows) + && device_info.properties.vendor_id == info::intel::VENDOR + && (device_info.properties.device_id & info::intel::DEVICE_KABY_LAKE_MASK + == info::intel::DEVICE_KABY_LAKE_MASK + || device_info.properties.device_id & info::intel::DEVICE_SKY_LAKE_MASK + == info::intel::DEVICE_SKY_LAKE_MASK); + if is_windows_intel_dual_src_bug { + bits.set(Features::DUAL_SRC_BLENDING, false); + } + + bits + }; + let physical_device = PhysicalDevice { instance: instance.clone(), handle: device, @@ -703,6 +730,7 @@ pub(crate) fn load_adapter( | vk::MemoryPropertyFlags::LAZILY_ALLOCATED, device_info, device_features, + available_features, }; let queue_families = unsafe { @@ -809,9 +837,6 @@ impl adapter::PhysicalDevice for PhysicalDevice { &enabled_extensions, requested_features, supports_vulkan12_imageless_framebuffer, - self.device_features - .vulkan_1_2 - .map_or(false, |features| features.sampler_filter_minmax == vk::TRUE), ); let info = vk::DeviceCreateInfo::builder() .queue_create_infos(&family_infos) @@ -912,6 +937,10 @@ impl adapter::PhysicalDevice for PhysicalDevice { || self .device_info .supports_extension(vk::KhrImagelessFramebufferFn::name()), + image_view_usage: self.device_info.api_version() >= Version::V1_1 + || self + .device_info + .supports_extension(vk::KhrMaintenance2Fn::name()), timestamp_period: self.device_info.properties.limits.timestamp_period, }), vendor_id: self.device_info.properties.vendor_id, @@ -956,12 +985,8 @@ impl adapter::PhysicalDevice for PhysicalDevice { .supports_extension(vk::KhrMaintenance1Fn::name()); let supports_sampler_filter_minmax = self - .device_info - .supports_extension(vk::ExtSamplerFilterMinmaxFn::name()) - || self - .device_features - .vulkan_1_2 - .map_or(false, |features| features.sampler_filter_minmax == vk::TRUE); + .available_features + .contains(Features::SAMPLER_REDUCTION); format::Properties { linear_tiling: conv::map_image_features( @@ -1062,20 +1087,7 @@ impl adapter::PhysicalDevice for PhysicalDevice { } fn features(&self) -> Features { - let mut bits = self.device_features.to_hal_features(&self.device_info); - - // see https://github.com/gfx-rs/gfx/issues/1930 - let is_windows_intel_dual_src_bug = cfg!(windows) - && self.device_info.properties.vendor_id == info::intel::VENDOR - && (self.device_info.properties.device_id & info::intel::DEVICE_KABY_LAKE_MASK - == info::intel::DEVICE_KABY_LAKE_MASK - || self.device_info.properties.device_id & info::intel::DEVICE_SKY_LAKE_MASK - == info::intel::DEVICE_SKY_LAKE_MASK); - if is_windows_intel_dual_src_bug { - bits = bits & !Features::DUAL_SRC_BLENDING; - } - - bits + self.available_features } fn properties(&self) -> PhysicalDeviceProperties { @@ -1192,6 +1204,7 @@ impl adapter::PhysicalDevice for PhysicalDevice { let mut descriptor_indexing_capabilities = hal::DescriptorIndexingProperties::default(); let mut mesh_shader_capabilities = hal::MeshShaderProperties::default(); + let mut sampler_reduction_capabilities = hal::SamplerReductionProperties::default(); if let Some(get_physical_device_properties) = self.instance.get_physical_device_properties.as_ref() @@ -1199,13 +1212,16 @@ impl adapter::PhysicalDevice for PhysicalDevice { let mut descriptor_indexing_properties = vk::PhysicalDeviceDescriptorIndexingPropertiesEXT::builder(); let mut mesh_shader_properties = vk::PhysicalDeviceMeshShaderPropertiesNV::builder(); + let mut sampler_reduction_properties = + vk::PhysicalDeviceSamplerFilterMinmaxProperties::builder(); unsafe { get_physical_device_properties.get_physical_device_properties2_khr( self.handle, &mut vk::PhysicalDeviceProperties2::builder() - .push_next(&mut mesh_shader_properties) .push_next(&mut descriptor_indexing_properties) + .push_next(&mut mesh_shader_properties) + .push_next(&mut sampler_reduction_properties) .build() as *mut _, ); } @@ -1255,12 +1271,22 @@ impl adapter::PhysicalDevice for PhysicalDevice { mesh_output_per_primitive_granularity: mesh_shader_properties .mesh_output_per_primitive_granularity, }; + + sampler_reduction_capabilities = hal::SamplerReductionProperties { + single_component_formats: sampler_reduction_properties + .filter_minmax_single_component_formats + == vk::TRUE, + image_component_mapping: sampler_reduction_properties + .filter_minmax_image_component_mapping + == vk::TRUE, + }; } PhysicalDeviceProperties { limits, descriptor_indexing: descriptor_indexing_capabilities, mesh_shader: mesh_shader_capabilities, + sampler_reduction: sampler_reduction_capabilities, performance_caveats: Default::default(), dynamic_pipeline_states: DynamicStates::all(), downlevel: DownlevelProperties::all_enabled(), diff --git a/third_party/rust/gfx-backend-vulkan/src/window.rs b/third_party/rust/gfx-backend-vulkan/src/window.rs index a27d8c68e272..ea6e040b938c 100644 --- a/third_party/rust/gfx-backend-vulkan/src/window.rs +++ b/third_party/rust/gfx-backend-vulkan/src/window.rs @@ -358,6 +358,7 @@ impl w::PresentationSurface for Surface { ) -> Result<(), w::SwapchainError> { use hal::device::Device as _; + let usage = config.image_usage; let format = config.format; let old = self .swapchain @@ -380,6 +381,7 @@ impl w::PresentationSurface for Surface { hal::image::ViewKind::D2, format, hal::format::Swizzle::NO, + usage, hal::image::SubresourceRange { aspects: hal::format::Aspects::COLOR, ..Default::default() diff --git a/third_party/rust/gfx-hal/.cargo-checksum.json b/third_party/rust/gfx-hal/.cargo-checksum.json index 9461c0a7d6be..c6271fff6456 100644 --- a/third_party/rust/gfx-hal/.cargo-checksum.json +++ b/third_party/rust/gfx-hal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0d5a50a10c282ac99c76702d61d3d2b269c53704786fdd57000a60e733f6ba62","src/adapter.rs":"301e36e78467e229bd7f140336fa4a64005a289f6a2a6139b1182e8e0d37f146","src/buffer.rs":"076031b8d4d8a7478888f4e8f5b142b916118832aedc01605066fe54d7b8840a","src/command/clear.rs":"94c4c7188e925275850359296fa0d6e523b19a6e0b868faea996867e45454a3b","src/command/mod.rs":"73e891e27d591405a881455394865d522c09179bfd2711e075684f314a3c527a","src/command/structs.rs":"00b5850540ae21227c6578866e86cc741d074601239f8b1bbd0342a5e5f74623","src/device.rs":"872f69eeede580ba2a4f0c9153342e2c6e17e5c36e67d0f2f2b4921057fc3c28","src/format.rs":"5400f77897740ad6cf13d8d26c4a032cc7629ba7b7ff8628ca25ad67c8e79f8c","src/image.rs":"1beccc7c044f4a9e550c75800159fa19355cad8fda83bf8a35e184784fffa466","src/lib.rs":"262f3456c53d34f8fb65ba31835068511872d8f39f737234f5eb2636b5d8361e","src/memory.rs":"0f71319c5d2d8ef2f45b41ed451f450f3350baab4c11c99f8940fe13837637db","src/pass.rs":"10e60b840ceca18d1a37003653d14e47c1d9e31948dab554f933c1778e46639f","src/pool.rs":"f8517834b3fffe99a7147188cbc65ffcdb582cded4280f14af0878c34cf836f6","src/pso/compute.rs":"93814076966c4e4658cada975c2615fd8dc919e5c96cb265cc6da102191cc6c8","src/pso/descriptor.rs":"60dcde7c74b41cabe72117e640607302d14dbe4fd42b95f8e9933b0d410fd4c2","src/pso/graphics.rs":"7d53b720cba5698f7b0400a776b5894293218b88a4862d34e231c4b024e82d68","src/pso/input_assembler.rs":"0f75dcbc26e253a3ad531089b969e25b9cc86ec9c938f056a62e82ad36383ccb","src/pso/mod.rs":"4680a7156654941cd9f911cefa6548ea7fd814a02c4c999bb7486398a10ec43c","src/pso/output_merger.rs":"cfd3b9ba8b8ba85c497e8bdb9f594a1bd83b1c12b99f40c833e1be4ceadace80","src/pso/specialization.rs":"c6335efebcd358250c54c3698e86b2897bcc04e9e1318708b80330f09a0b8521","src/query.rs":"5e168845383e97081b23e88e2c287d4bf0318db4e35d9b55c820376c24e99ee1","src/queue/family.rs":"d2ffb5b3b90591796df4ef43895e70e8607c6fc233e13313accba438b8f264b6","src/queue/mod.rs":"c13ad81215a2cc05c3a4d2c936247319398e9a6c8407b4a816a81d1d4e48f480","src/window.rs":"ad4b88a05a3842ae1afee8b2d79823b40e8a9bfed77540013a62a0c970c9109e"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"6c0d7d1eeece31d1ff3b12161ecc8c7b655884b498db89dc8fa968676ba6ca90","src/adapter.rs":"301e36e78467e229bd7f140336fa4a64005a289f6a2a6139b1182e8e0d37f146","src/buffer.rs":"076031b8d4d8a7478888f4e8f5b142b916118832aedc01605066fe54d7b8840a","src/command/clear.rs":"94c4c7188e925275850359296fa0d6e523b19a6e0b868faea996867e45454a3b","src/command/mod.rs":"73e891e27d591405a881455394865d522c09179bfd2711e075684f314a3c527a","src/command/structs.rs":"00b5850540ae21227c6578866e86cc741d074601239f8b1bbd0342a5e5f74623","src/device.rs":"bc1dd5450b44fc01251f039b2ae2e1e8da2a9d5ef35f89adcf706a5de2c2dcd8","src/format.rs":"5400f77897740ad6cf13d8d26c4a032cc7629ba7b7ff8628ca25ad67c8e79f8c","src/image.rs":"159faa0e3ba4405dbfe619f362157130b2abda0feaa85afbe6b2f7773c3390f6","src/lib.rs":"89f6511bea451cca3efa020a7e0f307578b2dfb83b7d7697337e466b1c53f7f3","src/memory.rs":"0f71319c5d2d8ef2f45b41ed451f450f3350baab4c11c99f8940fe13837637db","src/pass.rs":"10e60b840ceca18d1a37003653d14e47c1d9e31948dab554f933c1778e46639f","src/pool.rs":"f8517834b3fffe99a7147188cbc65ffcdb582cded4280f14af0878c34cf836f6","src/pso/compute.rs":"93814076966c4e4658cada975c2615fd8dc919e5c96cb265cc6da102191cc6c8","src/pso/descriptor.rs":"60dcde7c74b41cabe72117e640607302d14dbe4fd42b95f8e9933b0d410fd4c2","src/pso/graphics.rs":"2e4b585e63c54fa3c5b53848d8b7209bc65eab156abb28c326ae9ac33fd034fb","src/pso/input_assembler.rs":"0f75dcbc26e253a3ad531089b969e25b9cc86ec9c938f056a62e82ad36383ccb","src/pso/mod.rs":"4680a7156654941cd9f911cefa6548ea7fd814a02c4c999bb7486398a10ec43c","src/pso/output_merger.rs":"cfd3b9ba8b8ba85c497e8bdb9f594a1bd83b1c12b99f40c833e1be4ceadace80","src/pso/specialization.rs":"ab4c4d9a4907e9aa12ab2bbb92a47f52a2a0ee3dc00d0c1c72c438282161b039","src/query.rs":"5e168845383e97081b23e88e2c287d4bf0318db4e35d9b55c820376c24e99ee1","src/queue/family.rs":"d2ffb5b3b90591796df4ef43895e70e8607c6fc233e13313accba438b8f264b6","src/queue/mod.rs":"c13ad81215a2cc05c3a4d2c936247319398e9a6c8407b4a816a81d1d4e48f480","src/window.rs":"eed377aaa6bc3a041e12b9eaadecb9f8cd1bd28070bafe3cbab20bfae8a3f92e"},"package":null} \ No newline at end of file diff --git a/third_party/rust/gfx-hal/Cargo.toml b/third_party/rust/gfx-hal/Cargo.toml index 494bca077c79..90a7e5bed96c 100644 --- a/third_party/rust/gfx-hal/Cargo.toml +++ b/third_party/rust/gfx-hal/Cargo.toml @@ -20,7 +20,7 @@ path = "src/lib.rs" [dependencies] bitflags = "1.0" -naga = { git = "https://github.com/gfx-rs/naga", tag = "gfx-20" } +naga = { git = "https://github.com/gfx-rs/naga", tag = "gfx-22" } raw-window-handle = "0.3" serde = { version = "1", features = ["serde_derive"], optional = true } thiserror = "1" diff --git a/third_party/rust/gfx-hal/src/device.rs b/third_party/rust/gfx-hal/src/device.rs index 42b48a3ee3c0..14702b6e2176 100644 --- a/third_party/rust/gfx-hal/src/device.rs +++ b/third_party/rust/gfx-hal/src/device.rs @@ -455,6 +455,7 @@ pub trait Device: fmt::Debug + Any + Send + Sync { view_kind: image::ViewKind, format: format::Format, swizzle: format::Swizzle, + usage: image::Usage, range: image::SubresourceRange, ) -> Result; diff --git a/third_party/rust/gfx-hal/src/image.rs b/third_party/rust/gfx-hal/src/image.rs index b68fb47d27fc..3c03b7735090 100644 --- a/third_party/rust/gfx-hal/src/image.rs +++ b/third_party/rust/gfx-hal/src/image.rs @@ -397,6 +397,20 @@ pub enum WrapMode { MirrorClamp, } +/// Specifies how the image texels in the filter kernel are reduced to a single value. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum ReductionMode { + /// + WeightedAverage, + /// + /// Only valid if `Features::SAMPLER_FILTER_MINMAX` is enabled. + Minimum, + /// + /// Only valid if `Features::SAMPLER_FILTER_MINMAX` is enabled. + Maximum, +} + /// A wrapper for the LOD level of an image. Needed so that we can /// implement Eq and Hash for it. #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] @@ -467,7 +481,6 @@ impl Into<[f32; 4]> for BorderColor { /// available that alter how the GPU goes from a coordinate in an image /// to producing an actual value from the texture, including filtering/ /// scaling, wrap mode, etc. -// TODO: document the details of sampling. #[derive(Clone, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SamplerDesc { @@ -477,6 +490,8 @@ pub struct SamplerDesc { pub mag_filter: Filter, /// Mip filter method to use. pub mip_filter: Filter, + /// Reduction mode over the filter. + pub reduction_mode: ReductionMode, /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL /// speak). pub wrap_mode: (WrapMode, WrapMode, WrapMode), @@ -506,6 +521,7 @@ impl SamplerDesc { min_filter: filter, mag_filter: filter, mip_filter: filter, + reduction_mode: ReductionMode::WeightedAverage, wrap_mode: (wrap, wrap, wrap), lod_bias: Lod(0.0), lod_range: Lod::RANGE.clone(), diff --git a/third_party/rust/gfx-hal/src/lib.rs b/third_party/rust/gfx-hal/src/lib.rs index 704c34808aab..2f71b8690e0b 100644 --- a/third_party/rust/gfx-hal/src/lib.rs +++ b/third_party/rust/gfx-hal/src/lib.rs @@ -287,6 +287,8 @@ bitflags! { const MESH_SHADER = 0x0002 << 96; /// Mask for all the features associated with mesh shader stages. const MESH_SHADER_MASK = Features::TASK_SHADER.bits | Features::MESH_SHADER.bits; + /// Support sampler min/max reduction mode. + const SAMPLER_REDUCTION = 0x0004 << 96; } } @@ -312,8 +314,8 @@ bitflags! { const SCISSOR = 0x0002; /// Supports `Rasterizer::line_width == State::Dynamic(_)` const LINE_WIDTH = 0x0004; - /// Supports `BakedStates::blend_color == None` - const BLEND_COLOR = 0x0008; + /// Supports `BakedStates::blend_constants == None` + const BLEND_CONSTANTS = 0x0008; /// Supports `Rasterizer::depth_bias == Some(State::Dynamic(_))` const DEPTH_BIAS = 0x0010; /// Supports `BakedStates::depth_bounds == None` @@ -340,6 +342,8 @@ pub struct PhysicalDeviceProperties { pub descriptor_indexing: DescriptorIndexingProperties, /// Mesh Shader properties. pub mesh_shader: MeshShaderProperties, + /// Sampler reduction modes. + pub sampler_reduction: SamplerReductionProperties, /// Downlevel properties. pub downlevel: DownlevelProperties, /// Performance caveats. @@ -571,6 +575,16 @@ pub struct MeshShaderProperties { pub mesh_output_per_primitive_granularity: u32, } +/// Resource limits related to the reduction samplers. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct SamplerReductionProperties { + /// Support for the minimum set of required formats support min/max filtering + pub single_component_formats: bool, + /// Support for the non-identity component mapping of the image when doing min/max filtering. + pub image_component_mapping: bool, +} + /// Propterties to indicate when the backend does not support full vulkan compliance. #[derive(Clone, Copy, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/third_party/rust/gfx-hal/src/pso/graphics.rs b/third_party/rust/gfx-hal/src/pso/graphics.rs index 5905f14f1d41..6e51242d9840 100644 --- a/third_party/rust/gfx-hal/src/pso/graphics.rs +++ b/third_party/rust/gfx-hal/src/pso/graphics.rs @@ -61,7 +61,7 @@ pub struct BakedStates { /// Static scissor. TODO: multiple scissors pub scissor: Option, /// Static blend constant color. - pub blend_color: Option, + pub blend_constants: Option, /// Static depth bounds. pub depth_bounds: Option>, } diff --git a/third_party/rust/gfx-hal/src/pso/specialization.rs b/third_party/rust/gfx-hal/src/pso/specialization.rs index d4c15c3d2521..2b6191dad7b5 100644 --- a/third_party/rust/gfx-hal/src/pso/specialization.rs +++ b/third_party/rust/gfx-hal/src/pso/specialization.rs @@ -92,7 +92,7 @@ where { fn fold(self, storage: &mut SpecializationStorage) { let size = std::mem::size_of::(); - assert!(storage.data.len() + size <= u16::max_value() as usize); + assert!(storage.data.len() + size <= u16::MAX as usize); let offset = storage.data.len() as u16; storage.data.extend_from_slice(unsafe { // Inspecting bytes is always safe. diff --git a/third_party/rust/gfx-hal/src/window.rs b/third_party/rust/gfx-hal/src/window.rs index f15504aafba1..7ea24a717463 100644 --- a/third_party/rust/gfx-hal/src/window.rs +++ b/third_party/rust/gfx-hal/src/window.rs @@ -89,6 +89,9 @@ pub enum SwapchainError { /// Window in use #[error("Window is in use")] WindowInUse, + /// Unknown error. + #[error("Swapchain can't be created for an unlknown reason")] + Unknown, } /// An extent describes the size of a rectangle, such as diff --git a/third_party/rust/glslopt/glsl-optimizer/generateParsers.sh b/third_party/rust/glslopt/glsl-optimizer/generateParsers.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/image/release.sh b/third_party/rust/image/release.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus-ast/generate_ast.py b/third_party/rust/jsparagus-ast/generate_ast.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/.githooks/pre-commit b/third_party/rust/jsparagus/.githooks/pre-commit old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/.metrics/create-ci-branch.sh b/third_party/rust/jsparagus/.metrics/create-ci-branch.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/.metrics/populate_fuzzbug.sh b/third_party/rust/jsparagus/.metrics/populate_fuzzbug.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/.metrics/populate_not_implemented.sh b/third_party/rust/jsparagus/.metrics/populate_not_implemented.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/js_parser/extract_es_grammar.py b/third_party/rust/jsparagus/js_parser/extract_es_grammar.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/js_parser/generate_js_parser_tables.py b/third_party/rust/jsparagus/js_parser/generate_js_parser_tables.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/js_parser/try_it.py b/third_party/rust/jsparagus/js_parser/try_it.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/jsparagus/gen.py b/third_party/rust/jsparagus/jsparagus/gen.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/jsparagus/main.py b/third_party/rust/jsparagus/jsparagus/main.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/jsparagus/parse_pgen.py b/third_party/rust/jsparagus/jsparagus/parse_pgen.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/test.sh b/third_party/rust/jsparagus/test.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/tests/test.py b/third_party/rust/jsparagus/tests/test.py old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/update.sh b/third_party/rust/jsparagus/update.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/jsparagus/update_stencil.py b/third_party/rust/jsparagus/update_stencil.py old mode 100644 new mode 100755 diff --git a/third_party/rust/leb128/benches/bench.rs b/third_party/rust/leb128/benches/bench.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/leb128/format b/third_party/rust/leb128/format old mode 100644 new mode 100755 diff --git a/third_party/rust/libc/src/vxworks/mod.rs b/third_party/rust/libc/src/vxworks/mod.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/libsqlite3-sys/upgrade.sh b/third_party/rust/libsqlite3-sys/upgrade.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/mach/ci/build_fail.sh b/third_party/rust/mach/ci/build_fail.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/mach/ci/run.sh b/third_party/rust/mach/ci/run.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/metal/.cargo-checksum.json b/third_party/rust/metal/.cargo-checksum.json index 3bd82f86bb5a..ef1eecce9e17 100644 --- a/third_party/rust/metal/.cargo-checksum.json +++ b/third_party/rust/metal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".github/workflows/ci.yml":"08d24906a6e23f870040b1dff654a89ca915b28973c1d7f10503fd3c1d326ce6","Cargo.toml":"f8e7c6dea292e461348bbdca1ce73b66a778864884e2bda48455ec90a26ce05b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","Makefile":"6fddc61a94f5b31a65b11c1bef8b19c92bff738716998076c5d49c2834223c75","README.md":"6817e12da257b43352f71f595dcc713adf117c734ebf656e6af2d7d04be27cd6","bors.toml":"c2733ec512a08bf76b6a1ed77270810a0edeb888ba24c2a75679e1eb1bd563a5","examples/argument-buffer/main.rs":"4c1d1d9949bc56628980f84077dafdfa68a853141d6d4dc3e6202f6c61ba11f7","examples/bind/main.rs":"a0c85aad05f08666f9b380a7146a8473a6a6fe0db5d523760373093a0af20e5f","examples/caps/main.rs":"145f5efc728232061d12f09ab954f738b6870921ee3f07744ee1450111c98ed8","examples/circle/README.md":"e1c97cf5252f0d1f2934ace78b5d839c5f45911f3007dbd2925eeceefb8f0af6","examples/circle/main.rs":"edf84bf14e8423080f25590a5fe39eca3e8b40a26b43328196570c8372ba9b30","examples/circle/screenshot.png":"97bf07c85bf02367447b9c8a81707c124e4a3b420fa386b95ba08b21938f4f2a","examples/circle/shaders.metal":"5e4f40efca5bb386204a09e1b983cc6c634fdf1ca9dd4974227313adbf50e8b5","examples/circle/shaders.metallib":"666a9491d795ef9c0b9c122c7ada571cc2c0e8774d2d89e5b4b996f3dc47962b","examples/compute/compute-argument-buffer.metal":"6530bbd6a0101d9db2893805436f5dc877959e81ea97a27014c0fc52fc9fa77b","examples/compute/compute-argument-buffer.rs":"e3de61fd7cc2f14d9d52300e4878601dbc072bc26d9dafc66115df58f94e0470","examples/compute/embedded-lib.rs":"55f701810fa5270c27ca771e713f9f8cf09e124a997b0b03790b38435593a7ea","examples/compute/main.rs":"f16cbf57cd27dc948ff651251ce26e6bd616cb5d989b8dadb4256c73a9bfba4b","examples/compute/shaders.metal":"f2b15551bb5247b88a3029c3d8ef37c6fa04a4a6cca9f90f069894ed6822b4bf","examples/compute/shaders.metallib":"fef91643e60c0ec99ad2bd2f3916299bcc3e6a80038ea27bed59681badfea7d1","examples/events/main.rs":"4a92d1e1f4be2975e6458736cc59e60c174f7f966aa962e27ff3c1a18c3b2329","examples/fence/main.rs":"47741327e62db1d8bd344b6a9ec26ef13ffb0b56b0dd7077c5d926d43faaeff7","examples/headless-render/.gitignore":"99520a5b5abaf30fc75759f1fd9f4338b6fbd1fc49f2dcbb466b22e6f9db4f62","examples/headless-render/README.md":"b1c97b52701cfb41fc0b9e269ba7a7a454d9161746198e2f5789f2636f60842d","examples/headless-render/main.rs":"cf0180839e8d09d4bf403ae947365ac18fa17782172986311bfa04b84f88169e","examples/headless-render/screenshot.png":"01d6ea5791b63b0f01190198756446cf313fc25dc64d0138c1b4f62c9f862dd1","examples/library/main.rs":"a1420ec28a471f28a789b75b3ecf5abb699ed352b337747169914812fb98045a","examples/mps/main.rs":"51f34582bf118f171bbb81d22c11407c7a35f381dbbff2d75c6f8e90d22a2aa1","examples/mps/shaders.metal":"155922d6a4184078ae7ee29504a268e1218f07d908f921eef60e5bfa8a793bda","examples/mps/shaders.metallib":"b62451223549b1e7eb90ec3d3534c0ed4cdfdc581c7df3ffcdc4786a5fcacde4","examples/reflection/main.rs":"fa0ade08750e14c8fded19c2b57e3fc1252f4fc0292890aea1d46968a647b600","examples/shader-dylib/main.rs":"c4ba734e1ff5325a4053d032a3ff69c41b4189db24c19c6de8a1ec92465a0720","examples/shader-dylib/test_dylib.metal":"3469de785c2c0da784e84758fc0da5a81e474ca15588485d9e04398690641cc8","examples/shader-dylib/test_shader.metal":"1a04ff8ab3288b09d14cd35440b2557e92ddedbff9d07c4144a22e9062e6e1e4","examples/window/README.md":"69655cff298e07887fe70e8a13e27d8a87efcd0cc0da4e15485134e064e1aceb","examples/window/main.rs":"57b956895ec339214d2cd9350c9ca9659e07062b86ba4279f60749a8bcc18f35","examples/window/screenshot.png":"da7369d7cc297c7f7f6bd773c93e7d708d72442c9c5ff5a20c2f2ee6852552dc","examples/window/shaders.metal":"90dee6c752add5c617dfdca93064b2824b44ff8c01ef63986826f6a1531e95d6","examples/window/shaders.metallib":"16fa82beb70bf16c3501970cae0d5028a747a08164337161dc9c2e8965d4c366","src/argument.rs":"cbea626cb84b60bc1c3c033eb7c56cacb1c31fd4233307ce851e7c6a49b17271","src/buffer.rs":"80c55c8703340bf0d4d1b5eface518fdf82355ccb897883639cbf7e4933a4344","src/capturedescriptor.rs":"7d90b1e7b87fa9da1e38bba9637cd8d7a18a81f8c3f408149058ed4ea20a6894","src/capturemanager.rs":"bdee9e170da371778452513a9ac363a738ea8bfd3f0870d86c6013459c5af010","src/commandbuffer.rs":"0123224dcc0552748f1c2c87385f1f6be2863887f8862fbfd8b3a1562d9f69ba","src/commandqueue.rs":"5b87621ae4495ae04a5de5ce980d0cde31b4bb0d1e31e932d34c49252240c9d9","src/constants.rs":"7be4d901da863f126d158d1042f5482a122fbcf760f7c225b0b1693a55f6bb4b","src/depthstencil.rs":"5bfa4f49940fdc9d12b2af08f7fe710c41f0b7e26bdb6f8709fe17b9a9d7d5eb","src/device.rs":"37da14ec4bb531b9722e4cf775497f86ab11b1f0492a070f63ef87a49c83feeb","src/drawable.rs":"03a8adb20da93839314586f0ec12bce139ece546a07e2f9ed60c89303fa52a82","src/encoder.rs":"2b168327b5d798698ca2eea5ad92360d53081924910cd480ce0d9cb24be134b3","src/heap.rs":"2470f9e71ba994ae1bd008c41b18c461dbe94fbb2353d7639f9db5696dfb44e3","src/indirect_encoder.rs":"b3e3fe78e69fc97431c82e42c925cc1751953c43c7f7706fd77ca649b610800d","src/lib.rs":"f6fa8ed3db79bfc296c8e4c99e1cb7fae0fb400927b3ea0a821b992700491bac","src/library.rs":"8e05f9be0763ec7468365a90e5abd92681c9a029bb213dbe946728d4c3093d13","src/mps.rs":"b415be3221754d836fd535f4b5b45ed484d4cc926bd26145e82a9e61d337da4c","src/pipeline/compute.rs":"f14a4a77d73df11121244970c1d2f20928da8cba617bded774aab25e2d903ece","src/pipeline/mod.rs":"5ec3cb524cc03202a3394dad5a7d0b733474f664935353253e76a49aed5513ad","src/pipeline/render.rs":"0374d5720c801b0eaa9e999391af06f641a8f71f99dfabf1efea77defe19ebfc","src/renderpass.rs":"163f119c4ae196663336c3327f827623e7e4e5ac16c43e8b2eed0317929521f0","src/resource.rs":"c0d21eb409fa3eb796be1f71a542717f6079e35c4d730dceee96e8496517ff8f","src/sampler.rs":"3c3b2f8a5f7c6f817e9153ff63223512bbfcf7037fc76741f81ac46a3ddc1431","src/sync.rs":"2accf8760b19134f100533b91db1bfc56778afa5375a06fe7a7985624f00a836","src/texture.rs":"7b6e134957053fcaf085411adfad041dec74b60902b6a7cb01351430c0b65c88","src/types.rs":"a14c7148eeebe3eb5f7e90b1add7a2109825a52b115d2aa57fd999eb67b70f08","src/vertexdescriptor.rs":"b36244b752406769dd0930a607b8f5b9c191b9045e973dd2cce6d85443f318ca"},"package":null} \ No newline at end of file +{"files":{".github/workflows/ci.yml":"08d24906a6e23f870040b1dff654a89ca915b28973c1d7f10503fd3c1d326ce6","Cargo.toml":"f8e7c6dea292e461348bbdca1ce73b66a778864884e2bda48455ec90a26ce05b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","Makefile":"6fddc61a94f5b31a65b11c1bef8b19c92bff738716998076c5d49c2834223c75","README.md":"6817e12da257b43352f71f595dcc713adf117c734ebf656e6af2d7d04be27cd6","bors.toml":"c2733ec512a08bf76b6a1ed77270810a0edeb888ba24c2a75679e1eb1bd563a5","examples/argument-buffer/main.rs":"4c1d1d9949bc56628980f84077dafdfa68a853141d6d4dc3e6202f6c61ba11f7","examples/bind/main.rs":"a0c85aad05f08666f9b380a7146a8473a6a6fe0db5d523760373093a0af20e5f","examples/caps/main.rs":"20d441b939dcd01e71e8c7686fcd2dd203dde1816603192ea8f65796b9984b5d","examples/circle/README.md":"e1c97cf5252f0d1f2934ace78b5d839c5f45911f3007dbd2925eeceefb8f0af6","examples/circle/main.rs":"e3a9ade6357307b48ef3a8072699cf26f9658495945b7b9de8904a691826b80a","examples/circle/screenshot.png":"97bf07c85bf02367447b9c8a81707c124e4a3b420fa386b95ba08b21938f4f2a","examples/circle/shaders.metal":"5e4f40efca5bb386204a09e1b983cc6c634fdf1ca9dd4974227313adbf50e8b5","examples/circle/shaders.metallib":"666a9491d795ef9c0b9c122c7ada571cc2c0e8774d2d89e5b4b996f3dc47962b","examples/compute/compute-argument-buffer.metal":"6530bbd6a0101d9db2893805436f5dc877959e81ea97a27014c0fc52fc9fa77b","examples/compute/compute-argument-buffer.rs":"e3de61fd7cc2f14d9d52300e4878601dbc072bc26d9dafc66115df58f94e0470","examples/compute/embedded-lib.rs":"55f701810fa5270c27ca771e713f9f8cf09e124a997b0b03790b38435593a7ea","examples/compute/main.rs":"f16cbf57cd27dc948ff651251ce26e6bd616cb5d989b8dadb4256c73a9bfba4b","examples/compute/shaders.metal":"f2b15551bb5247b88a3029c3d8ef37c6fa04a4a6cca9f90f069894ed6822b4bf","examples/compute/shaders.metallib":"fef91643e60c0ec99ad2bd2f3916299bcc3e6a80038ea27bed59681badfea7d1","examples/events/main.rs":"4a92d1e1f4be2975e6458736cc59e60c174f7f966aa962e27ff3c1a18c3b2329","examples/fence/main.rs":"47741327e62db1d8bd344b6a9ec26ef13ffb0b56b0dd7077c5d926d43faaeff7","examples/headless-render/.gitignore":"99520a5b5abaf30fc75759f1fd9f4338b6fbd1fc49f2dcbb466b22e6f9db4f62","examples/headless-render/README.md":"b1c97b52701cfb41fc0b9e269ba7a7a454d9161746198e2f5789f2636f60842d","examples/headless-render/main.rs":"cf0180839e8d09d4bf403ae947365ac18fa17782172986311bfa04b84f88169e","examples/headless-render/screenshot.png":"01d6ea5791b63b0f01190198756446cf313fc25dc64d0138c1b4f62c9f862dd1","examples/library/main.rs":"a1420ec28a471f28a789b75b3ecf5abb699ed352b337747169914812fb98045a","examples/mps/main.rs":"51f34582bf118f171bbb81d22c11407c7a35f381dbbff2d75c6f8e90d22a2aa1","examples/mps/shaders.metal":"155922d6a4184078ae7ee29504a268e1218f07d908f921eef60e5bfa8a793bda","examples/mps/shaders.metallib":"b62451223549b1e7eb90ec3d3534c0ed4cdfdc581c7df3ffcdc4786a5fcacde4","examples/reflection/main.rs":"fa0ade08750e14c8fded19c2b57e3fc1252f4fc0292890aea1d46968a647b600","examples/shader-dylib/main.rs":"c4ba734e1ff5325a4053d032a3ff69c41b4189db24c19c6de8a1ec92465a0720","examples/shader-dylib/test_dylib.metal":"3469de785c2c0da784e84758fc0da5a81e474ca15588485d9e04398690641cc8","examples/shader-dylib/test_shader.metal":"1a04ff8ab3288b09d14cd35440b2557e92ddedbff9d07c4144a22e9062e6e1e4","examples/window/README.md":"69655cff298e07887fe70e8a13e27d8a87efcd0cc0da4e15485134e064e1aceb","examples/window/main.rs":"57b956895ec339214d2cd9350c9ca9659e07062b86ba4279f60749a8bcc18f35","examples/window/screenshot.png":"da7369d7cc297c7f7f6bd773c93e7d708d72442c9c5ff5a20c2f2ee6852552dc","examples/window/shaders.metal":"90dee6c752add5c617dfdca93064b2824b44ff8c01ef63986826f6a1531e95d6","examples/window/shaders.metallib":"16fa82beb70bf16c3501970cae0d5028a747a08164337161dc9c2e8965d4c366","src/argument.rs":"cbea626cb84b60bc1c3c033eb7c56cacb1c31fd4233307ce851e7c6a49b17271","src/buffer.rs":"80c55c8703340bf0d4d1b5eface518fdf82355ccb897883639cbf7e4933a4344","src/capturedescriptor.rs":"7d90b1e7b87fa9da1e38bba9637cd8d7a18a81f8c3f408149058ed4ea20a6894","src/capturemanager.rs":"bdee9e170da371778452513a9ac363a738ea8bfd3f0870d86c6013459c5af010","src/commandbuffer.rs":"0123224dcc0552748f1c2c87385f1f6be2863887f8862fbfd8b3a1562d9f69ba","src/commandqueue.rs":"5b87621ae4495ae04a5de5ce980d0cde31b4bb0d1e31e932d34c49252240c9d9","src/constants.rs":"7be4d901da863f126d158d1042f5482a122fbcf760f7c225b0b1693a55f6bb4b","src/depthstencil.rs":"5bfa4f49940fdc9d12b2af08f7fe710c41f0b7e26bdb6f8709fe17b9a9d7d5eb","src/device.rs":"8a9fae53b1906c0eee38657822130bee37ab8652f6ae38987d78fe3f3a142cd0","src/drawable.rs":"191ed7d3e370544df49e861119d7d1681c2aadfdea105a3f4db2721cad643e33","src/encoder.rs":"2b168327b5d798698ca2eea5ad92360d53081924910cd480ce0d9cb24be134b3","src/heap.rs":"2470f9e71ba994ae1bd008c41b18c461dbe94fbb2353d7639f9db5696dfb44e3","src/indirect_encoder.rs":"b3e3fe78e69fc97431c82e42c925cc1751953c43c7f7706fd77ca649b610800d","src/lib.rs":"f6fa8ed3db79bfc296c8e4c99e1cb7fae0fb400927b3ea0a821b992700491bac","src/library.rs":"8e05f9be0763ec7468365a90e5abd92681c9a029bb213dbe946728d4c3093d13","src/mps.rs":"b415be3221754d836fd535f4b5b45ed484d4cc926bd26145e82a9e61d337da4c","src/pipeline/compute.rs":"a1d71d809e8296f037b1fd7e1cdd0ee5821fe9f119a0b8b754edf377bb1ed7f3","src/pipeline/mod.rs":"5ec3cb524cc03202a3394dad5a7d0b733474f664935353253e76a49aed5513ad","src/pipeline/render.rs":"cd9cbb491fcc558a2a2a37f83c5b087dcf66bff1a1f2ae8ce6a95de59b385a69","src/renderpass.rs":"163f119c4ae196663336c3327f827623e7e4e5ac16c43e8b2eed0317929521f0","src/resource.rs":"c0d21eb409fa3eb796be1f71a542717f6079e35c4d730dceee96e8496517ff8f","src/sampler.rs":"3c3b2f8a5f7c6f817e9153ff63223512bbfcf7037fc76741f81ac46a3ddc1431","src/sync.rs":"2accf8760b19134f100533b91db1bfc56778afa5375a06fe7a7985624f00a836","src/texture.rs":"7b6e134957053fcaf085411adfad041dec74b60902b6a7cb01351430c0b65c88","src/types.rs":"a14c7148eeebe3eb5f7e90b1add7a2109825a52b115d2aa57fd999eb67b70f08","src/vertexdescriptor.rs":"b36244b752406769dd0930a607b8f5b9c191b9045e973dd2cce6d85443f318ca"},"package":null} \ No newline at end of file diff --git a/third_party/rust/metal/examples/caps/main.rs b/third_party/rust/metal/examples/caps/main.rs index 76030954efc5..9420938459ca 100644 --- a/third_party/rust/metal/examples/caps/main.rs +++ b/third_party/rust/metal/examples/caps/main.rs @@ -25,6 +25,7 @@ fn main() { 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() diff --git a/third_party/rust/metal/examples/circle/main.rs b/third_party/rust/metal/examples/circle/main.rs index 0190eedf6b0c..528d4761eebc 100644 --- a/third_party/rust/metal/examples/circle/main.rs +++ b/third_party/rust/metal/examples/circle/main.rs @@ -46,6 +46,22 @@ fn main() { let device = Device::system_default().expect("no device found"); println!("Your device is: {}", device.name(),); + 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"); @@ -53,7 +69,12 @@ fn main() { 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); + 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(); @@ -199,7 +220,11 @@ fn prepare_render_pass_descriptor(descriptor: &RenderPassDescriptorRef, texture: color_attachment.set_store_action(MTLStoreAction::Store); } -fn prepare_pipeline_state(device: &Device, library: &Library) -> RenderPipelineState { +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(); @@ -211,6 +236,13 @@ fn prepare_pipeline_state(device: &Device, library: &Library) -> RenderPipelineS .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) diff --git a/third_party/rust/metal/src/device.rs b/third_party/rust/metal/src/device.rs index 0c2b3d475fa5..7dc85b9f2728 100644 --- a/third_party/rust/metal/src/device.rs +++ b/third_party/rust/metal/src/device.rs @@ -537,6 +537,14 @@ impl MTLFeatureSet { } } + pub fn supports_binary_archive(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 3, + OS::macOS => self.gpu_family() >= 1, + } + } + pub fn max_vertex_attributes(&self) -> u32 { 31 } @@ -1799,10 +1807,10 @@ impl DeviceRef { pub fn new_binary_archive_with_descriptor( &self, descriptor: &BinaryArchiveDescriptorRef, - ) -> Result<(), String> { + ) -> Result { unsafe { let mut err: *mut Object = ptr::null_mut(); - let _r: () = msg_send![self, newBinaryArchiveWithDescriptor:descriptor + let binary_archive: *mut MTLBinaryArchive = msg_send![self, newBinaryArchiveWithDescriptor:descriptor error:&mut err]; if !err.is_null() { // TODO: copy pasta @@ -1811,7 +1819,7 @@ impl DeviceRef { let message = CStr::from_ptr(c_msg).to_string_lossy().into_owned(); Err(message) } else { - Ok(()) + Ok(BinaryArchive::from_ptr(binary_archive)) } } } @@ -1836,6 +1844,27 @@ impl DeviceRef { } } + /// Useful for debugging binary archives. + pub fn new_render_pipeline_state_with_fail_on_binary_archive_miss( + &self, + descriptor: &RenderPipelineDescriptorRef, + ) -> Result { + unsafe { + let pipeline_options = MTLPipelineOption::FailOnBinaryArchiveMiss; + + let reflection: *mut MTLRenderPipelineReflection = std::ptr::null_mut(); + + let pipeline_state: *mut MTLRenderPipelineState = try_objc! { err => + msg_send![self, newRenderPipelineStateWithDescriptor:descriptor + options:pipeline_options + reflection:reflection + error:&mut err] + }; + + Ok(RenderPipelineState::from_ptr(pipeline_state)) + } + } + pub fn new_render_pipeline_state( &self, descriptor: &RenderPipelineDescriptorRef, @@ -2041,4 +2070,9 @@ impl DeviceRef { pub fn current_allocated_size(&self) -> NSUInteger { unsafe { msg_send![self, currentAllocatedSize] } } + + /// Only available on (macos(10.14), ios(12.0), tvos(12.0)) + pub fn max_buffer_length(&self) -> NSUInteger { + unsafe { msg_send![self, maxBufferLength] } + } } diff --git a/third_party/rust/metal/src/drawable.rs b/third_party/rust/metal/src/drawable.rs index 0e6d8377c495..d119b0afd420 100644 --- a/third_party/rust/metal/src/drawable.rs +++ b/third_party/rust/metal/src/drawable.rs @@ -5,6 +5,8 @@ // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms. +use cocoa_foundation::foundation::NSUInteger; + pub enum MTLDrawable {} foreign_obj_type! { @@ -17,4 +19,8 @@ impl DrawableRef { pub fn present(&self) { unsafe { msg_send![self, present] } } + + pub fn drawable_id(&self) -> NSUInteger { + unsafe { msg_send![self, drawableID] } + } } diff --git a/third_party/rust/metal/src/pipeline/compute.rs b/third_party/rust/metal/src/pipeline/compute.rs index 05735b225a33..744eca388144 100644 --- a/third_party/rust/metal/src/pipeline/compute.rs +++ b/third_party/rust/metal/src/pipeline/compute.rs @@ -235,6 +235,7 @@ impl ComputePipelineDescriptorRef { } } + /// API_AVAILABLE(macos(11.0), ios(14.0)); /// Marshal from Rust slice pub fn set_binary_archives(&self, archives: &[&BinaryArchiveRef]) { let ns_array = Array::::from_slice(archives); diff --git a/third_party/rust/metal/src/pipeline/render.rs b/third_party/rust/metal/src/pipeline/render.rs index ae4f0d542152..dc59d70ecc3e 100644 --- a/third_party/rust/metal/src/pipeline/render.rs +++ b/third_party/rust/metal/src/pipeline/render.rs @@ -393,8 +393,28 @@ impl RenderPipelineDescriptorRef { // TODO: tesselation stuff - // TODO: binaryArchives - // @property (readwrite, nullable, nonatomic, copy) NSArray> *binaryArchives API_AVAILABLE(macos(11.0), ios(14.0)); + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal to Rust Vec + pub fn binary_archives(&self) -> Vec { + 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::::from_slice(archives); + unsafe { msg_send![self, setBinaryArchives: ns_array] } + } pub fn reset(&self) { unsafe { msg_send![self, reset] } diff --git a/third_party/rust/miniz_oxide/build.rs b/third_party/rust/miniz_oxide/build.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/naga/.cargo-checksum.json b/third_party/rust/naga/.cargo-checksum.json index d83375519e46..f918cd47410f 100644 --- a/third_party/rust/naga/.cargo-checksum.json +++ b/third_party/rust/naga/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".github/workflows/pipeline.yml":"376d5f06b093c8fffc08c1c47d6598882b9199a7bf15fc2777cd955abb65a9b1",".github/workflows/validation-linux.yml":"f9d251585b7c8b4a46057493b3ddb713843154f783f8946d9c2e3e0a8d7f6feb",".github/workflows/validation-macos.yml":"6c809b31f200c5e5d1091d1efda041c42461c9cd1fc748fe7490e302d187d613",".monocodus":"9be77868b35e2af7e3da0e95f7b3282ca573cd19cbec20c6a6a30435ce6d58c2","CHANGELOG.md":"d4bd3d367873f19de91a964174e4ef5a890c1a4abe17d6b06cea337c85c9c87f","Cargo.toml":"bc40fb23f6b85064631a6a906e623d31e737025a321a22f358b7019cfe912ad7","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"ca3be8518f5ef097669cea882643fc532025f29972def4fda49df885565a0480","Makefile":"8e0c3aba5a722a92f8e817076613d20bae54b1fb427e94591158d5410bc9ef6c","README.md":"b2f433c4f9558dc4ab310979dc99f20c14c72641f161e9547f0ae383f7f10369","bin/convert.rs":"53b2378df6696e7e94875a4a37be241a4a12f86a7c3448055d624449ef506f36","src/arena.rs":"8d9b1b3a6164ffccc8be42c2f59bf91df688a7096064b216c1355498ef7378ff","src/back/dot/mod.rs":"e693960c83073ac01cc0eff00dfb81e3ae6362db1c86d844fabbed7986e37d24","src/back/glsl/features.rs":"a0b79fce5ef83a4738462abf3ec9bfcbc1f8e8579395705fd4d3df772cbce8d9","src/back/glsl/keywords.rs":"3f23b1e63e99a7056c3b223524d5d37000ef7316ae9df25532a726a1157d1dcd","src/back/glsl/mod.rs":"46eb12deb962ed52918cff4a8742c8c827ec77ebf67041754577f7a2cb17bd44","src/back/mod.rs":"23cb0d25a5f55257707f86d15e56ecf1f924a01f4bad54cf1516a359932a63f4","src/back/msl/keywords.rs":"bd655a55e551a994632af87813dde0b0ac50589c081fd00b7f15ff2736f7f132","src/back/msl/mod.rs":"3f52b7be669a2a72ad508b28c400912dd49f5f53d8af4d4d0bba0fbbf3862162","src/back/msl/writer.rs":"9c355f59e9522fec386a2f689858c95e826b70eaf12defed8a5fe8b583895075","src/back/spv/helpers.rs":"57f4c90373ef6433adecc366d874708db83f8ae187fb817af6c7ddaac73064d3","src/back/spv/instructions.rs":"542aca5fc4e42dea09cd76cdd1f65c558c786df2dcb77c2dba2c93c4c3f0678a","src/back/spv/layout.rs":"173ec4d496ab53becdd6a223073d142e2a4b2a25d297b9f9f67059777613b5c2","src/back/spv/mod.rs":"f25c312d63a978b9278ff15348a241adee15049a70c5c4914032873648940378","src/back/spv/writer.rs":"fb4665d4d078838b0a34a0bfda65f86e24ebc350ba42898383e1bb02cc9c0fef","src/front/glsl/ast.rs":"9e2f85e898ac9990eef6a9dfd279b39274d1cc1f9202c3a3c1d3a4e336e83ab9","src/front/glsl/constants.rs":"a7704c8c294535e9fda2d92f7782a8dbc9650dc4f9fadc0561817fb9e275a265","src/front/glsl/error.rs":"98d99a2129b73372d64ca04d9a8967e93b32278772d4bbcbc9412364fea4bf80","src/front/glsl/functions.rs":"5398b7456460c7c424b9aaae02822226950c741a67de0b9e0166800642c91b98","src/front/glsl/lex.rs":"40442c6b3dc6e94997a75ec6eb3d5c7bcfcb0c92fdf51834dd8815a9850e94a1","src/front/glsl/mod.rs":"db3c834565b42e68631c2d07db91122d78b8e35c2db9ca751f03f68e981e48eb","src/front/glsl/parser.rs":"094580a677fc6cfcfa163f4e4289da02317c2e9fa5161fd5d75868f1730be2f0","src/front/glsl/parser_tests.rs":"619056f38390b2964baaafa17e2652239cbd45f1395a42926ac237d927d316aa","src/front/glsl/token.rs":"8c8d311d43a9991ae71e1eddc2e9a54435cd3fa853819ab15349bfcbd81afe1c","src/front/glsl/types.rs":"15bffe9885a952db4c9bd1ab6b4b300147289e36f4e8a1dd2e473733187630e8","src/front/glsl/variables.rs":"64b448567df0bd4e12f3bb14275462c9e3b3db9c87134c537c7568efea64ab69","src/front/mod.rs":"6e5fbaaed1d7e3f98e2f757361b6804190ed6a874d3b1e998dad7b2891f712c8","src/front/spv/convert.rs":"19b462a27e62f1e35d8ecf4235556c407cf173b8692f8eba0f31affa6eb477e1","src/front/spv/error.rs":"131164fba8999e9261568db5568710d5ed8973c530885e7a00bf996867db22e9","src/front/spv/flow.rs":"0809c64c537f4959f9c781806efd16f2eff7c8aad10e57f19b81d9a14fffd5d1","src/front/spv/function.rs":"d0a940caaf4055658c43bc9f5c8afb62cbe66322ae75baaf5b8feee876f61ef2","src/front/spv/image.rs":"e5fdd4ce744edce800694733e35746bb1b027345f1a9f207935d35ca88617aa7","src/front/spv/mod.rs":"a2853fc95c52d5da57a86c7e83a9f62c933e705c28ec75f851bb422869a5afa8","src/front/wgsl/conv.rs":"aba5a548805fd54f979f020884c9af8168cab0790933965f3935587688988086","src/front/wgsl/lexer.rs":"3e712cacfc6cb5ae69119e4ff6591f544ba39295b87d9b56c4cd69d89623e270","src/front/wgsl/mod.rs":"ba858030bc61bd18aedda0d36ee03ea7074779ab29cfbf7231eb2f7aef599eba","src/front/wgsl/tests.rs":"f1f67f238eb1dc04af3a487cda2a382dd08bbc4301d0b98c93742d97d44aaa25","src/lib.rs":"b9c83d9e89f9b4985dd4d4a5b565406a0fb8bc348377adbe0f19b82d449c974d","src/proc/layouter.rs":"d26942bae8a51c4047eed4b3469fb947b58ad8b0a7575f5ae231d6241b8f150d","src/proc/mod.rs":"eef6bab9edac314d1b578647178c38caaa821e9cd1977a05cf5793fc4b94114f","src/proc/namer.rs":"78489925e43476cc16fd0aae9ef0692a8535def69e3690edfee6d1a9cb2924d9","src/proc/terminator.rs":"1ee66bc82cc478156073fcdfc53e281c8bc85bbe3ac1e79ca1613fb50619e7c2","src/proc/typifier.rs":"235ef0a41d17759d828060bcbf25c44103f866fdd9edc840cbdad99d18c13605","src/valid/analyzer.rs":"549f97bba84e19e4e472ba0173824afa8e2d8bddd621016a4777b83e35171c53","src/valid/expression.rs":"bae9e64e77aeda4befa4af3fd2a774b5ca5ebf33c13403b3792fe7599ab0a85a","src/valid/function.rs":"23e928a3f7af4424ff711f70685e12a4e384c714f80616106e766f28c5d8eb73","src/valid/interface.rs":"6744427d40e7723a016eadce05977720e013d69cda760dc8b675f77fea16bc14","src/valid/mod.rs":"4b7b634c71212437088fb8fcdeb433d20dd9ad869d73c9ac4c8c5a009b00976c","src/valid/type.rs":"8a3cc9a12ec2f6e4444bf2a88b7494de3dd4310b86c68bb1eb541641ed0d1b87","tests/cases/glsl_constant_expression.vert":"89e1ec69f019ea1c91db65ea1509c81a32841b55bc812a4f14caacd9123351eb","tests/cases/glsl_if_preprocessor.vert":"3b7f98c2592f2d4f17dc55896e31b5896111b0f5546e4abbb3abadfeffadfec8","tests/cases/glsl_phong_lighting.frag":"97fe2c7a9ba918256469c8a8810b300664655ee78c62ee50ca5165df6ce50eb1","tests/cases/glsl_preprocessor_abuse.vert":"86ed48d088256d3095a3dfb20d4d3f719b7dbc370c046399bf3147e5847d407a","tests/cases/glsl_vertex_test_shader.vert":"fdd38521bdef9f6edd437f4530af06bd2b9770cb6c9cee35d0f9fb24135590fd","tests/errors.rs":"5944a155281fb6125d419d8d58c2317cf968318384c9005948806f8c37ad41d3","tests/in/boids.param.ron":"5e72be50f5e1603bf986f9628991028020db054f08188a4fbc812c4efd109254","tests/in/boids.wgsl":"10cad2c6ffccb6e879144efa6772b245defdee159a280f90dc2ee7e7d4f291a2","tests/in/collatz.param.ron":"9f521a9bd899744f8ce217bce32fa4f250213f75b309b2a254783c1abbb4972e","tests/in/collatz.wgsl":"34e740dbf4bdbda2c4d20ea1984d2dfa263ad7b09823ebb857a6a3d85af5e1bb","tests/in/empty.param.ron":"0a853f8b63cc4e55b80d139d43e85de22d543e19b1e68c13345224b4f05c4211","tests/in/empty.wgsl":"626dc2c8b00c02b40cf74a87154511068a46fa586c8780765bb506fab5f60c6c","tests/in/image-copy.param.ron":"908d41f4bca92484b1ddff731d89d234a87150833e517371b4cb1dbe5decb97e","tests/in/image-copy.wgsl":"c9ad36837936b9cd81a6cc90678431c19d10a2be53bd821f84fc5250e3fe0dbd","tests/in/quad-glsl.glsl":"ef2f105c06b15406353b604b686c1e707fa8a49b66985b4e616d59591be4cbff","tests/in/quad-glsl.param.ron":"89edcf48c7d25be087c8fbe407d218e24b086001d34939e237c28dd36967bcb7","tests/in/quad-vert.spv":"c194227c35a6b69613c577b5548713ebb058fc9ffbc2d04de4fe673f07b8cb30","tests/in/quad.param.ron":"b8150a5769ad15a4588cc965f1ee5bcaf33d39877dedd58ad97d43db9c069c29","tests/in/quad.wgsl":"88fe100e9f3f735a0b22cda95299c7cd1ecff82122a76bc7d72877c94de7b11b","tests/in/shadow.param.ron":"cf13aabc48c33c79ac7baadd301e0bcb406e3be854708693dc15369c9f2abcdd","tests/in/shadow.spv":"5a239809a04e7f8937330296394899e423ee86578c692e3581baaadbe36194d5","tests/in/shadow.wgsl":"859a8e88c9fff41771d93db3fad13b058eeae1e8ae4bff18de6000fc970b9946","tests/in/skybox.param.ron":"191d5834c5dfddea86679cdb3fe8dbc26a57ff1797fec8fba53cdbd16cd5eae1","tests/in/skybox.wgsl":"4a337429a3ac9c998e5ce698441ae693cc33bdf0dd75b0c3aae7f134fde6f6f5","tests/in/texture-array.param.ron":"56f9feb06257ef396803d7dc70a0b7591beb4ea7fc90486d5055e68cb6214201","tests/in/texture-array.wgsl":"1aa82179c75e12f14869f4412195cf2c3fdd4c989daac911a9142603b36ce67f","tests/out/boids.msl.snap":"766229f410d290d97bb37890157ef87ac443a7a33cba6e4a414b8eaf8dfa71bb","tests/out/boids.spvasm.snap":"4075e5580408a1716aff4776e670175c6c870939222a33a40c22e9838aec53f7","tests/out/collatz.info.ron.snap":"fa1cc56eb54a96b70e76c4ca50f43ad608aa76c2c05edb153da1c21f1380bdea","tests/out/collatz.msl.snap":"2a621f2338e97cf88c6ab2b591d6e6c76e1dc19bb045fad83b3ea6fc4cd1f627","tests/out/collatz.ron.snap":"4193405be9cb707721d5dea849634384f7ce64fb52d42e6df2f618781380879c","tests/out/collatz.spvasm.snap":"27912af1ccc39111a82ee80c6f91b51c2c7b9c99e6a6ceefdced3b3c3279110f","tests/out/empty-Compute.glsl.snap":"e6416ae44e84c15626cf899e1d81014f310c92b2c1b678c8b9f0e7d6473afa37","tests/out/empty.msl.snap":"cc77ffa468e834ec895ff13238f066953c599bb4c3db91b47d9a2945ed22aef6","tests/out/empty.spvasm.snap":"cd5f1340bcec1e1bb085053255da4b83e6cbe1f91a3023b1cbe42a1f6ead7c5d","tests/out/image-copy.msl.snap":"d6b80591d29d51b28c6033340e71108512d7d9e38c5e75b25359c2939b8fea0e","tests/out/quad-Fragment.glsl.snap":"58a67f3b0ce8444b84dbd0a9b263394dd24f966eb20223ddc790325e1312fe10","tests/out/quad-Vertex.glsl.snap":"c49d79122aa203c884f7df4f3c4f100632dd0c32edb847ffdc72908d9d24eb6d","tests/out/quad-glsl.ron.snap":"b87062f8f0375e0da7db3dfc322662154a92e6e4a8ad649be27121bc9909cfad","tests/out/quad-glsl.spvasm.snap":"c3658f6088c956f36457f0042a5bc9a1938aa5bb8ed35c1b91494fa993fa178b","tests/out/quad-vert.msl.snap":"bc7e30e811b46929197246bddee9ec9423ef0e6af80d4bec993df59774522edf","tests/out/quad.dot.snap":"d7b61bd06a978431696ab529ca7733f06ac2fe4bf0edf083170030a486e21056","tests/out/quad.msl.snap":"4d5e9970ea5834268d6a2801660fc6f99969c9a18706fe0633db5dd895ed583b","tests/out/quad.spvasm.snap":"bcb166382094586a7f72ca764a6e0aeb77fb78a3b6eea743649583d32bfffe96","tests/out/shadow-Fragment.glsl.snap":"e8c5f1dba741d1ecbd2e1406217746fd4ed2ff93ee1066434e81eed2e4e16afa","tests/out/shadow.info.ron.snap":"8a41b188189c3ec8323cb2acbddd7b59b908d1cd928700b8cbaa22833dcb5f79","tests/out/shadow.msl.snap":"d9b20525783afcc9d271fe13a181d609356103da5a76dc20247fdc1563a78466","tests/out/shadow.ron.snap":"4cd55c8429887b244d808a3929c3e84c6183305944ec9e70d8d6f5621d1172e6","tests/out/shadow.spvasm.snap":"ca90be6869f6f7aec7daa766259c189bbbd9fc4982f55ac0437e51a91c440021","tests/out/skybox-Fragment.glsl.snap":"403bd6e280824702e058f104b13848470a12ad5f9a2664a4b35485056d6f6289","tests/out/skybox-Vertex.glsl.snap":"0ef871798e54dad2ff93c69e8291be1e1ee71ae34f37b4646f3efa3455d12494","tests/out/skybox.msl.snap":"1e58aeda7d668723f3da13fb2bfe85ea83d3b079dd921ee1af0d094b64acc756","tests/out/skybox.spvasm.snap":"34efb1e672f4246593e68b78479c52e026bc0805e78bb12a255390b7b5b05f5d","tests/out/texture-array.spvasm.snap":"9ce0351b0ce4ffdc716c9841aed79047dd078e37216075560d0f5fc48ff089ba","tests/parse.rs":"965e46ed8720aeb260ac8d20d764889529c9d0c4c75c03933ee3e853377c6427","tests/snapshots.rs":"261720e331f49b61041c68c7022c28e263cfc2616fbe538fcdf048bfd29bbbb5"},"package":null} \ No newline at end of file +{"files":{".github/workflows/pipeline.yml":"3a0f75251fb7b410c0c3c8a7c84b940b6caf1317106bf2bf38af3e8ff58f7c9b",".github/workflows/validation-linux.yml":"99698620a9b78eab6b32b9f576b6b5cb1c136445efd863132846e03e99c7df21",".github/workflows/validation-macos.yml":"e55a7c1bebf7ea04947d0d95f9ead375d27c80e0ac109403de083df6ad8aa5c8",".monocodus":"9be77868b35e2af7e3da0e95f7b3282ca573cd19cbec20c6a6a30435ce6d58c2","CHANGELOG.md":"d4bd3d367873f19de91a964174e4ef5a890c1a4abe17d6b06cea337c85c9c87f","Cargo.toml":"b03963b76f88b636c27d6217bf153bf1698023f9bd128d423feb3d24e4b08991","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"ca3be8518f5ef097669cea882643fc532025f29972def4fda49df885565a0480","Makefile":"b52e8ffbf0e6939e067640dd146d22ad4d10674647f8bf479bbff4f368003542","README.md":"cc4e875684858ea18195d0c39fd63f6b18f3c788e29d5ddc1a069d417818d46f","bin/convert.rs":"8d02feb3d214662136a455123b7bb01c2a0c8da6c71ab9733b7e0a1aa15ae7db","src/arena.rs":"b57ecba85ea4bffd5d4a54b3bb3ed00555afe173892d19ed8e543b656e553eb0","src/back/dot/mod.rs":"d0d01ffaa4328a2aab177ad81f20c641f4c4bca02d4fb0d940184e7c985a6a41","src/back/glsl/features.rs":"9ae8016cde010aa3414a0556ad6e358c4a02159d40ba09e441f6796d6c62d6cb","src/back/glsl/keywords.rs":"3f23b1e63e99a7056c3b223524d5d37000ef7316ae9df25532a726a1157d1dcd","src/back/glsl/mod.rs":"508fbbe2d7b6d28222b98334e6dc91f4404f91412d4012079a0620d9da359f8b","src/back/hlsl/keywords.rs":"5cd1d637458c6db2ddad2f2fde23d72bce1b6ef1c976101c920f4d978a40fab0","src/back/hlsl/mod.rs":"f1c8eb38cd47dc9f4dca701c717a7a0404e9243327fad3fa1a30550ae0f4253b","src/back/hlsl/writer.rs":"9e6279060fb10d077a90b036f5f651f22c9c62115995b31c39b5473ebe1839df","src/back/mod.rs":"28e3719d85b67cc5589ad508bc27fd09e67f41547114770aaa3e5cd8aa8dc491","src/back/msl/keywords.rs":"868d9873ccf3eb70c78c10badae6c627d1dddebd808d1279b87d2fcc959af6aa","src/back/msl/mod.rs":"817624b31351ed85ed9e7c637b2e4a52c30bf37055b452cc275015143aae301f","src/back/msl/sampler.rs":"19a905f5eb11d9dad769b60694d1ed7a16ad36ce92b57f9bf70f0a60cd0df1ee","src/back/msl/writer.rs":"979c7f0e88f4a425ac91b4d93104f9bf88589521a34af97ae2934ce8b59a5147","src/back/spv/helpers.rs":"57f4c90373ef6433adecc366d874708db83f8ae187fb817af6c7ddaac73064d3","src/back/spv/instructions.rs":"f0964c5a0075294fcd53940c7a43e2541ca288ae513f53ef73798e4b0ddf7235","src/back/spv/layout.rs":"173ec4d496ab53becdd6a223073d142e2a4b2a25d297b9f9f67059777613b5c2","src/back/spv/mod.rs":"f25c312d63a978b9278ff15348a241adee15049a70c5c4914032873648940378","src/back/spv/writer.rs":"82c27203b6c09712b6852bdf35181ce230c83999780325e4cec182d93c946b16","src/back/wgsl/keywords.rs":"d3e775d961265db10d57060db586e5e584d33a4febb8ef527471cb1c0b6ae5d1","src/back/wgsl/mod.rs":"f1c8eb38cd47dc9f4dca701c717a7a0404e9243327fad3fa1a30550ae0f4253b","src/back/wgsl/writer.rs":"e834c2aeedd0541ddf56b37607f0ed1885818651253ac95858f7d6472ebf6f32","src/front/glsl/ast.rs":"3a393b7f3f5964d3c547e4ffa5915d7fee8088b2babb90e2a9d14ed81cf62ce3","src/front/glsl/constants.rs":"07c9e3ebbfd32cc0a4467581956a36840b2c8040028ba1df991e8f7c2abdb8a9","src/front/glsl/error.rs":"98d99a2129b73372d64ca04d9a8967e93b32278772d4bbcbc9412364fea4bf80","src/front/glsl/functions.rs":"3588119e2eb82dab9704ec1d210189c821de9890de5f5914631e8850ada33563","src/front/glsl/lex.rs":"0d934d8fd7559e33582c4778060b740cc1a35dbb71113b51989ae67a5c39f225","src/front/glsl/mod.rs":"db3c834565b42e68631c2d07db91122d78b8e35c2db9ca751f03f68e981e48eb","src/front/glsl/parser.rs":"3f2aef35a1aa510f59b201da3a95f4ec1eb805db41098c3ed6bf09978101e1c7","src/front/glsl/parser_tests.rs":"619056f38390b2964baaafa17e2652239cbd45f1395a42926ac237d927d316aa","src/front/glsl/token.rs":"8c8d311d43a9991ae71e1eddc2e9a54435cd3fa853819ab15349bfcbd81afe1c","src/front/glsl/types.rs":"15bffe9885a952db4c9bd1ab6b4b300147289e36f4e8a1dd2e473733187630e8","src/front/glsl/variables.rs":"30e1218f667001fcdd1aa266ad4c8d72ff0fb4fc4b75c0ecd521c26772c4deca","src/front/mod.rs":"6e5fbaaed1d7e3f98e2f757361b6804190ed6a874d3b1e998dad7b2891f712c8","src/front/spv/convert.rs":"19b462a27e62f1e35d8ecf4235556c407cf173b8692f8eba0f31affa6eb477e1","src/front/spv/error.rs":"a0864157cdf5296041cfc7534c37223f6807b19edcebe69efe4bc1738c96a116","src/front/spv/flow.rs":"14695aa14cc2140775cb90a2d689c93525184cc5953ee52673c1ab381d8d9bfc","src/front/spv/function.rs":"39a6d33ebd1f2bdd902444f0ad2eb52c5e97086a5a1af3a130d6e08786030150","src/front/spv/image.rs":"e5fdd4ce744edce800694733e35746bb1b027345f1a9f207935d35ca88617aa7","src/front/spv/mod.rs":"f516d5e83a44e3139a98b3feeb441d9b6d95244f130b181a8daec93b50a55663","src/front/wgsl/conv.rs":"6400acd2f8ff7ee1590d6941919b3e18268f971bd0ee379f2828da613b7550ec","src/front/wgsl/layout.rs":"872cb0aed253e673441726515ebff06f7370387a99a60bb5676e2a29d8129a8c","src/front/wgsl/lexer.rs":"3e712cacfc6cb5ae69119e4ff6591f544ba39295b87d9b56c4cd69d89623e270","src/front/wgsl/mod.rs":"a116ef61da1f926a82d5c403cdfa24056513d04a62e57d93af20068e92917397","src/front/wgsl/tests.rs":"aa31503aa11e1ead618709457dcde2f669d5c646b5ba52cbf36040a375ead652","src/lib.rs":"e92a7a2c0aac37422b8402c17239d7517706e4d1d8a782290a0f33fd14776b9a","src/proc/interpolator.rs":"df64ccebc03d5291b9d8fd7398819dd0fa12287158bf7de73b52c3767735eab8","src/proc/mod.rs":"2e9621a025bfe1420af63b42c30855073fdf3828cb8a9acd8a91104742d4e148","src/proc/namer.rs":"6e16e736c11fe323a98155008ca6283560c6d75daaee24a952723fbd508229e7","src/proc/terminator.rs":"1ee66bc82cc478156073fcdfc53e281c8bc85bbe3ac1e79ca1613fb50619e7c2","src/proc/typifier.rs":"26909545aad87eade8a8a06f729e25724b5cf8974de3cf54437629c6be8bde91","src/valid/analyzer.rs":"b77c5bb796681b6797a8a987c754ded098cc05cfbab4f2ec1f451a59d11e2841","src/valid/compose.rs":"f8a0cfa702ba9dd0b7167916c6d82bea38486be81d272a3e67905b4913e11974","src/valid/expression.rs":"301920f859b71aa339181ce71eaf5f3fefdcec4c37a06e213ee25f06a04b6b05","src/valid/function.rs":"23e928a3f7af4424ff711f70685e12a4e384c714f80616106e766f28c5d8eb73","src/valid/interface.rs":"2d109b719e784f9d73410e8ca87474e82a705a166ac720ebd851285d2b6efbc8","src/valid/mod.rs":"f698fdc8dcdbcfd50a0a7343538bf95ebbaa4c4ad1bcd86d8dcb9aeff6924cbe","src/valid/type.rs":"a1be5bf6786074fa5a057b328b694770654c7b1dc1b10bc8c1de3905bd78c806","tests/cases/glsl_constant_expression.vert":"89e1ec69f019ea1c91db65ea1509c81a32841b55bc812a4f14caacd9123351eb","tests/cases/glsl_if_preprocessor.vert":"3b7f98c2592f2d4f17dc55896e31b5896111b0f5546e4abbb3abadfeffadfec8","tests/cases/glsl_phong_lighting.frag":"97fe2c7a9ba918256469c8a8810b300664655ee78c62ee50ca5165df6ce50eb1","tests/cases/glsl_preprocessor_abuse.vert":"86ed48d088256d3095a3dfb20d4d3f719b7dbc370c046399bf3147e5847d407a","tests/cases/glsl_vertex_test_shader.vert":"fdd38521bdef9f6edd437f4530af06bd2b9770cb6c9cee35d0f9fb24135590fd","tests/errors.rs":"f542f436c964c47335ee8fe2730207f56e4d7b1e4978f64d73c702101271b71e","tests/in/access.param.ron":"612f54bec21ff04b0a82028537f6bb45572d3f47754202e85be0ba4e80cde41f","tests/in/access.wgsl":"883c4e9339d47a2813c976e9cbcf80742a6ae778aa01db8f928893f7f81d29b8","tests/in/boids.param.ron":"83722a9b88dcc01f691c7148a03e37149c04ba898402d930c66110c06bb5efcc","tests/in/boids.wgsl":"94cb4bf333aecc4d2b4b15e08b47b46fb66c41027ea1bf2ab11b7ec8f4e7cd27","tests/in/collatz.param.ron":"abe9a778c054ba81b3483477702c9e21219f57ca376e3cd57606a92d48c39ba4","tests/in/collatz.wgsl":"34e740dbf4bdbda2c4d20ea1984d2dfa263ad7b09823ebb857a6a3d85af5e1bb","tests/in/empty.param.ron":"128c929cf8b57d2348c593af3690c90cbcbe2ccaaa4611788474cbabe3ef91f9","tests/in/empty.wgsl":"626dc2c8b00c02b40cf74a87154511068a46fa586c8780765bb506fab5f60c6c","tests/in/image-copy.param.ron":"612f54bec21ff04b0a82028537f6bb45572d3f47754202e85be0ba4e80cde41f","tests/in/image-copy.wgsl":"6d4c2aebdecc1f832cc3df5da24c4bbeef8762df22096cff440ec00cefa90c89","tests/in/interpolate.param.ron":"c4aab5757838fe02a069ef07b3541c7f3fb5b9bb08dba0c77acf59515f764915","tests/in/interpolate.wgsl":"9977ed39cfbd625c4e212df581407a50979983d9dbcf7edfae708c405db234e5","tests/in/operators.param.ron":"2641038deb0b043e98c841841294cd91fe3f849fef8a0ac768fd84c9bba18077","tests/in/operators.wgsl":"ad0b7986832f1340887eacba83e0fe1e98fbb4c6f1ebd3becd5b19933689fca9","tests/in/quad-glsl.glsl":"ef2f105c06b15406353b604b686c1e707fa8a49b66985b4e616d59591be4cbff","tests/in/quad-glsl.param.ron":"255dc5dbda6b6da104fed3142ea0ac331b8ad51962bd5606a77b5ba17e6e5bd1","tests/in/quad-vert.spv":"c194227c35a6b69613c577b5548713ebb058fc9ffbc2d04de4fe673f07b8cb30","tests/in/quad.param.ron":"255dc5dbda6b6da104fed3142ea0ac331b8ad51962bd5606a77b5ba17e6e5bd1","tests/in/quad.wgsl":"f0ca4a082e80ca291d76181e5b7429d14fe851ee9efc264a251b4fe57ed07eb9","tests/in/shadow.param.ron":"ade85c1c9fd87aebfc833b1264fe04d2dcb9531ae1b3eb6652b86a15ec68c36f","tests/in/shadow.spv":"5a239809a04e7f8937330296394899e423ee86578c692e3581baaadbe36194d5","tests/in/shadow.wgsl":"60ba5cfb0357d8b4b1ade54d951cc2550cc3c438af21037f46457f64d6167c97","tests/in/skybox.param.ron":"97ed087c60e057f53a439cd3d3442b7bf40226dd76850919f81d9b84d76a1d8a","tests/in/skybox.wgsl":"3fe6493ee35161881c7ccaee2d087ddd4b320cb81eb7c7a9e969f2143b8e3fdd","tests/in/texture-array.param.ron":"7595502b6acb9470652b437a3b262112cd4e8670c912b9caf76e835e89369cfc","tests/in/texture-array.wgsl":"1aa82179c75e12f14869f4412195cf2c3fdd4c989daac911a9142603b36ce67f","tests/out/access.msl":"d1200b5bb928c932d58f1d0daf06148ec087e766e6cefbd920ac25871d4af1dd","tests/out/access.spvasm":"2fcc00328919669dd86693589924e79d3e6e8da382e2bb59baebf77aceec7c46","tests/out/boids.msl":"6940cb43b67da43ad714170a9a89a4f225a37b3dcfebcbd8f28762a8739c10bd","tests/out/boids.spvasm":"8610e02dd14e40635b9bfea12023be7f46e4e96843a3b3554f96812d05105d39","tests/out/collatz.info.ron":"5a1867fbcab44ab0f984abf29dcbd18f3a443b3e4f61876c01e42d5efce09755","tests/out/collatz.msl":"fd62eeb752f9a62cb22720374a65684c7dc892598c04d25b81515a9943c7d41c","tests/out/collatz.ron":"248d732cbd348343821744c162df4abcd9eacc7c38554233a98ae1e5da21636d","tests/out/collatz.spvasm":"92e6135a2c3b096dd9dc432e824f05aee6881bbbd5b0c5749e99602126040a06","tests/out/empty.Compute.glsl":"e480da0379e21d9bd05139526ed9946740a530714cf51f0c30fe863da19cb448","tests/out/empty.hlsl":"0ee78abc7d8ff0edad1b792199c17a9b0a8521d52f87427f996474e334956610","tests/out/empty.msl":"abbb0c34e41482aaac71db58342a3e0fdf97aecb9c103140a91823750dd84333","tests/out/empty.spvasm":"41f3f9c7e3565b68330e9435bea9b1e4ca9844dd26a29a2a821947a20558d818","tests/out/empty.wgsl":"07e26cc19e06452ec9b5b5ebbc03771cb43fe4d2dfeef73f88cadb81b23908a8","tests/out/image-copy.msl":"421da1c9bbccfd7ce22e8dc8d46a04b1bdf8954b783ac66736547162bcd22fe2","tests/out/interpolate.Fragment.glsl":"9037751e4708a9b363299537c3290aefbc1162ba243c42cad8bbbf35fa64db00","tests/out/interpolate.Vertex.glsl":"aaed5578af062a60dc8f3f3d9807f1b86bd6ab64fca72b59dcb6254bd67bc315","tests/out/interpolate.msl":"d549fd209965285b9b990278d08f146e37e89c9817e96f902280e826c67a0d65","tests/out/interpolate.spvasm":"ec387aaa0a23727023e2154e6046ced1ee30179a3a3cc704ec6eb5a231f263f5","tests/out/operators.Vertex.glsl":"3364892bd633808f95539662606b4af90f9bbe60d3667031cb0fa47583588aef","tests/out/operators.msl":"7e9b50cf5a905e8cd9e7ea7ebe8ba4d7cc54d5826d5ed422ef312b5fc000d5a5","tests/out/operators.spvasm":"d980de90d07b5db578f230ccbb89e8fe8d32b53b7dc73a358a0310aa156729a2","tests/out/quad-vert.msl":"3804bc991f121e578d4c8150af3c23fe0e7a4953e3144052d7863afce355d03a","tests/out/quad.Fragment.glsl":"e3ba9d67634c5c44628a02bc39af5eefd873a33ca065e0c3898f33148c420091","tests/out/quad.Vertex.glsl":"fb267c78640af5dad654f94cafc8d556e7e99c80288fa77d2dd15aae2f50d47b","tests/out/quad.dot":"8b734904753b9bcbf38b8907d82eead5fca6986061e43ac08d967c3109462c69","tests/out/quad.msl":"cbf1559f956369cf03d7c0597507a3c992c199dd165e71d24de31a9d1ff6ad58","tests/out/quad.spvasm":"2703777fe6f98776813646a8f54c634a51a4e0ed4aac116c8a2ad1b770b82d17","tests/out/shadow.Fragment.glsl":"0a813c20f1f540f460883f299546176ff9e171e11dd26e6f3e4a0ad64b302e7d","tests/out/shadow.info.ron":"a7c214498f026f57d349f24780e660cb79e400c05f4e1376908cd003305c7e83","tests/out/shadow.msl":"f2e48181af8d5cf6bed25b2bbb86e43513ee0b2900885bf78be4b90f6f17626b","tests/out/shadow.ron":"2e35315043a9293ee6c1ce7cec8e0fc1dcbd55db75000482bb30bdfb46e6940e","tests/out/shadow.spvasm":"061e0c521e655d142b001ed1ac8a689864c21a872b7a5e0068491bda672070bb","tests/out/skybox.Fragment.glsl":"e3de0ce91dfd5a1f6045176919e42ffe17efa3a2b33a7dce39e7ec95ffb40fbb","tests/out/skybox.Vertex.glsl":"66ce4768bf5c4c397866830251a2906017c2d417876a66ab44583ddeb5ca0546","tests/out/skybox.msl":"1dc5f0d992613b6ebb6ca20fd50166d588ab97985841c7409af5ff2dd599913e","tests/out/skybox.spvasm":"40d274e436e82842141619e993999cb82ca022fe0e509a94ae75fc205e3c982d","tests/out/texture-array.msl":"936c6fb925fe62f845e283c121bd8abc9fafe56acfcf00cde08f677241b6f013","tests/out/texture-array.spvasm":"81833a2fcd7cf1ff5ce7bab9b7f0427fa7a7b4b0d64cf3417bb43b45050b024d","tests/parse.rs":"965e46ed8720aeb260ac8d20d764889529c9d0c4c75c03933ee3e853377c6427","tests/snapshots.rs":"126cf95b15fba43a3f80bbe0474fcb601906f1b063fbbffae9c313200cbec088"},"package":null} \ No newline at end of file diff --git a/third_party/rust/naga/.github/workflows/pipeline.yml b/third_party/rust/naga/.github/workflows/pipeline.yml index 5ee486280c79..3d9ca0f6a08d 100644 --- a/third_party/rust/naga/.github/workflows/pipeline.yml +++ b/third_party/rust/naga/.github/workflows/pipeline.yml @@ -24,6 +24,8 @@ jobs: with: command: test args: --all-features + - name: Check snapshots + run: git diff --exit-code -- tests/out clippy: name: Clippy runs-on: ubuntu-latest diff --git a/third_party/rust/naga/.github/workflows/validation-linux.yml b/third_party/rust/naga/.github/workflows/validation-linux.yml index 870299b4bd35..997b80783f71 100644 --- a/third_party/rust/naga/.github/workflows/validation-linux.yml +++ b/third_party/rust/naga/.github/workflows/validation-linux.yml @@ -2,9 +2,10 @@ name: validation-linux on: pull_request: paths: - - 'tests/out/*.spvasm.snap' - - 'tests/out/*.glsl.snap' - - 'tests/out/*.dot.snap' + - 'tests/out/*.spvasm' + - 'tests/out/*.glsl' + - 'tests/out/*.dot' + - 'tests/out/*.wgsl' jobs: validate-linux: @@ -17,3 +18,4 @@ jobs: - run: make validate-spv - run: make validate-glsl - run: make validate-dot + - run: make validate-wgsl diff --git a/third_party/rust/naga/.github/workflows/validation-macos.yml b/third_party/rust/naga/.github/workflows/validation-macos.yml index 850e9f08c50f..89a3b13f5106 100644 --- a/third_party/rust/naga/.github/workflows/validation-macos.yml +++ b/third_party/rust/naga/.github/workflows/validation-macos.yml @@ -2,7 +2,7 @@ name: validation-macos on: pull_request: paths: - - 'tests/out/*.msl.snap' + - 'tests/out/*.msl' jobs: validate-macos: diff --git a/third_party/rust/naga/Cargo.toml b/third_party/rust/naga/Cargo.toml index 7f3ef3efdb07..90b3dedd1fdc 100644 --- a/third_party/rust/naga/Cargo.toml +++ b/third_party/rust/naga/Cargo.toml @@ -39,15 +39,16 @@ deserialize = ["serde"] spv-in = ["petgraph", "spirv"] spv-out = ["spirv"] wgsl-in = ["codespan-reporting"] +wgsl-out = [] +hlsl-out = [] [[bin]] name = "convert" path = "bin/convert.rs" [dev-dependencies] -difference = "2.0" +diff = "0.1" ron = "0.6" serde = { version = "1.0", features = ["derive"] } spirv = { package = "spirv_headers", version = "1.5", features = ["deserialize"] } -insta = { version = "1.6", features = ["glob"] } rspirv = "0.7" diff --git a/third_party/rust/naga/Makefile b/third_party/rust/naga/Makefile index 8f38834193a1..ea631e4995c8 100644 --- a/third_party/rust/naga/Makefile +++ b/third_party/rust/naga/Makefile @@ -1,4 +1,4 @@ -.PHONY: all clean validate-spv validate-msl validate-glsl validate-dot +.PHONY: all clean validate-spv validate-msl validate-glsl validate-dot validate-wgsl .SECONDARY: boids.metal quad.metal SNAPSHOTS_IN=tests/in SNAPSHOTS_OUT=tests/out @@ -26,34 +26,40 @@ clean: %.png: %.dot dot -Tpng $< -o $@ -validate-spv: $(SNAPSHOTS_OUT)/*.spvasm.snap +validate-spv: $(SNAPSHOTS_OUT)/*.spvasm @set -e && for file in $^ ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"}; \ - tail -n +5 $${file} | spirv-as --target-env vulkan1.0 -o - | spirv-val; \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"}; \ + cat $${file} | spirv-as --target-env vulkan1.0 -o - | spirv-val; \ done -validate-msl: $(SNAPSHOTS_OUT)/*.msl.snap +validate-msl: $(SNAPSHOTS_OUT)/*.msl @set -e && for file in $^ ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"}; \ - tail -n +5 $${file} | xcrun -sdk macosx metal -mmacosx-version-min=10.11 -x metal - -o /dev/null; \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"}; \ + cat $${file} | xcrun -sdk macosx metal -mmacosx-version-min=10.11 -x metal - -o /dev/null; \ done -validate-glsl: $(SNAPSHOTS_OUT)/*.glsl.snap - @set -e && for file in $(SNAPSHOTS_OUT)/*-Vertex.glsl.snap ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"};\ - tail -n +5 $${file} | glslangValidator --stdin -S vert; \ +validate-glsl: $(SNAPSHOTS_OUT)/*.glsl + @set -e && for file in $(SNAPSHOTS_OUT)/*.Vertex.glsl ; do \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"};\ + cat $${file} | glslangValidator --stdin -S vert; \ done - @set -e && for file in $(SNAPSHOTS_OUT)/*-Fragment.glsl.snap ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"};\ - tail -n +5 $${file} | glslangValidator --stdin -S frag; \ + @set -e && for file in $(SNAPSHOTS_OUT)/*.Fragment.glsl ; do \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"};\ + cat $${file} | glslangValidator --stdin -S frag; \ done - @set -e && for file in $(SNAPSHOTS_OUT)/*-Compute.glsl.snap ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"};\ - tail -n +5 $${file} | glslangValidator --stdin -S comp; \ + @set -e && for file in $(SNAPSHOTS_OUT)/*.Compute.glsl ; do \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"};\ + cat $${file} | glslangValidator --stdin -S comp; \ done -validate-dot: $(SNAPSHOTS_OUT)/*.dot.snap +validate-dot: $(SNAPSHOTS_OUT)/*.dot @set -e && for file in $^ ; do \ - echo "Validating" $${file#"$(SNAPSHOTS_OUT)/snapshots__"}; \ - tail -n +5 $${file} | dot -o /dev/null; \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"}; \ + cat $${file} | dot -o /dev/null; \ + done + +validate-wgsl: $(SNAPSHOTS_OUT)/*.wgsl + @set -e && for file in $^ ; do \ + echo "Validating" $${file#"$(SNAPSHOTS_OUT)/"}; \ + cargo run --bin convert --features wgsl-in $${file} >/dev/null; \ done diff --git a/third_party/rust/naga/README.md b/third_party/rust/naga/README.md index 9a83e18d83a7..2224fab6e953 100644 --- a/third_party/rust/naga/README.md +++ b/third_party/rust/naga/README.md @@ -21,7 +21,7 @@ Rust | | | | Back-end | Status | Feature | Notes | --------------- | ------------------ | -------- | ----- | SPIR-V | :white_check_mark: | spv-out | | -WGSL | | | | +WGSL | :construction: | wgsl-out | | Metal | :white_check_mark: | msl-out | | HLSL | :construction: | hlsl-out | | GLSL | :ok: | glsl-out | | @@ -44,9 +44,8 @@ cargo run --features wgsl-in,glsl-out -- my_shader.wgsl my_shader.vert --profile ## Development workflow The main instrument aiding the development is the good old `cargo test --all-features`, -which will run the snapshot tests as well as the unit tests. -Any changes in the snapshots would then have to be reviewed with `cargo insta review` -before being accepted into the code. +which will run the unit tests, and also update all the snapshots. You'll see these +changes in git before committing the code. If working on a particular front-end or back-end, it may be convenient to enable the relevant features in `Cargo.toml`, e.g. @@ -61,4 +60,6 @@ are indeed valid for the target platforms they are compiled for. We automate thi make validate-spv # for Vulkan shaders, requires SPIRV-Tools installed make validate-msl # for Metal shaders, requires XCode command-line tools installed make validate-glsl # for OpenGL shaders, requires GLSLang installed +make validate-dot # for dot files, requires GraphViz installed +make validate-wgsl # for WGSL shaders ``` diff --git a/third_party/rust/naga/bin/convert.rs b/third_party/rust/naga/bin/convert.rs index d52468110ba8..151fc2967448 100644 --- a/third_party/rust/naga/bin/convert.rs +++ b/third_party/rust/naga/bin/convert.rs @@ -202,8 +202,14 @@ fn main() { #[cfg(feature = "msl-out")] "metal" => { use naga::back::msl; - let (msl, _) = - msl::write_string(&module, info.as_ref().unwrap(), ¶ms.msl).unwrap_pretty(); + let pipeline_options = msl::PipelineOptions::default(); + let (msl, _) = msl::write_string( + &module, + info.as_ref().unwrap(), + ¶ms.msl, + &pipeline_options, + ) + .unwrap_pretty(); fs::write(output_path, msl).unwrap(); } #[cfg(feature = "spv-out")] @@ -255,6 +261,20 @@ fn main() { let output = dot::write(&module, info.as_ref()).unwrap(); fs::write(output_path, output).unwrap(); } + #[cfg(feature = "hlsl-out")] + "hlsl" => { + use naga::back::hlsl; + + let hlsl = hlsl::write_string(&module).unwrap_pretty(); + fs::write(output_path, hlsl).unwrap(); + } + #[cfg(feature = "wgsl-out")] + "wgsl" => { + use naga::back::wgsl; + + let wgsl = wgsl::write_string(&module).unwrap_pretty(); + fs::write(output_path, wgsl).unwrap(); + } other => { let _ = params; panic!( diff --git a/third_party/rust/naga/src/arena.rs b/third_party/rust/naga/src/arena.rs index af3fba55dd2a..174c79b540e9 100644 --- a/third_party/rust/naga/src/arena.rs +++ b/third_party/rust/naga/src/arena.rs @@ -189,7 +189,8 @@ impl Arena { /// Adds a new value to the arena, returning a typed handle. pub fn append(&mut self, value: T) -> Handle { let position = self.data.len() + 1; - let index = unsafe { Index::new_unchecked(position as u32) }; + let index = + Index::new(position as u32).expect("Failed to append to Arena. Handle overflows"); self.data.push(value); Handle::new(index) } diff --git a/third_party/rust/naga/src/back/dot/mod.rs b/third_party/rust/naga/src/back/dot/mod.rs index 8296e0ba2a3e..d1df17517681 100644 --- a/third_party/rust/naga/src/back/dot/mod.rs +++ b/third_party/rust/naga/src/back/dot/mod.rs @@ -183,6 +183,10 @@ fn write_fun( (Cow::Owned(format!("AccessIndex[{}]", index)), 1) } E::Constant(_) => (Cow::Borrowed("Constant"), 2), + E::Splat { size, value } => { + edges.insert("value", value); + (Cow::Owned(format!("Splat{:?}", size)), 3) + } E::Compose { ref components, .. } => { payload = Some(Payload::Arguments(components)); (Cow::Borrowed("Compose"), 3) diff --git a/third_party/rust/naga/src/back/glsl/features.rs b/third_party/rust/naga/src/back/glsl/features.rs index 283c2ac7d568..d5c835f9d096 100644 --- a/third_party/rust/naga/src/back/glsl/features.rs +++ b/third_party/rust/naga/src/back/glsl/features.rs @@ -1,7 +1,7 @@ use super::{BackendResult, Error, Version, Writer}; use crate::{ - Bytes, ImageClass, ImageDimension, ScalarKind, ShaderStage, StorageClass, StorageFormat, - TypeInner, + Binding, Bytes, Handle, ImageClass, ImageDimension, Interpolation, Sampling, ScalarKind, + ShaderStage, StorageClass, StorageFormat, Type, TypeInner, }; use std::io::Write; @@ -24,6 +24,10 @@ bitflags::bitflags! { const CONSERVATIVE_DEPTH = 1 << 9; /// Isn't supported in ES const TEXTURE_1D = 1 << 10; + /// Interpolation and auxiliary qualifiers. Perspective, Flat, and + /// Centroid are available in all GLSL versions we support. + const NOPERSPECTIVE_QUALIFIER = 1 << 11; + const SAMPLE_QUALIFIER = 1 << 12; } } @@ -84,6 +88,8 @@ impl FeaturesManager { // 1D textures are supported by all core versions and aren't supported by an es versions // so use 0 that way the check will always be false and can be optimized away check_feature!(TEXTURE_1D, 0); + check_feature!(NOPERSPECTIVE_QUALIFIER, 130); + check_feature!(SAMPLE_QUALIFIER, 400, 320); // Return an error if there are missing features if missing.is_empty() { @@ -183,6 +189,13 @@ impl<'a, W> Writer<'a, W> { } } + for arg in self.entry_point.function.arguments.iter() { + self.varying_required_features(arg.binding.as_ref(), arg.ty); + } + if let Some(ref result) = self.entry_point.function.result { + self.varying_required_features(result.binding.as_ref(), result.ty); + } + if let ShaderStage::Compute = self.options.shader_stage { self.features.request(Features::COMPUTE_SHADER) } @@ -266,4 +279,28 @@ impl<'a, W> Writer<'a, W> { self.features.request(Features::DOUBLE_TYPE); } } + + fn varying_required_features(&mut self, binding: Option<&Binding>, ty: Handle) { + match self.module.types[ty].inner { + crate::TypeInner::Struct { ref members, .. } => { + for member in members { + self.varying_required_features(member.binding.as_ref(), member.ty); + } + } + _ => { + if let Some(&Binding::Location { + interpolation, + sampling, + .. + }) = binding { + if interpolation == Some(Interpolation::Linear) { + self.features.request(Features::NOPERSPECTIVE_QUALIFIER); + } + if sampling == Some(Sampling::Sample) { + self.features.request(Features::SAMPLE_QUALIFIER); + } + } + } + } + } } diff --git a/third_party/rust/naga/src/back/glsl/mod.rs b/third_party/rust/naga/src/back/glsl/mod.rs index b27b6468b73a..11b4c2fd0805 100644 --- a/third_party/rust/naga/src/back/glsl/mod.rs +++ b/third_party/rust/naga/src/back/glsl/mod.rs @@ -48,9 +48,10 @@ use crate::{ valid::{FunctionInfo, ModuleInfo}, Arena, ArraySize, BinaryOperator, Binding, BuiltIn, Bytes, ConservativeDepth, Constant, ConstantInner, DerivativeAxis, Expression, FastHashMap, Function, GlobalVariable, Handle, - ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, ScalarKind, ScalarValue, - ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember, Type, - TypeInner, UnaryOperator, + ImageClass, Interpolation, LocalVariable, Module, RelationalFunction, Sampling, ScalarKind, + ScalarValue, ShaderStage, Statement, StorageAccess, StorageClass, StorageFormat, StructMember, + Type, TypeInner, UnaryOperator, + }; use features::FeaturesManager; use std::{ @@ -232,8 +233,10 @@ impl IdGenerator { /// Helper wrapper used to get a name for a varying /// /// Varying have different naming schemes depending on their binding: -/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in) -/// - Varyings with location bindings are named `_location_X` where `X` is the location +/// - Varyings with builtin bindings get the from [`glsl_built_in`](glsl_built_in). +/// - Varyings with location bindings are named `_S_location_X` where `S` is a +/// prefix identifying which pipeline stage the varying connects, and `X` is +/// the location. struct VaryingName<'a> { binding: &'a Binding, stage: ShaderStage, @@ -242,7 +245,7 @@ struct VaryingName<'a> { impl fmt::Display for VaryingName<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.binding { - Binding::Location(location, _) => { + Binding::Location { location, .. } => { let prefix = match (self.stage, self.output) { (ShaderStage::Compute, _) => unreachable!(), // pipeline to vertex @@ -448,11 +451,7 @@ impl<'a, W: Write> Writer<'a, W> { // This are always ordered because of the IR is structured in a way that you can't make a // struct without adding all of it's members first for (handle, ty) in self.module.types.iter() { - if let TypeInner::Struct { - block: _, - ref members, - } = ty.inner - { + if let TypeInner::Struct { ref members, .. } = ty.inner { // No needed to write a struct that also should be written as a global variable let is_global_struct = self .module @@ -670,11 +669,12 @@ impl<'a, W: Write> Writer<'a, W> { // glsl has no pointer types so just write types as normal and loads are skipped TypeInner::Pointer { base, .. } => self.write_type(base), TypeInner::Struct { - block: true, + level: crate::StructLevel::Root, ref members, + span: _, } => self.write_struct(true, ty, members), // glsl structs are written as just the struct name if it isn't a block - TypeInner::Struct { block: false, .. } => { + TypeInner::Struct { .. } => { // Get the struct name let name = &self.names[&NameKey::Type(ty)]; write!(self.out, "{}", name)?; @@ -790,25 +790,28 @@ impl<'a, W: Write> Writer<'a, W> { output: bool, ) -> Result<(), Error> { match self.module.types[ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { for member in members { self.write_varying(member.binding.as_ref(), member.ty, output)?; } } _ => { - let (location, interpolation) = match binding { - Some(&Binding::Location(location, interpolation)) => (location, interpolation), + let (location, interpolation, sampling) = match binding { + Some(&Binding::Location { location, interpolation, sampling }) => (location, interpolation, sampling), _ => return Ok(()), }; + // Write the interpolation modifier if needed // - // We ignore all interpolation modifiers that aren't used in input globals in fragment - // shaders or output globals in vertex shaders + // We ignore all interpolation and auxiliary modifiers that aren't used in fragment + // shaders' input globals or vertex shaders' output globals. + let emit_interpolation_and_auxiliary = match self.options.shader_stage { + ShaderStage::Vertex => output, + ShaderStage::Fragment => !output, + _ => false, + }; if let Some(interp) = interpolation { - if self.options.shader_stage == ShaderStage::Fragment { + if emit_interpolation_and_auxiliary { write!(self.out, "{} ", glsl_interpolation(interp))?; } } @@ -817,13 +820,26 @@ impl<'a, W: Write> Writer<'a, W> { if self.options.version.supports_explicit_locations() { write!( self.out, - "layout(location = {}) {} ", - location, - if output { "out" } else { "in" } - )?; - } else { - write!(self.out, "{} ", if output { "out" } else { "in" })?; + "layout(location = {}) ", + location)?; } + + // Write the sampling auxiliary qualifier. + // + // Before GLSL 4.2, the `centroid` and `sample` qualifiers were required to appear + // immediately before the `in` / `out` qualifier, so we'll just follow that rule + // here, regardless of the version. + if let Some(sampling) = sampling { + if emit_interpolation_and_auxiliary { + if let Some(qualifier) = glsl_sampling(sampling) { + write!(self.out, "{} ", qualifier)?; + } + } + } + + // Write the input/output qualifier. + write!(self.out, "{} ", if output { "out" } else { "in" })?; + // Write the type // `write_type` adds no leading or trailing spaces self.write_type(ty)?; @@ -831,7 +847,7 @@ impl<'a, W: Write> Writer<'a, W> { // Finally write the global name and end the global with a `;` and a newline // Leading space is important let vname = VaryingName { - binding: &Binding::Location(location, None), + binding: &Binding::Location { location, interpolation: None, sampling: None }, stage: self.entry_point.stage, output, }; @@ -918,10 +934,7 @@ impl<'a, W: Write> Writer<'a, W> { write!(self.out, " {}", name)?; write!(self.out, " = ")?; match self.module.types[arg.ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { self.write_type(arg.ty)?; write!(self.out, "(")?; for (index, member) in members.iter().enumerate() { @@ -1338,10 +1351,7 @@ impl<'a, W: Write> Writer<'a, W> { if let Some(ref result) = ep.function.result { let value = value.unwrap(); match self.module.types[result.ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { for (index, member) in members.iter().enumerate() { let varying_name = VaryingName { binding: member.binding.as_ref().unwrap(), @@ -1489,6 +1499,14 @@ impl<'a, W: Write> Writer<'a, W> { Expression::Constant(constant) => { self.write_constant(&self.module.constants[constant])? } + // `Splat` needs to actually write down a vector, it's not always inferred in GLSL. + Expression::Splat { size: _, value } => { + let resolved = ctx.info[expr].ty.inner_with(&self.module.types); + self.write_value_type(resolved)?; + write!(self.out, "(")?; + self.write_expr(value, ctx)?; + write!(self.out, ")")? + } // `Compose` is pretty simple we just write `type(components)` where `components` is a // comma separated list of expressions Expression::Compose { ty, ref components } => { @@ -2205,8 +2223,15 @@ fn glsl_interpolation(interpolation: Interpolation) -> &'static str { Interpolation::Perspective => "smooth", Interpolation::Linear => "noperspective", Interpolation::Flat => "flat", - Interpolation::Centroid => "centroid", - Interpolation::Sample => "sample", + } +} + +/// Return the GLSL auxiliary qualifier for the given sampling value. +fn glsl_sampling(sampling: Sampling) -> Option<&'static str> { + match sampling { + Sampling::Center => None, + Sampling::Centroid => Some("centroid"), + Sampling::Sample => Some("sample"), } } diff --git a/third_party/rust/naga/src/back/hlsl/keywords.rs b/third_party/rust/naga/src/back/hlsl/keywords.rs new file mode 100644 index 000000000000..e4ce79f3664f --- /dev/null +++ b/third_party/rust/naga/src/back/hlsl/keywords.rs @@ -0,0 +1 @@ +pub const RESERVED: &[&str] = &[]; diff --git a/third_party/rust/naga/src/back/hlsl/mod.rs b/third_party/rust/naga/src/back/hlsl/mod.rs new file mode 100644 index 000000000000..e785b57a128a --- /dev/null +++ b/third_party/rust/naga/src/back/hlsl/mod.rs @@ -0,0 +1,23 @@ +mod keywords; +mod writer; + +use std::io::Error as IoError; +use std::string::FromUtf8Error; +use thiserror::Error; + +pub use writer::Writer; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + IoError(#[from] IoError), + #[error(transparent)] + Utf8(#[from] FromUtf8Error), +} + +pub fn write_string(module: &crate::Module) -> Result { + let mut w = Writer::new(Vec::new()); + w.write(module)?; + let output = String::from_utf8(w.finish())?; + Ok(output) +} diff --git a/third_party/rust/naga/src/back/hlsl/writer.rs b/third_party/rust/naga/src/back/hlsl/writer.rs new file mode 100644 index 000000000000..121d4506c5dd --- /dev/null +++ b/third_party/rust/naga/src/back/hlsl/writer.rs @@ -0,0 +1,69 @@ +use super::Error; +use crate::back::hlsl::keywords::RESERVED; +use crate::proc::{NameKey, Namer}; +use crate::FastHashMap; +use std::io::Write; + +const INDENT: &str = " "; + +pub struct Writer { + out: W, + names: FastHashMap, + namer: Namer, +} + +impl Writer { + pub fn new(out: W) -> Self { + Writer { + out, + names: FastHashMap::default(), + namer: Namer::default(), + } + } + + pub fn write(&mut self, module: &crate::Module) -> Result<(), Error> { + self.names.clear(); + self.namer.reset(module, RESERVED, &mut self.names); + + for (ep_index, ep) in module.entry_points.iter().enumerate() { + let fun = &ep.function; + let fun_name = &self.names[&NameKey::EntryPoint(ep_index as _)]; + writeln!(self.out)?; + + let return_type_name = match fun.result { + None => "void", + _ => "", + }; + + writeln!( + self.out, + "{} {}({}", + return_type_name, + fun_name, + if fun.arguments.is_empty() { ")" } else { "" } + )?; + + // TODO Support arguments + self.write_block(&ep.function.body)?; + } + Ok(()) + } + + fn write_block(&mut self, statements: &[crate::Statement]) -> Result<(), Error> { + writeln!(self.out, "{{")?; + + for statement in statements { + if let crate::Statement::Return { value: None } = *statement { + writeln!(self.out, "{}return;", INDENT)?; + } + } + + writeln!(self.out, "}}")?; + + Ok(()) + } + + pub fn finish(self) -> W { + self.out + } +} diff --git a/third_party/rust/naga/src/back/mod.rs b/third_party/rust/naga/src/back/mod.rs index c7d513a66dc9..a478d971d40f 100644 --- a/third_party/rust/naga/src/back/mod.rs +++ b/third_party/rust/naga/src/back/mod.rs @@ -4,10 +4,14 @@ pub mod dot; #[cfg(feature = "glsl-out")] pub mod glsl; +#[cfg(feature = "hlsl-out")] +pub mod hlsl; #[cfg(feature = "msl-out")] pub mod msl; #[cfg(feature = "spv-out")] pub mod spv; +#[cfg(feature = "wgsl-out")] +pub mod wgsl; impl crate::Expression { /// Returns the ref count, upon reaching which this expression diff --git a/third_party/rust/naga/src/back/msl/keywords.rs b/third_party/rust/naga/src/back/msl/keywords.rs index cd074ab43feb..bb4338560efc 100644 --- a/third_party/rust/naga/src/back/msl/keywords.rs +++ b/third_party/rust/naga/src/back/msl/keywords.rs @@ -99,4 +99,114 @@ pub const RESERVED: &[&str] = &[ "read_only", "write_only", "read_write", + "auto", + // Metal reserved types + "llong", + "ullong", + "quad", + "complex", + "imaginary", + // Metal constants + "CHAR_BIT", + "SCHAR_MAX", + "SCHAR_MIN", + "UCHAR_MAX", + "CHAR_MAX", + "CHAR_MIN", + "USHRT_MAX", + "SHRT_MAX", + "SHRT_MIN", + "UINT_MAX", + "INT_MAX", + "INT_MIN", + "ULONG_MAX", + "LONG_MAX", + "LONG_MIN", + "ULLONG_MAX", + "LLONG_MAX", + "LLONG_MIN", + "FLT_DIG", + "FLT_MANT_DIG", + "FLT_MAX_10_EXP", + "FLT_MAX_EXP", + "FLT_MIN_10_EXP", + "FLT_MIN_EXP", + "FLT_RADIX", + "FLT_MAX", + "FLT_MIN", + "FLT_EPSILON", + "FLT_DECIMAL_DIG", + "FP_ILOGB0", + "FP_ILOGB0", + "FP_ILOGBNAN", + "FP_ILOGBNAN", + "MAXFLOAT", + "HUGE_VALF", + "INFINITY", + "NAN", + "M_E_F", + "M_LOG2E_F", + "M_LOG10E_F", + "M_LN2_F", + "M_LN10_F", + "M_PI_F", + "M_PI_2_F", + "M_PI_4_F", + "M_1_PI_F", + "M_2_PI_F", + "M_2_SQRTPI_F", + "M_SQRT2_F", + "M_SQRT1_2_F", + "HALF_DIG", + "HALF_MANT_DIG", + "HALF_MAX_10_EXP", + "HALF_MAX_EXP", + "HALF_MIN_10_EXP", + "HALF_MIN_EXP", + "HALF_RADIX", + "HALF_MAX", + "HALF_MIN", + "HALF_EPSILON", + "HALF_DECIMAL_DIG", + "MAXHALF", + "HUGE_VALH", + "M_E_H", + "M_LOG2E_H", + "M_LOG10E_H", + "M_LN2_H", + "M_LN10_H", + "M_PI_H", + "M_PI_2_H", + "M_PI_4_H", + "M_1_PI_H", + "M_2_PI_H", + "M_2_SQRTPI_H", + "M_SQRT2_H", + "M_SQRT1_2_H", + "DBL_DIG", + "DBL_MANT_DIG", + "DBL_MAX_10_EXP", + "DBL_MAX_EXP", + "DBL_MIN_10_EXP", + "DBL_MIN_EXP", + "DBL_RADIX", + "DBL_MAX", + "DBL_MIN", + "DBL_EPSILON", + "DBL_DECIMAL_DIG", + "MAXDOUBLE", + "HUGE_VAL", + "M_E", + "M_LOG2E", + "M_LOG10E", + "M_LN2", + "M_LN10", + "M_PI", + "M_PI_2", + "M_PI_4", + "M_1_PI", + "M_2_PI", + "M_2_SQRTPI", + "M_SQRT2", + "M_SQRT1_2", ]; diff --git a/third_party/rust/naga/src/back/msl/mod.rs b/third_party/rust/naga/src/back/msl/mod.rs index 23b63794c990..92b80ffa0aab 100644 --- a/third_party/rust/naga/src/back/msl/mod.rs +++ b/third_party/rust/naga/src/back/msl/mod.rs @@ -23,39 +23,86 @@ For the result type, if it's a structure, we re-compose it with a temporary valu holding the result. !*/ -use crate::{arena::Handle, valid::ModuleInfo, FastHashMap}; +use crate::{arena::Handle, valid::ModuleInfo}; use std::fmt::{Error as FmtError, Write}; mod keywords; +pub mod sampler; mod writer; pub use writer::Writer; -#[derive(Clone, Debug, Default, PartialEq)] +pub type Slot = u8; +pub type InlineSamplerIndex = u8; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub enum BindSamplerTarget { + Resource(Slot), + Inline(InlineSamplerIndex), +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct BindTarget { - pub buffer: Option, - pub texture: Option, - pub sampler: Option, + #[cfg_attr(feature = "deserialize", serde(default))] + pub buffer: Option, + #[cfg_attr(feature = "deserialize", serde(default))] + pub texture: Option, + #[cfg_attr(feature = "deserialize", serde(default))] + pub sampler: Option, + #[cfg_attr(feature = "deserialize", serde(default))] pub mutable: bool, } #[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct BindSource { pub stage: crate::ShaderStage, pub group: u32, pub binding: u32, } -pub type BindingMap = FastHashMap; +pub type BindingMap = std::collections::BTreeMap; + +#[derive(Clone, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub struct PushConstantsMap { + #[cfg_attr(feature = "deserialize", serde(default))] + pub vs_buffer: Option, + #[cfg_attr(feature = "deserialize", serde(default))] + pub fs_buffer: Option, + #[cfg_attr(feature = "deserialize", serde(default))] + pub cs_buffer: Option, +} enum ResolvedBinding { BuiltIn(crate::BuiltIn), Attribute(u32), Color(u32), - User { prefix: &'static str, index: u32 }, + User { + prefix: &'static str, + index: u32, + interpolation: ResolvedInterpolation + }, Resource(BindTarget), } +#[derive(Copy, Clone)] +enum ResolvedInterpolation { + CenterPerspective, + CenterNoPerspective, + CentroidPerspective, + CentroidNoPerspective, + SamplePerspective, + SampleNoPerspective, + Flat, +} + // Note: some of these should be removed in favor of proper IR validation. #[derive(Debug, thiserror::Error)] @@ -77,9 +124,13 @@ pub enum Error { } #[derive(Clone, Debug, PartialEq, thiserror::Error)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub enum EntryPointError { #[error("mapping of {0:?} is missing")] MissingBinding(BindSource), + #[error("mapping for push constants at stage {0:?} is missing")] + MissingPushConstants(crate::ShaderStage), } #[derive(Clone, Copy, Debug)] @@ -90,19 +141,22 @@ enum LocationMode { Uniform, } -#[derive(Debug, Clone)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] pub struct Options { /// (Major, Minor) target version of the Metal Shading Language. pub lang_version: (u8, u8), /// Binding model mapping to Metal. pub binding_map: BindingMap, + /// Push constants mapping to Metal. + pub push_constants_map: PushConstantsMap, + /// Samplers to be inlined into the code. + pub inline_samplers: Vec, /// Make it possible to link different stages via SPIRV-Cross. pub spirv_cross_compatibility: bool, /// Don't panic on missing bindings, instead generate invalid MSL. pub fake_missing_bindings: bool, - /// Allow `BuiltIn::PointSize` in the vertex shader. - /// Metal doesn't like this for non-point primitive topologies. - pub allow_point_size: bool, } impl Default for Options { @@ -110,8 +164,27 @@ impl Default for Options { Options { lang_version: (1, 0), binding_map: BindingMap::default(), + push_constants_map: PushConstantsMap::default(), + inline_samplers: Vec::new(), spirv_cross_compatibility: false, fake_missing_bindings: true, + } + } +} + +// A subset of options that are meant to be changed per pipeline. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub struct PipelineOptions { + /// Allow `BuiltIn::PointSize` in the vertex shader. + /// Metal doesn't like this for non-point primitive topologies. + pub allow_point_size: bool, +} + +impl Default for PipelineOptions { + fn default() -> Self { + PipelineOptions { allow_point_size: true, } } @@ -125,21 +198,29 @@ impl Options { ) -> Result { match *binding { crate::Binding::BuiltIn(built_in) => Ok(ResolvedBinding::BuiltIn(built_in)), - crate::Binding::Location(index, _) => match mode { - LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(index)), - LocationMode::FragmentOutput => Ok(ResolvedBinding::Color(index)), + crate::Binding::Location { location, interpolation, sampling } => match mode { + LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)), + LocationMode::FragmentOutput => Ok(ResolvedBinding::Color(location)), LocationMode::Intermediate => Ok(ResolvedBinding::User { prefix: if self.spirv_cross_compatibility { "locn" } else { "loc" }, - index, + index: location, + interpolation: { + // unwrap: The verifier ensures that vertex shader outputs and fragment + // shader inputs always have fully specified interpolation, and that + // sampling is `None` only for Flat interpolation. + let interpolation = interpolation.unwrap(); + let sampling = sampling.unwrap_or(crate::Sampling::Center); + ResolvedInterpolation::from_binding(interpolation, sampling) + } }), LocationMode::Uniform => { log::error!( "Unexpected Binding::Location({}) for the Uniform mode", - index + location ); Err(Error::Validation) } @@ -147,7 +228,7 @@ impl Options { } } - fn resolve_global_binding( + fn resolve_resource_binding( &self, stage: crate::ShaderStage, res_binding: &crate::ResourceBinding, @@ -162,16 +243,52 @@ impl Options { None if self.fake_missing_bindings => Ok(ResolvedBinding::User { prefix: "fake", index: 0, + interpolation: ResolvedInterpolation::CenterPerspective, }), None => Err(EntryPointError::MissingBinding(source)), } } + + fn resolve_push_constants( + &self, + stage: crate::ShaderStage, + ) -> Result { + let slot = match stage { + crate::ShaderStage::Vertex => self.push_constants_map.vs_buffer, + crate::ShaderStage::Fragment => self.push_constants_map.fs_buffer, + crate::ShaderStage::Compute => self.push_constants_map.cs_buffer, + }; + match slot { + Some(slot) => Ok(ResolvedBinding::Resource(BindTarget { + buffer: Some(slot), + texture: None, + sampler: None, + mutable: false, + })), + None if self.fake_missing_bindings => Ok(ResolvedBinding::User { + prefix: "fake", + index: 0, + interpolation: ResolvedInterpolation::CenterPerspective, + }), + None => Err(EntryPointError::MissingPushConstants(stage)), + } + } } impl ResolvedBinding { + fn as_inline_sampler<'a>(&self, options: &'a Options) -> Option<&'a sampler::InlineSampler> { + match *self { + Self::Resource(BindTarget { + sampler: Some(BindSamplerTarget::Inline(index)), + .. + }) => Some(&options.inline_samplers[index as usize]), + _ => None, + } + } + fn try_fmt(&self, out: &mut W) -> Result<(), Error> { match *self { - ResolvedBinding::BuiltIn(built_in) => { + Self::BuiltIn(built_in) => { use crate::BuiltIn as Bi; let name = match built_in { Bi::Position => "position", @@ -194,25 +311,27 @@ impl ResolvedBinding { Bi::WorkGroupId => "threadgroup_position_in_grid", Bi::WorkGroupSize => "dispatch_threads_per_threadgroup", }; - Ok(write!(out, "{}", name)?) + write!(out, "{}", name)?; } - ResolvedBinding::Attribute(index) => Ok(write!(out, "attribute({})", index)?), - ResolvedBinding::Color(index) => Ok(write!(out, "color({})", index)?), - ResolvedBinding::User { prefix, index } => { - Ok(write!(out, "user({}{})", prefix, index)?) + Self::Attribute(index) => write!(out, "attribute({})", index)?, + Self::Color(index) => write!(out, "color({})", index)?, + Self::User { prefix, index, interpolation } => { + write!(out, "user({}{}), ", prefix, index)?; + interpolation.try_fmt(out)?; } - ResolvedBinding::Resource(ref target) => { + Self::Resource(ref target) => { if let Some(id) = target.buffer { - Ok(write!(out, "buffer({})", id)?) + write!(out, "buffer({})", id)?; } else if let Some(id) = target.texture { - Ok(write!(out, "texture({})", id)?) - } else if let Some(id) = target.sampler { - Ok(write!(out, "sampler({})", id)?) + write!(out, "texture({})", id)?; + } else if let Some(BindSamplerTarget::Resource(id)) = target.sampler { + write!(out, "sampler({})", id)?; } else { - Err(Error::UnimplementedBindTarget(target.clone())) + return Err(Error::UnimplementedBindTarget(target.clone())); } } } + Ok(()) } fn try_fmt_decorated(&self, out: &mut W, terminator: &str) -> Result<(), Error> { @@ -224,6 +343,40 @@ impl ResolvedBinding { } } +impl ResolvedInterpolation { + fn from_binding(interpolation: crate::Interpolation, + sampling: crate::Sampling) + -> Self +{ + use crate::Interpolation as I; + use crate::Sampling as S; + + match (interpolation, sampling) { + (I::Perspective, S::Center) => Self::CenterPerspective, + (I::Perspective, S::Centroid) => Self::CentroidPerspective, + (I::Perspective, S::Sample) => Self::SamplePerspective, + (I::Linear, S::Center) => Self::CenterNoPerspective, + (I::Linear, S::Centroid) => Self::CentroidNoPerspective, + (I::Linear, S::Sample) => Self::SampleNoPerspective, + (I::Flat, _) => Self::Flat, + } + } + + fn try_fmt(self, out: &mut W) -> Result<(), Error> { + let identifier = match self { + Self::CenterPerspective => "center_perspective", + Self::CenterNoPerspective => "center_no_perspective", + Self::CentroidPerspective => "centroid_perspective", + Self::CentroidNoPerspective => "centroid_no_perspective", + Self::SamplePerspective => "sample_perspective", + Self::SampleNoPerspective => "sample_no_perspective", + Self::Flat => "flat", + }; + out.write_str(identifier)?; + Ok(()) + } +} + /// Information about a translated module that is required /// for the use of the result. pub struct TranslationInfo { @@ -238,9 +391,10 @@ pub fn write_string( module: &crate::Module, info: &ModuleInfo, options: &Options, + pipeline_options: &PipelineOptions, ) -> Result<(String, TranslationInfo), Error> { let mut w = writer::Writer::new(String::new()); - let info = w.write(module, info, options)?; + let info = w.write(module, info, options, pipeline_options)?; Ok((w.finish(), info)) } diff --git a/third_party/rust/naga/src/back/msl/sampler.rs b/third_party/rust/naga/src/back/msl/sampler.rs new file mode 100644 index 000000000000..c603fac1b10b --- /dev/null +++ b/third_party/rust/naga/src/back/msl/sampler.rs @@ -0,0 +1,175 @@ +#[cfg(feature = "deserialize")] +use serde::Deserialize; +#[cfg(feature = "serialize")] +use serde::Serialize; +use std::{num::NonZeroU32, ops::Range}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum Coord { + Normalized, + Pixel, +} + +impl Default for Coord { + fn default() -> Self { + Self::Normalized + } +} + +impl Coord { + pub fn as_str(&self) -> &'static str { + match *self { + Self::Normalized => "normalized", + Self::Pixel => "pixel", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum Address { + Repeat, + MirroredRepeat, + ClampToEdge, + ClampToZero, + ClampToBorder, +} + +impl Default for Address { + fn default() -> Self { + Self::ClampToEdge + } +} + +impl Address { + pub fn as_str(&self) -> &'static str { + match *self { + Self::Repeat => "repeat", + Self::MirroredRepeat => "mirrored_repeat", + Self::ClampToEdge => "clamp_to_edge", + Self::ClampToZero => "clamp_to_zero", + Self::ClampToBorder => "clamp_to_border", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum BorderColor { + TransparentBlack, + OpaqueBlack, + OpaqueWhite, +} + +impl Default for BorderColor { + fn default() -> Self { + Self::TransparentBlack + } +} + +impl BorderColor { + pub fn as_str(&self) -> &'static str { + match *self { + Self::TransparentBlack => "transparent_black", + Self::OpaqueBlack => "opaque_black", + Self::OpaqueWhite => "opaque_white", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum Filter { + Nearest, + Linear, +} + +impl Filter { + pub fn as_str(&self) -> &'static str { + match *self { + Self::Nearest => "nearest", + Self::Linear => "linear", + } + } +} + +impl Default for Filter { + fn default() -> Self { + Self::Nearest + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum CompareFunc { + Never, + Less, + LessEqual, + Greater, + GreaterEqual, + Equal, + NotEqual, + Always, +} + +impl Default for CompareFunc { + fn default() -> Self { + Self::Never + } +} + +impl CompareFunc { + pub fn as_str(&self) -> &'static str { + match *self { + Self::Never => "never", + Self::Less => "less", + Self::LessEqual => "less_equal", + Self::Greater => "greater", + Self::GreaterEqual => "greater_equal", + Self::Equal => "equal", + Self::NotEqual => "not_equal", + Self::Always => "always", + } + } +} + +#[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub struct InlineSampler { + pub coord: Coord, + pub address: [Address; 3], + pub border_color: BorderColor, + pub mag_filter: Filter, + pub min_filter: Filter, + pub mip_filter: Option, + pub lod_clamp: Option>, + pub max_anisotropy: Option, + pub compare_func: CompareFunc, +} + +impl Eq for InlineSampler {} + +#[allow(clippy::derive_hash_xor_eq)] +impl std::hash::Hash for InlineSampler { + fn hash(&self, hasher: &mut H) { + self.coord.hash(hasher); + self.address.hash(hasher); + self.border_color.hash(hasher); + self.mag_filter.hash(hasher); + self.min_filter.hash(hasher); + self.mip_filter.hash(hasher); + self.lod_clamp + .as_ref() + .map(|range| (range.start.to_bits(), range.end.to_bits())) + .hash(hasher); + self.max_anisotropy.hash(hasher); + self.compare_func.hash(hasher); + } +} diff --git a/third_party/rust/naga/src/back/msl/writer.rs b/third_party/rust/naga/src/back/msl/writer.rs index 5d3f761199ec..79a811482487 100644 --- a/third_party/rust/naga/src/back/msl/writer.rs +++ b/third_party/rust/naga/src/back/msl/writer.rs @@ -1,6 +1,9 @@ -use super::{keywords::RESERVED, Error, LocationMode, Options, TranslationInfo}; +use super::{ + keywords::RESERVED, sampler as sm, Error, LocationMode, Options, PipelineOptions, + TranslationInfo, +}; use crate::{ - arena::Handle, + arena::{Arena, Handle}, proc::{EntryPointIndex, NameKey, Namer, TypeResolution}, valid::{FunctionInfo, GlobalUse, ModuleInfo}, FastHashMap, @@ -13,7 +16,7 @@ use std::{ const NAMESPACE: &str = "metal"; const INDENT: &str = " "; -const BAKE_PREFIX: &str = "_expr"; +const BAKE_PREFIX: &str = "_e"; #[derive(Clone)] struct Level(usize); @@ -28,6 +31,154 @@ impl Display for Level { } } +struct TypeContext<'a> { + handle: Handle, + arena: &'a Arena, + names: &'a FastHashMap, + usage: GlobalUse, + access: crate::StorageAccess, + first_time: bool, +} + +impl<'a> Display for TypeContext<'a> { + fn fmt(&self, out: &mut Formatter<'_>) -> Result<(), FmtError> { + let ty = &self.arena[self.handle]; + if ty.needs_alias() && !self.first_time { + let name = &self.names[&NameKey::Type(self.handle)]; + return write!(out, "{}", name); + } + + match ty.inner { + // work around Metal toolchain bug with `uint` typedef + crate::TypeInner::Scalar { + kind: crate::ScalarKind::Uint, + .. + } => { + write!(out, "metal::uint") + } + crate::TypeInner::Scalar { kind, .. } => { + write!(out, "{}", scalar_kind_string(kind)) + } + crate::TypeInner::Vector { size, kind, .. } => { + write!( + out, + "{}::{}{}", + NAMESPACE, + scalar_kind_string(kind), + vector_size_string(size), + ) + } + crate::TypeInner::Matrix { columns, rows, .. } => { + write!( + out, + "{}::{}{}x{}", + NAMESPACE, + scalar_kind_string(crate::ScalarKind::Float), + vector_size_string(columns), + vector_size_string(rows), + ) + } + crate::TypeInner::Pointer { base, class } => { + let sub = Self { + arena: self.arena, + names: self.names, + handle: base, + usage: self.usage, + access: self.access, + first_time: false, + }; + let class_name = match class.get_name(self.usage) { + Some(name) => name, + None => return Ok(()), + }; + write!(out, "{} {}&", class_name, sub) + } + crate::TypeInner::ValuePointer { + size: None, + kind, + width: _, + class, + } => { + let class_name = match class.get_name(self.usage) { + Some(name) => name, + None => return Ok(()), + }; + write!(out, "{} {}&", class_name, scalar_kind_string(kind),) + } + crate::TypeInner::ValuePointer { + size: Some(size), + kind, + width: _, + class, + } => { + let class_name = match class.get_name(self.usage) { + Some(name) => name, + None => return Ok(()), + }; + write!( + out, + "{} {}::{}{}&", + class_name, + NAMESPACE, + scalar_kind_string(kind), + vector_size_string(size), + ) + } + crate::TypeInner::Array { .. } | crate::TypeInner::Struct { .. } => unreachable!(), + crate::TypeInner::Image { + dim, + arrayed, + class, + } => { + let dim_str = match dim { + crate::ImageDimension::D1 => "1d", + crate::ImageDimension::D2 => "2d", + crate::ImageDimension::D3 => "3d", + crate::ImageDimension::Cube => "cube", + }; + let (texture_str, msaa_str, kind, access) = match class { + crate::ImageClass::Sampled { kind, multi } => { + ("texture", if multi { "_ms" } else { "" }, kind, "sample") + } + crate::ImageClass::Depth => ("depth", "", crate::ScalarKind::Float, "sample"), + crate::ImageClass::Storage(format) => { + let access = if self + .access + .contains(crate::StorageAccess::LOAD | crate::StorageAccess::STORE) + { + "read_write" + } else if self.access.contains(crate::StorageAccess::STORE) { + "write" + } else if self.access.contains(crate::StorageAccess::LOAD) { + "read" + } else { + unreachable!("module is not valid") + }; + ("texture", "", format.into(), access) + } + }; + let base_name = scalar_kind_string(kind); + let array_str = if arrayed { "_array" } else { "" }; + write!( + out, + "{}::{}{}{}{}<{}, {}::access::{}>", + NAMESPACE, + texture_str, + dim_str, + msaa_str, + array_str, + base_name, + NAMESPACE, + access, + ) + } + crate::TypeInner::Sampler { comparison: _ } => { + write!(out, "{}::sampler", NAMESPACE) + } + } + } +} + struct TypedGlobalVariable<'a> { module: &'a crate::Module, names: &'a FastHashMap, @@ -40,7 +191,14 @@ impl<'a> TypedGlobalVariable<'a> { fn try_fmt(&self, out: &mut W) -> Result<(), Error> { let var = &self.module.global_variables[self.handle]; let name = &self.names[&NameKey::GlobalVariable(self.handle)]; - let ty_name = &self.names[&NameKey::Type(var.ty)]; + let ty_name = TypeContext { + handle: var.ty, + arena: &self.module.types, + names: self.names, + usage: self.usage, + access: var.storage_access, + first_time: false, + }; let (space, access, reference) = match var.class.get_name(self.usage) { Some(space) if self.reference => { @@ -71,6 +229,50 @@ impl<'a> TypedGlobalVariable<'a> { } } +struct ConstantContext<'a> { + handle: Handle, + arena: &'a Arena, + names: &'a FastHashMap, + first_time: bool, +} + +impl<'a> Display for ConstantContext<'a> { + fn fmt(&self, out: &mut Formatter<'_>) -> Result<(), FmtError> { + let con = &self.arena[self.handle]; + if con.needs_alias() && !self.first_time { + let name = &self.names[&NameKey::Constant(self.handle)]; + return write!(out, "{}", name); + } + + match con.inner { + crate::ConstantInner::Scalar { value, width: _ } => match value { + crate::ScalarValue::Sint(value) => { + write!(out, "{}", value) + } + crate::ScalarValue::Uint(value) => { + write!(out, "{}u", value) + } + crate::ScalarValue::Float(value) => { + if value.is_infinite() { + let sign = if value.is_sign_negative() { "-" } else { "" }; + write!(out, "{}INFINITY", sign) + } else if value.is_nan() { + write!(out, "NAN") + } else { + let suffix = if value.fract() == 0.0 { ".0" } else { "" }; + + write!(out, "{}{}", value, suffix) + } + } + crate::ScalarValue::Bool(value) => { + write!(out, "{}", value) + } + }, + crate::ConstantInner::Composite { .. } => unreachable!("should be aliased"), + } + } +} + pub struct Writer { out: W, names: FastHashMap, @@ -119,6 +321,7 @@ impl crate::StorageClass { crate::StorageClass::Uniform | crate::StorageClass::Storage | crate::StorageClass::Private + | crate::StorageClass::PushConstant | crate::StorageClass::Handle => true, _ => false, } @@ -140,6 +343,35 @@ impl crate::StorageClass { } } +impl crate::Type { + // Returns `true` if we need to emit an alias for this type. + fn needs_alias(&self) -> bool { + use crate::TypeInner as Ti; + match self.inner { + // value types are concise enough, we only alias them if they are named + Ti::Scalar { .. } + | Ti::Vector { .. } + | Ti::Matrix { .. } + | Ti::Pointer { .. } + | Ti::ValuePointer { .. } => self.name.is_some(), + // composite types are better to be aliased, regardless of the name + Ti::Struct { .. } | Ti::Array { .. } => true, + // handle types may be different, depending on the global var access, so we always inline them + Ti::Image { .. } | Ti::Sampler { .. } => false, + } + } +} + +impl crate::Constant { + // Returns `true` if we need to emit an alias for this constant. + fn needs_alias(&self) -> bool { + match self.inner { + crate::ConstantInner::Scalar { .. } => self.name.is_some(), + crate::ConstantInner::Composite { .. } => true, + } + } +} + enum FunctionOrigin { Handle(Handle), EntryPoint(EntryPointIndex), @@ -150,7 +382,7 @@ struct ExpressionContext<'a> { origin: FunctionOrigin, info: &'a FunctionInfo, module: &'a crate::Module, - options: &'a Options, + pipeline_options: &'a PipelineOptions, } impl<'a> ExpressionContext<'a> { @@ -368,8 +600,16 @@ impl Writer { } } crate::Expression::Constant(handle) => { - let handle_name = &self.names[&NameKey::Constant(handle)]; - write!(self.out, "{}", handle_name)?; + let coco = ConstantContext { + handle, + arena: &context.module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, "{}", coco)?; + } + crate::Expression::Splat { size: _, value } => { + self.put_expression(value, context, is_scoped)?; } crate::Expression::Compose { ty, ref components } => { let inner = &context.module.types[ty].inner; @@ -440,7 +680,9 @@ impl Writer { write!(self.out, "{}", name)?; } crate::Expression::Load { pointer } => { - //write!(self.out, "*")?; + // We don't do any dereferencing with `*` here as pointer arguments to functions + // are done by `&` references and not `*` pointers. These do not need to be + // dereferenced. self.put_expression(pointer, context, is_scoped)?; } crate::Expression::ImageSample { @@ -493,8 +735,13 @@ impl Writer { } } if let Some(constant) = offset { - let offset_str = &self.names[&NameKey::Constant(constant)]; - write!(self.out, ", {}", offset_str)?; + let coco = ConstantContext { + handle: constant, + arena: &context.module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, ", {}", coco)?; } write!(self.out, ")")?; } @@ -616,10 +863,10 @@ impl Writer { .. } => { write!(self.out, "{}::select(", NAMESPACE)?; - self.put_expression(accept, context, true)?; - write!(self.out, ", ")?; self.put_expression(reject, context, true)?; write!(self.out, ", ")?; + self.put_expression(accept, context, true)?; + write!(self.out, ", ")?; self.put_expression(condition, context, true)?; write!(self.out, ")")?; } @@ -654,6 +901,11 @@ impl Writer { } => { use crate::MathFunction as Mf; + let scalar_argument = match *context.resolve_type(arg) { + crate::TypeInner::Scalar { .. } => true, + _ => false, + }; + let fun_name = match fun { // comparison Mf::Abs => "abs", @@ -691,6 +943,7 @@ impl Writer { Mf::Outer => return Err(Error::UnsupportedCall(format!("{:?}", fun))), Mf::Cross => "cross", Mf::Distance => "distance", + Mf::Length if scalar_argument => "abs", Mf::Length => "length", Mf::Normalize => "normalize", Mf::FaceForward => "faceforward", @@ -711,8 +964,16 @@ impl Writer { Mf::ReverseBits => "reverse_bits", }; - write!(self.out, "{}::{}", NAMESPACE, fun_name)?; - self.put_call_parameters(iter::once(arg).chain(arg1).chain(arg2), context)?; + if fun == Mf::Distance && scalar_argument { + write!(self.out, "{}::abs(", NAMESPACE)?; + self.put_expression(arg, context, false)?; + write!(self.out, " - ")?; + self.put_expression(arg1.unwrap(), context, false)?; + write!(self.out, ")")?; + } else { + write!(self.out, "{}::{}", NAMESPACE, fun_name)?; + self.put_call_parameters(iter::once(arg).chain(arg1).chain(arg2), context)?; + } } crate::Expression::As { expr, @@ -737,8 +998,13 @@ impl Writer { size: crate::ArraySize::Constant(const_handle), .. } => { - let size_str = &self.names[&NameKey::Constant(const_handle)]; - write!(self.out, "{}", size_str)?; + let coco = ConstantContext { + handle: const_handle, + arena: &context.module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, "{}", coco)?; } crate::TypeInner::Array { .. } => { return Err(Error::FeatureNotImplemented( @@ -762,10 +1028,7 @@ impl Writer { Some(struct_name) => { let result_ty = context.function.result.as_ref().unwrap().ty; match context.module.types[result_ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { let tmp = "_tmp"; write!(self.out, "{}const auto {} = ", level, tmp)?; self.put_expression(expr_handle, context, true)?; @@ -773,7 +1036,7 @@ impl Writer { write!(self.out, "{}return {} {{", level, struct_name)?; let mut is_first = true; for (index, member) in members.iter().enumerate() { - if !context.options.allow_point_size + if !context.pipeline_options.allow_point_size && member.binding == Some(crate::Binding::BuiltIn(crate::BuiltIn::PointSize)) { @@ -827,7 +1090,14 @@ impl Writer { ) -> Result<(), Error> { match context.info[handle].ty { TypeResolution::Handle(ty_handle) => { - let ty_name = &self.names[&NameKey::Type(ty_handle)]; + let ty_name = TypeContext { + handle: ty_handle, + arena: &context.module.types, + names: &self.names, + usage: GlobalUse::all(), + access: crate::StorageAccess::empty(), + first_time: false, + }; write!(self.out, "{}", ty_name)?; } TypeResolution::Value(crate::TypeInner::Scalar { kind, .. }) => { @@ -842,6 +1112,16 @@ impl Writer { vector_size_string(size) )?; } + TypeResolution::Value(crate::TypeInner::Matrix { columns, rows, .. }) => { + write!( + self.out, + "{}::{}{}x{}", + NAMESPACE, + scalar_kind_string(crate::ScalarKind::Float), + vector_size_string(columns), + vector_size_string(rows), + )?; + } TypeResolution::Value(ref other) => { log::error!("Type {:?} isn't a known local", other); return Err(Error::FeatureNotImplemented("weird local type".to_string())); @@ -915,7 +1195,7 @@ impl Writer { for case in cases.iter() { writeln!(self.out, "{}case {}: {{", lcase, case.value)?; self.put_block(lcase.next(), &case.body, context)?; - if case.fall_through { + if !case.fall_through { writeln!(self.out, "{}break;", lcase.next())?; } writeln!(self.out, "{}}}", lcase)?; @@ -1076,6 +1356,7 @@ impl Writer { module: &crate::Module, info: &ModuleInfo, options: &Options, + pipeline_options: &PipelineOptions, ) -> Result { self.names.clear(); self.namer.reset(module, RESERVED, &mut self.names); @@ -1087,174 +1368,114 @@ impl Writer { self.write_scalar_constants(module)?; self.write_type_defs(module)?; self.write_composite_constants(module)?; - self.write_functions(module, info, options) + self.write_functions(module, info, options, pipeline_options) } fn write_type_defs(&mut self, module: &crate::Module) -> Result<(), Error> { for (handle, ty) in module.types.iter() { + if !ty.needs_alias() { + continue; + } let name = &self.names[&NameKey::Type(handle)]; let global_use = GlobalUse::all(); //TODO match ty.inner { - // work around Metal toolchain bug with `uint` typedef - crate::TypeInner::Scalar { - kind: crate::ScalarKind::Uint, - .. - } => { - writeln!(self.out, "typedef metal::uint {};", name)?; - } - crate::TypeInner::Scalar { kind, .. } => { - writeln!(self.out, "typedef {} {};", scalar_kind_string(kind), name)?; - } - crate::TypeInner::Vector { size, kind, .. } => { - writeln!( - self.out, - "typedef {}::{}{} {};", - NAMESPACE, - scalar_kind_string(kind), - vector_size_string(size), - name - )?; - } - crate::TypeInner::Matrix { columns, rows, .. } => { - writeln!( - self.out, - "typedef {}::{}{}x{} {};", - NAMESPACE, - scalar_kind_string(crate::ScalarKind::Float), - vector_size_string(columns), - vector_size_string(rows), - name - )?; - } - crate::TypeInner::Pointer { base, class } => { - let base_name = &self.names[&NameKey::Type(base)]; - let class_name = match class.get_name(global_use) { - Some(name) => name, - None => continue, - }; - writeln!(self.out, "typedef {} {} *{};", class_name, base_name, name)?; - } - crate::TypeInner::ValuePointer { - size: None, - kind, - width: _, - class, - } => { - let class_name = match class.get_name(global_use) { - Some(name) => name, - None => continue, - }; - writeln!( - self.out, - "typedef {} {} *{};", - class_name, - scalar_kind_string(kind), - name - )?; - } - crate::TypeInner::ValuePointer { - size: Some(size), - kind, - width: _, - class, - } => { - let class_name = match class.get_name(global_use) { - Some(name) => name, - None => continue, - }; - writeln!( - self.out, - "typedef {} {}::{}{} {};", - class_name, - NAMESPACE, - scalar_kind_string(kind), - vector_size_string(size), - name - )?; - } crate::TypeInner::Array { base, size, stride: _, } => { - let base_name = &self.names[&NameKey::Type(base)]; - let size_str = match size { - crate::ArraySize::Constant(const_handle) => { - &self.names[&NameKey::Constant(const_handle)] - } - crate::ArraySize::Dynamic => "1", + let base_name = TypeContext { + handle: base, + arena: &module.types, + names: &self.names, + usage: global_use, + access: crate::StorageAccess::empty(), + first_time: false, }; - writeln!(self.out, "typedef {} {}[{}];", base_name, name, size_str)?; + write!(self.out, "typedef {} {}", base_name, name)?; + match size { + crate::ArraySize::Constant(const_handle) => { + let coco = ConstantContext { + handle: const_handle, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + writeln!(self.out, "[{}];", coco)?; + } + crate::ArraySize::Dynamic => { + writeln!(self.out, "[1];")?; + } + } } - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { writeln!(self.out, "struct {} {{", name)?; + let mut last_offset = 0; for (index, member) in members.iter().enumerate() { + // quick and dirty way to figure out if we need this... + if member.binding.is_none() && member.offset > last_offset { + let pad = member.offset - last_offset; + //TODO: adjust the struct initializers + writeln!(self.out, "{}char _pad{}[{}];", INDENT, index, pad)?; + } + let ty_inner = &module.types[member.ty].inner; + last_offset = member.offset + ty_inner.span(&module.constants); + let is_tight = match members.get(index + 1) { + Some(next) => next.offset == last_offset, + None => false, + }; let member_name = &self.names[&NameKey::StructMember(handle, index as u32)]; - let base_name = &self.names[&NameKey::Type(member.ty)]; - writeln!(self.out, "{}{} {};", INDENT, base_name, member_name)?; + + match *ty_inner { + // for a misaligned vec3, issue a packed vector + crate::TypeInner::Vector { + size: crate::VectorSize::Tri, + kind, + width: 4, + } if member.offset & 0xF != 0 || is_tight => { + writeln!( + self.out, + "{}packed_{}3 {};", + INDENT, + scalar_kind_string(kind), + member_name + )?; + } + _ => { + let base_name = TypeContext { + handle: member.ty, + arena: &module.types, + names: &self.names, + usage: global_use, + access: crate::StorageAccess::empty(), + first_time: false, + }; + writeln!(self.out, "{}{} {};", INDENT, base_name, member_name)?; + + // for 3-component vectors, add one component + if let crate::TypeInner::Vector { + size: crate::VectorSize::Tri, + kind: _, + width, + } = *ty_inner + { + last_offset += width as u32; + } + } + } } writeln!(self.out, "}};")?; } - crate::TypeInner::Image { - dim, - arrayed, - class, - } => { - let dim_str = match dim { - crate::ImageDimension::D1 => "1d", - crate::ImageDimension::D2 => "2d", - crate::ImageDimension::D3 => "3d", - crate::ImageDimension::Cube => "cube", + _ => { + let ty_name = TypeContext { + handle, + arena: &module.types, + names: &self.names, + usage: global_use, + access: crate::StorageAccess::empty(), + first_time: true, }; - let (texture_str, msaa_str, kind, access) = match class { - crate::ImageClass::Sampled { kind, multi } => { - ("texture", if multi { "_ms" } else { "" }, kind, "sample") - } - crate::ImageClass::Depth => { - ("depth", "", crate::ScalarKind::Float, "sample") - } - crate::ImageClass::Storage(format) => { - let (_, global) = module - .global_variables - .iter() - .find(|&(_, ref var)| var.ty == handle) - .expect("Unable to find a global variable using the image type"); - let access = if global - .storage_access - .contains(crate::StorageAccess::LOAD | crate::StorageAccess::STORE) - { - "read_write" - } else if global.storage_access.contains(crate::StorageAccess::STORE) { - "write" - } else if global.storage_access.contains(crate::StorageAccess::LOAD) { - "read" - } else { - return Err(Error::Validation); - }; - ("texture", "", format.into(), access) - } - }; - let base_name = scalar_kind_string(kind); - let array_str = if arrayed { "_array" } else { "" }; - writeln!( - self.out, - "typedef {}::{}{}{}{}<{}, {}::access::{}> {};", - NAMESPACE, - texture_str, - dim_str, - msaa_str, - array_str, - base_name, - NAMESPACE, - access, - name - )?; - } - crate::TypeInner::Sampler { comparison: _ } => { - writeln!(self.out, "typedef {}::sampler {};", NAMESPACE, name)?; + writeln!(self.out, "typedef {} {};", ty_name, name)?; } } } @@ -1267,29 +1488,33 @@ impl Writer { crate::ConstantInner::Scalar { width: _, ref value, - } => { - let name = &self.names[&NameKey::Constant(handle)]; + } if constant.name.is_some() => { + debug_assert!(constant.needs_alias()); write!(self.out, "constexpr constant ")?; match *value { - crate::ScalarValue::Sint(value) => { - write!(self.out, "int {} = {}", name, value)?; + crate::ScalarValue::Sint(_) => { + write!(self.out, "int")?; } - crate::ScalarValue::Uint(value) => { - write!(self.out, "unsigned {} = {}u", name, value)?; + crate::ScalarValue::Uint(_) => { + write!(self.out, "unsigned")?; } - crate::ScalarValue::Float(value) => { - write!(self.out, "float {} = {}", name, value)?; - if value.fract() == 0.0 { - write!(self.out, ".0")?; - } + crate::ScalarValue::Float(_) => { + write!(self.out, "float")?; } - crate::ScalarValue::Bool(value) => { - write!(self.out, "bool {} = {}", name, value)?; + crate::ScalarValue::Bool(_) => { + write!(self.out, "bool")?; } } - writeln!(self.out, ";")?; + let name = &self.names[&NameKey::Constant(handle)]; + let coco = ConstantContext { + handle, + arena: &module.constants, + names: &self.names, + first_time: true, + }; + writeln!(self.out, " {} = {};", name, coco)?; } - crate::ConstantInner::Composite { .. } => {} + _ => {} } } Ok(()) @@ -1300,13 +1525,26 @@ impl Writer { match constant.inner { crate::ConstantInner::Scalar { .. } => {} crate::ConstantInner::Composite { ty, ref components } => { + debug_assert!(constant.needs_alias()); let name = &self.names[&NameKey::Constant(handle)]; - let ty_name = &self.names[&NameKey::Type(ty)]; - write!(self.out, "constexpr constant {} {} = {{", ty_name, name,)?; + let ty_name = TypeContext { + handle: ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; + write!(self.out, "constant {} {} = {{", ty_name, name,)?; for (i, &sub_handle) in components.iter().enumerate() { let separator = if i != 0 { ", " } else { "" }; - let sub_name = &self.names[&NameKey::Constant(sub_handle)]; - write!(self.out, "{}{}", separator, sub_name)?; + let coco = ConstantContext { + handle: sub_handle, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, "{}{}", separator, coco)?; } writeln!(self.out, "}};")?; } @@ -1315,12 +1553,91 @@ impl Writer { Ok(()) } + fn put_inline_sampler_properties( + &mut self, + level: Level, + sampler: &sm::InlineSampler, + ) -> Result<(), Error> { + for (&letter, address) in ['s', 't', 'r'].iter().zip(sampler.address.iter()) { + writeln!( + self.out, + "{}{}::{}_address::{},", + level, + NAMESPACE, + letter, + address.as_str(), + )?; + } + writeln!( + self.out, + "{}{}::mag_filter::{},", + level, + NAMESPACE, + sampler.mag_filter.as_str(), + )?; + writeln!( + self.out, + "{}{}::min_filter::{},", + level, + NAMESPACE, + sampler.min_filter.as_str(), + )?; + if let Some(filter) = sampler.mip_filter { + writeln!( + self.out, + "{}{}::mip_filter::{},", + level, + NAMESPACE, + filter.as_str(), + )?; + } + // avoid setting it on platforms that don't support it + if sampler.border_color != sm::BorderColor::TransparentBlack { + writeln!( + self.out, + "{}{}::border_color::{},", + level, + NAMESPACE, + sampler.border_color.as_str(), + )?; + } + //TODO: I'm not able to feed this in a way that MSL likes: + //>error: use of undeclared identifier 'lod_clamp' + //>error: no member named 'max_anisotropy' in namespace 'metal' + if false { + if let Some(ref lod) = sampler.lod_clamp { + writeln!(self.out, "{}lod_clamp({},{}),", level, lod.start, lod.end,)?; + } + if let Some(aniso) = sampler.max_anisotropy { + writeln!(self.out, "{}max_anisotropy({}),", level, aniso.get(),)?; + } + } + if sampler.compare_func != sm::CompareFunc::Never { + writeln!( + self.out, + "{}{}::compare_func::{},", + level, + NAMESPACE, + sampler.compare_func.as_str(), + )?; + } + writeln!( + self.out, + "{}{}::coord::{}", + level, + NAMESPACE, + sampler.coord.as_str() + )?; + Ok(()) + } + // Returns the array of mapped entry point names. fn write_functions( &mut self, module: &crate::Module, mod_info: &ModuleInfo, options: &Options, + pipeline_options: &PipelineOptions, ) -> Result { let mut pass_through_globals = Vec::new(); for (fun_handle, fun) in module.functions.iter() { @@ -1332,16 +1649,36 @@ impl Writer { } } + writeln!(self.out)?; let fun_name = &self.names[&NameKey::Function(fun_handle)]; - let result_type_name = match fun.result { - Some(ref result) => &self.names[&NameKey::Type(result.ty)], - None => "void", - }; - writeln!(self.out, "{} {}(", result_type_name, fun_name)?; + match fun.result { + Some(ref result) => { + let ty_name = TypeContext { + handle: result.ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; + write!(self.out, "{}", ty_name)?; + } + None => { + write!(self.out, "void")?; + } + } + writeln!(self.out, " {}(", fun_name)?; for (index, arg) in fun.arguments.iter().enumerate() { let name = &self.names[&NameKey::FunctionArgument(fun_handle, index as u32)]; - let param_type_name = &self.names[&NameKey::Type(arg.ty)]; + let param_type_name = TypeContext { + handle: arg.ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; let separator = separate(!pass_through_globals.is_empty() || index + 1 != fun.arguments.len()); writeln!( @@ -1366,12 +1703,24 @@ impl Writer { writeln!(self.out, ") {{")?; for (local_handle, local) in fun.local_variables.iter() { - let ty_name = &self.names[&NameKey::Type(local.ty)]; + let ty_name = TypeContext { + handle: local.ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; let local_name = &self.names[&NameKey::FunctionLocal(fun_handle, local_handle)]; write!(self.out, "{}{} {}", INDENT, ty_name, local_name)?; if let Some(value) = local.init { - let value_str = &self.names[&NameKey::Constant(value)]; - write!(self.out, " = {}", value_str)?; + let coco = ConstantContext { + handle: value, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, " = {}", coco)?; } writeln!(self.out, ";")?; } @@ -1382,7 +1731,7 @@ impl Writer { origin: FunctionOrigin::Handle(fun_handle), info: fun_info, module, - options, + pipeline_options, }, mod_info, result_struct: None, @@ -1390,7 +1739,6 @@ impl Writer { self.named_expressions.clear(); self.put_block(Level(1), &fun.body, &context)?; writeln!(self.out, "}}")?; - writeln!(self.out)?; } let mut info = TranslationInfo { @@ -1407,7 +1755,12 @@ impl Writer { .find_map(|(var_handle, var)| { if !fun_info[var_handle].is_empty() { if let Some(ref br) = var.binding { - if let Err(e) = options.resolve_global_binding(ep.stage, br) { + if let Err(e) = options.resolve_resource_binding(ep.stage, br) { + return Some(e); + } + } + if var.class == crate::StorageClass::PushConstant { + if let Err(e) = options.resolve_push_constants(ep.stage) { return Some(e); } } @@ -1420,6 +1773,7 @@ impl Writer { } } + writeln!(self.out)?; let fun_name = &self.names[&NameKey::EntryPoint(ep_index as _)]; info.entry_point_names.push(Ok(fun_name.clone())); @@ -1445,10 +1799,7 @@ impl Writer { let mut argument_members = Vec::new(); for (arg_index, arg) in fun.arguments.iter().enumerate() { match module.types[arg.ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { for (member_index, member) in members.iter().enumerate() { argument_members.push(( NameKey::StructMember(arg.ty, member_index as u32), @@ -1470,14 +1821,21 @@ impl Writer { writeln!(self.out, "struct {} {{", stage_in_name)?; for &(ref name_key, ty, binding) in argument_members.iter() { let binding = match binding { - Some(ref binding @ &crate::Binding::Location(..)) => binding, + Some(ref binding @ &crate::Binding::Location { .. }) => binding, _ => continue, }; varying_count += 1; let name = &self.names[&name_key]; - let type_name = &self.names[&NameKey::Type(ty)]; + let ty_name = TypeContext { + handle: ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; let resolved = options.resolve_local_binding(binding, in_mode)?; - write!(self.out, "{}{} {}", INDENT, type_name, name)?; + write!(self.out, "{}{} {}", INDENT, ty_name, name)?; resolved.try_fmt_decorated(&mut self.out, "")?; writeln!(self.out, ";")?; } @@ -1488,10 +1846,8 @@ impl Writer { let result_type_name = match fun.result { Some(ref result) => { let mut result_members = Vec::new(); - if let crate::TypeInner::Struct { - block: _, - ref members, - } = module.types[result.ty].inner + if let crate::TypeInner::Struct { ref members, .. } = + module.types[result.ty].inner { for (member_index, member) in members.iter().enumerate() { result_members.push(( @@ -1509,15 +1865,22 @@ impl Writer { } writeln!(self.out, "struct {} {{", stage_out_name)?; for (name, ty, binding) in result_members { - let type_name = &self.names[&NameKey::Type(ty)]; + let ty_name = TypeContext { + handle: ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; let binding = binding.ok_or(Error::Validation)?; - if !options.allow_point_size + if !pipeline_options.allow_point_size && *binding == crate::Binding::BuiltIn(crate::BuiltIn::PointSize) { continue; } let resolved = options.resolve_local_binding(binding, out_mode)?; - write!(self.out, "{}{} {}", INDENT, type_name, name)?; + write!(self.out, "{}{} {}", INDENT, ty_name, name)?; resolved.try_fmt_decorated(&mut self.out, "")?; writeln!(self.out, ";")?; } @@ -1543,7 +1906,14 @@ impl Writer { _ => continue, }; let name = &self.names[&name_key]; - let type_name = &self.names[&NameKey::Type(ty)]; + let ty_name = TypeContext { + handle: ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; let resolved = options.resolve_local_binding(binding, in_mode)?; let separator = if is_first_argument { is_first_argument = false; @@ -1551,7 +1921,7 @@ impl Writer { } else { ',' }; - write!(self.out, "{} {} {}", separator, type_name, name)?; + write!(self.out, "{} {} {}", separator, ty_name, name)?; resolved.try_fmt_decorated(&mut self.out, "\n")?; } for (handle, var) in module.global_variables.iter() { @@ -1559,6 +1929,23 @@ impl Writer { if usage.is_empty() || var.class == crate::StorageClass::Private { continue; } + // the resolves have already been checked for `!fake_missing_bindings` case + let resolved = match var.class { + crate::StorageClass::PushConstant => { + options.resolve_push_constants(ep.stage).ok() + } + crate::StorageClass::WorkGroup => None, + _ => options + .resolve_resource_binding(ep.stage, var.binding.as_ref().unwrap()) + .ok(), + }; + if let Some(ref resolved) = resolved { + // Inline samplers are be defined in the EP body + if resolved.as_inline_sampler(options).is_some() { + continue; + } + } + let tyvar = TypedGlobalVariable { module, names: &self.names, @@ -1574,13 +1961,17 @@ impl Writer { }; write!(self.out, "{} ", separator)?; tyvar.try_fmt(&mut self.out)?; - if let Some(ref binding) = var.binding { - let resolved = options.resolve_global_binding(ep.stage, binding).unwrap(); + if let Some(resolved) = resolved { resolved.try_fmt_decorated(&mut self.out, "")?; } if let Some(value) = var.init { - let value_str = &self.names[&NameKey::Constant(value)]; - write!(self.out, " = {}", value_str)?; + let coco = ConstantContext { + handle: value, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, " = {}", coco)?; } writeln!(self.out)?; } @@ -1592,23 +1983,47 @@ impl Writer { // so we put them here, just like the locals. for (handle, var) in module.global_variables.iter() { let usage = fun_info[handle]; - if usage.is_empty() || var.class != crate::StorageClass::Private { + if usage.is_empty() { continue; } - let tyvar = TypedGlobalVariable { - module, - names: &self.names, - handle, - usage, - reference: false, - }; - write!(self.out, "{}", INDENT)?; - tyvar.try_fmt(&mut self.out)?; - let value_str = match var.init { - Some(value) => &self.names[&NameKey::Constant(value)], - None => "{}", - }; - writeln!(self.out, " = {};", value_str)?; + if var.class == crate::StorageClass::Private { + let tyvar = TypedGlobalVariable { + module, + names: &self.names, + handle, + usage, + reference: false, + }; + write!(self.out, "{}", INDENT)?; + tyvar.try_fmt(&mut self.out)?; + match var.init { + Some(value) => { + let coco = ConstantContext { + handle: value, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + writeln!(self.out, " = {};", coco)?; + } + None => { + writeln!(self.out, " = {{}};")?; + } + }; + } else if let Some(ref binding) = var.binding { + // write an inline sampler + let resolved = options.resolve_resource_binding(ep.stage, binding).unwrap(); + if let Some(sampler) = resolved.as_inline_sampler(options) { + let name = &self.names[&NameKey::GlobalVariable(handle)]; + writeln!( + self.out, + "{}constexpr {}::sampler {}(", + INDENT, NAMESPACE, name + )?; + self.put_inline_sampler_properties(Level(2), sampler)?; + writeln!(self.out, "{});", INDENT)?; + } + } } // Now refactor the inputs in a way that the rest of the code expects @@ -1616,10 +2031,7 @@ impl Writer { let arg_name = &self.names[&NameKey::EntryPointArgument(ep_index as _, arg_index as u32)]; match module.types[arg.ty].inner { - crate::TypeInner::Struct { - block: _, - ref members, - } => { + crate::TypeInner::Struct { ref members, .. } => { let struct_name = &self.names[&NameKey::Type(arg.ty)]; write!( self.out, @@ -1632,7 +2044,7 @@ impl Writer { if member_index != 0 { write!(self.out, ", ")?; } - if let Some(crate::Binding::Location(..)) = member.binding { + if let Some(crate::Binding::Location { .. }) = member.binding { write!(self.out, "{}.", varyings_member_name)?; } write!(self.out, "{}", name)?; @@ -1640,7 +2052,7 @@ impl Writer { writeln!(self.out, " }};")?; } _ => { - if let Some(crate::Binding::Location(..)) = arg.binding { + if let Some(crate::Binding::Location { .. }) = arg.binding { writeln!( self.out, "{}const auto {} = {}.{};", @@ -1655,11 +2067,23 @@ impl Writer { //TODO: we can postpone this till the relevant expressions are emitted for (local_handle, local) in fun.local_variables.iter() { let name = &self.names[&NameKey::EntryPointLocal(ep_index as _, local_handle)]; - let ty_name = &self.names[&NameKey::Type(local.ty)]; + let ty_name = TypeContext { + handle: local.ty, + arena: &module.types, + names: &self.names, + usage: GlobalUse::empty(), + access: crate::StorageAccess::empty(), + first_time: false, + }; write!(self.out, "{}{} {}", INDENT, ty_name, name)?; if let Some(value) = local.init { - let value_str = &self.names[&NameKey::Constant(value)]; - write!(self.out, " = {}", value_str)?; + let coco = ConstantContext { + handle: value, + arena: &module.constants, + names: &self.names, + first_time: false, + }; + write!(self.out, " = {}", coco)?; } writeln!(self.out, ";")?; } @@ -1670,7 +2094,7 @@ impl Writer { origin: FunctionOrigin::EntryPoint(ep_index as _), info: fun_info, module, - options, + pipeline_options, }, mod_info, result_struct: Some(&stage_out_name), @@ -1722,7 +2146,9 @@ fn test_stack_size() { .unwrap(); // process the module let mut writer = Writer::new(String::new()); - writer.write(&module, &info, &Default::default()).unwrap(); + writer + .write(&module, &info, &Default::default(), &Default::default()) + .unwrap(); { // check expression stack @@ -1733,8 +2159,8 @@ fn test_stack_size() { } let stack_size = addresses.end - addresses.start; // check the size (in debug only) - // last observed macOS value: 18768 - if stack_size < 18000 || stack_size > 20000 { + // last observed macOS value: 20336 + if stack_size < 19000 || stack_size > 21000 { panic!("`put_expression` stack size {} has changed!", stack_size); } } diff --git a/third_party/rust/naga/src/back/spv/instructions.rs b/third_party/rust/naga/src/back/spv/instructions.rs index 18de62be0492..90f8b0128eb0 100644 --- a/third_party/rust/naga/src/back/spv/instructions.rs +++ b/third_party/rust/naga/src/back/spv/instructions.rs @@ -433,12 +433,12 @@ impl super::Instruction { } pub(super) fn store( - pointer_type_id: Word, + pointer_id: Word, object_id: Word, memory_access: Option, ) -> Self { let mut instruction = Self::new(Op::Store); - instruction.add_operand(pointer_type_id); + instruction.add_operand(pointer_id); instruction.add_operand(object_id); if let Some(memory_access) = memory_access { diff --git a/third_party/rust/naga/src/back/spv/writer.rs b/third_party/rust/naga/src/back/spv/writer.rs index 8a375cfd73be..39df6f223ab0 100644 --- a/third_party/rust/naga/src/back/spv/writer.rs +++ b/third_party/rust/naga/src/back/spv/writer.rs @@ -3,7 +3,7 @@ use super::{ }; use crate::{ arena::{Arena, Handle}, - proc::{Layouter, TypeResolution}, + proc::TypeResolution, valid::{FunctionInfo, ModuleInfo}, }; use spirv::Word; @@ -70,6 +70,7 @@ struct Function { signature: Option, parameters: Vec, variables: crate::FastHashMap, LocalVariable>, + internal_variables: Vec, blocks: Vec, entry_point_context: Option, } @@ -86,6 +87,9 @@ impl Function { for local_var in self.variables.values() { local_var.instruction.to_words(sink); } + for internal_var in self.internal_variables.iter() { + internal_var.instruction.to_words(sink); + } } for instruction in block.body.iter() { instruction.to_words(sink); @@ -275,7 +279,8 @@ pub struct Writer { global_variables: Vec, cached: CachedExpressions, gl450_ext_inst_id: Word, - temp_chain: Vec, + // Just a temporary list of SPIR-V ids + temp_list: Vec, } impl Writer { @@ -307,7 +312,7 @@ impl Writer { global_variables: Vec::new(), cached: CachedExpressions::default(), gl450_ext_inst_id, - temp_chain: Vec::new(), + temp_list: Vec::new(), }) } @@ -338,6 +343,20 @@ impl Writer { } } + fn get_expression_type_id( + &mut self, + arena: &Arena, + tr: &TypeResolution, + ) -> Result { + let lookup_ty = match *tr { + TypeResolution::Handle(ty_handle) => LookupType::Handle(ty_handle), + TypeResolution::Value(ref inner) => { + LookupType::Local(self.physical_layout.make_local(inner).unwrap()) + } + }; + self.get_type_id(arena, lookup_ty) + } + fn get_pointer_id( &mut self, arena: &Arena, @@ -398,6 +417,10 @@ impl Writer { Ok(id) } + fn decorate(&mut self, id: Word, decoration: spirv::Decoration, operands: &[Word]) { + self.annotations.push(Instruction::decorate(id, decoration, operands)); + } + fn write_function( &mut self, ir_function: &crate::Function, @@ -455,10 +478,8 @@ impl Writer { .body .push(Instruction::load(argument_type_id, id, varying_id, None)); id - } else if let crate::TypeInner::Struct { - block: _, - ref members, - } = ir_module.types[argument.ty].inner + } else if let crate::TypeInner::Struct { ref members, .. } = + ir_module.types[argument.ty].inner { let struct_id = self.id_gen.next(); let mut constituent_ids = Vec::with_capacity(members.len()); @@ -509,10 +530,8 @@ impl Writer { type_id, built_in: binding.to_built_in(), }); - } else if let crate::TypeInner::Struct { - block: _, - ref members, - } = ir_module.types[result.ty].inner + } else if let crate::TypeInner::Struct { ref members, .. } = + ir_module.types[result.ty].inner { for member in members { let type_id = @@ -652,11 +671,6 @@ impl Writer { }; self.check(exec_model.required_capabilities())?; - if self.flags.contains(WriterFlags::DEBUG) { - self.debugs - .push(Instruction::name(function_id, &entry_point.name)); - } - Ok(Instruction::entry_point( exec_model, function_id, @@ -760,10 +774,10 @@ impl Writer { fn write_type_declaration_arena( &mut self, arena: &Arena, - layouter: &Layouter, handle: Handle, ) -> Result { let ty = &arena[handle]; + let decorate_layout = true; //TODO? let id = if let Some(local) = self.physical_layout.make_local(&ty.inner) { match self.lookup_type.entry(LookupType::Local(local)) { @@ -790,6 +804,8 @@ impl Writer { } } + use spirv::Decoration; + let instruction = match ty.inner { crate::TypeInner::Scalar { kind, width } => self.write_scalar(id, kind, width), crate::TypeInner::Vector { size, kind, width } => { @@ -843,12 +859,8 @@ impl Writer { } crate::TypeInner::Sampler { comparison: _ } => Instruction::type_sampler(id), crate::TypeInner::Array { base, size, stride } => { - if let Some(array_stride) = stride { - self.annotations.push(Instruction::decorate( - id, - spirv::Decoration::ArrayStride, - &[array_stride.get()], - )); + if decorate_layout { + self.decorate(id, Decoration::ArrayStride, &[stride]); } let type_id = self.get_type_id(arena, LookupType::Handle(base))?; @@ -860,23 +872,25 @@ impl Writer { crate::ArraySize::Dynamic => Instruction::type_runtime_array(id, type_id), } } - crate::TypeInner::Struct { block, ref members } => { - if block { - self.annotations - .push(Instruction::decorate(id, spirv::Decoration::Block, &[])); + crate::TypeInner::Struct { + ref level, + ref members, + span: _, + } => { + if let crate::StructLevel::Root = *level { + self.decorate(id, Decoration::Block, &[]); } - let mut current_offset = 0; let mut member_ids = Vec::with_capacity(members.len()); for (index, member) in members.iter().enumerate() { - let (placement, _) = layouter.member_placement(current_offset, member); - self.annotations.push(Instruction::member_decorate( - id, - index as u32, - spirv::Decoration::Offset, - &[placement.start], - )); - current_offset = placement.end; + if decorate_layout { + self.annotations.push(Instruction::member_decorate( + id, + index as u32, + Decoration::Offset, + &[member.offset], + )); + } if self.flags.contains(WriterFlags::DEBUG) { if let Some(ref name) = member.name { @@ -885,11 +899,17 @@ impl Writer { } } + // The matrix decorations also go on arrays of matrices, + // so lets check this first. + let member_array_subty_inner = match arena[member.ty].inner { + crate::TypeInner::Array { base, .. } => &arena[base].inner, + ref other => other, + }; if let crate::TypeInner::Matrix { columns, rows: _, width, - } = arena[member.ty].inner + } = *member_array_subty_inner { let byte_stride = match columns { crate::VectorSize::Bi => 2 * width, @@ -898,13 +918,13 @@ impl Writer { self.annotations.push(Instruction::member_decorate( id, index as u32, - spirv::Decoration::ColMajor, + Decoration::ColMajor, &[], )); self.annotations.push(Instruction::member_decorate( id, index as u32, - spirv::Decoration::MatrixStride, + Decoration::MatrixStride, &[byte_stride as u32], )); } @@ -1067,23 +1087,32 @@ impl Writer { } } + use spirv::{BuiltIn, Decoration}; + match *binding { - crate::Binding::Location(location, interpolation) => { - self.annotations.push(Instruction::decorate( - id, - spirv::Decoration::Location, - &[location], - )); - let interp_decoration = match interpolation { - Some(crate::Interpolation::Linear) => Some(spirv::Decoration::NoPerspective), - Some(crate::Interpolation::Flat) => Some(spirv::Decoration::Flat), - Some(crate::Interpolation::Centroid) => Some(spirv::Decoration::Centroid), - Some(crate::Interpolation::Sample) => Some(spirv::Decoration::Sample), - Some(crate::Interpolation::Perspective) | None => None, - }; - if let Some(decoration) = interp_decoration { - self.annotations - .push(Instruction::decorate(id, decoration, &[])); + crate::Binding::Location { location, interpolation, sampling } => { + self.decorate(id, Decoration::Location, &[location]); + + match interpolation { + // Perspective-correct interpolation is the default in SPIR-V. + None | Some(crate::Interpolation::Perspective) => (), + Some(crate::Interpolation::Flat) => { + self.decorate(id, Decoration::Flat, &[]); + } + Some(crate::Interpolation::Linear) => { + self.decorate(id, Decoration::NoPerspective, &[]); + } + } + + match sampling { + // Center sampling is the default in SPIR-V. + None | Some(crate::Sampling::Center) => (), + Some(crate::Sampling::Centroid) => { + self.decorate(id, Decoration::Centroid, &[]); + } + Some(crate::Sampling::Sample) => { + self.decorate(id, Decoration::Sample, &[]); + } } } crate::Binding::BuiltIn(built_in) => { @@ -1091,36 +1120,32 @@ impl Writer { let built_in = match built_in { Bi::Position => { if class == spirv::StorageClass::Output { - spirv::BuiltIn::Position + BuiltIn::Position } else { - spirv::BuiltIn::FragCoord + BuiltIn::FragCoord } } // vertex - Bi::BaseInstance => spirv::BuiltIn::BaseInstance, - Bi::BaseVertex => spirv::BuiltIn::BaseVertex, - Bi::ClipDistance => spirv::BuiltIn::ClipDistance, - Bi::InstanceIndex => spirv::BuiltIn::InstanceIndex, - Bi::PointSize => spirv::BuiltIn::PointSize, - Bi::VertexIndex => spirv::BuiltIn::VertexIndex, + Bi::BaseInstance => BuiltIn::BaseInstance, + Bi::BaseVertex => BuiltIn::BaseVertex, + Bi::ClipDistance => BuiltIn::ClipDistance, + Bi::InstanceIndex => BuiltIn::InstanceIndex, + Bi::PointSize => BuiltIn::PointSize, + Bi::VertexIndex => BuiltIn::VertexIndex, // fragment - Bi::FragDepth => spirv::BuiltIn::FragDepth, - Bi::FrontFacing => spirv::BuiltIn::FrontFacing, - Bi::SampleIndex => spirv::BuiltIn::SampleId, - Bi::SampleMask => spirv::BuiltIn::SampleMask, + Bi::FragDepth => BuiltIn::FragDepth, + Bi::FrontFacing => BuiltIn::FrontFacing, + Bi::SampleIndex => BuiltIn::SampleId, + Bi::SampleMask => BuiltIn::SampleMask, // compute - Bi::GlobalInvocationId => spirv::BuiltIn::GlobalInvocationId, - Bi::LocalInvocationId => spirv::BuiltIn::LocalInvocationId, - Bi::LocalInvocationIndex => spirv::BuiltIn::LocalInvocationIndex, - Bi::WorkGroupId => spirv::BuiltIn::WorkgroupId, - Bi::WorkGroupSize => spirv::BuiltIn::WorkgroupSize, + Bi::GlobalInvocationId => BuiltIn::GlobalInvocationId, + Bi::LocalInvocationId => BuiltIn::LocalInvocationId, + Bi::LocalInvocationIndex => BuiltIn::LocalInvocationIndex, + Bi::WorkGroupId => BuiltIn::WorkgroupId, + Bi::WorkGroupSize => BuiltIn::WorkgroupSize, }; - self.annotations.push(Instruction::decorate( - id, - spirv::Decoration::BuiltIn, - &[built_in as u32], - )); + self.decorate(id, Decoration::BuiltIn, &[built_in as u32]); } } @@ -1149,27 +1174,20 @@ impl Writer { } } + use spirv::Decoration; + let access_decoration = match global_variable.storage_access { - crate::StorageAccess::LOAD => Some(spirv::Decoration::NonWritable), - crate::StorageAccess::STORE => Some(spirv::Decoration::NonReadable), + crate::StorageAccess::LOAD => Some(Decoration::NonWritable), + crate::StorageAccess::STORE => Some(Decoration::NonReadable), _ => None, }; if let Some(decoration) = access_decoration { - self.annotations - .push(Instruction::decorate(id, decoration, &[])); + self.decorate(id, decoration, &[]); } if let Some(ref res_binding) = global_variable.binding { - self.annotations.push(Instruction::decorate( - id, - spirv::Decoration::DescriptorSet, - &[res_binding.group], - )); - self.annotations.push(Instruction::decorate( - id, - spirv::Decoration::Binding, - &[res_binding.binding], - )); + self.decorate(id, Decoration::DescriptorSet, &[res_binding.group]); + self.decorate(id, Decoration::Binding, &[res_binding.binding]); } // TODO Initializer is optional and not (yet) included in the IR @@ -1196,21 +1214,6 @@ impl Writer { } } - fn write_composite_construct( - &mut self, - base_type_id: Word, - constituent_ids: &[Word], - block: &mut Block, - ) -> Word { - let id = self.id_gen.next(); - block.body.push(Instruction::composite_construct( - base_type_id, - id, - constituent_ids, - )); - id - } - fn write_texture_coordinates( &mut self, ir_module: &crate::Module, @@ -1282,33 +1285,86 @@ impl Writer { }), )?; - self.write_composite_construct( + let id = self.id_gen.next(); + block.body.push(Instruction::composite_construct( extended_coordinate_type_id, + id, &constituent_ids[..size as usize], - block, - ) + )); + id } else { coordinate_id }) } - /// Cache an expression for a value. - fn cache_expression_value<'a>( + #[allow(clippy::too_many_arguments)] + fn promote_access_expression_to_variable( &mut self, - ir_module: &'a crate::Module, + ir_types: &Arena, + result_type_id: Word, + container_id: Word, + container_resolution: &TypeResolution, + index_id: Word, + element_ty: Handle, + block: &mut Block, + ) -> Result<(Word, LocalVariable), Error> { + let container_type_id = self.get_expression_type_id(ir_types, container_resolution)?; + let pointer_type_id = self.id_gen.next(); + Instruction::type_pointer( + pointer_type_id, + spirv::StorageClass::Function, + container_type_id, + ) + .to_words(&mut self.logical_layout.declarations); + + let variable = { + let id = self.id_gen.next(); + LocalVariable { + id, + instruction: Instruction::variable( + pointer_type_id, + id, + spirv::StorageClass::Function, + None, + ), + } + }; + block + .body + .push(Instruction::store(variable.id, container_id, None)); + + let element_pointer_id = self.id_gen.next(); + let element_pointer_type_id = + self.get_pointer_id(ir_types, element_ty, spirv::StorageClass::Function)?; + block.body.push(Instruction::access_chain( + element_pointer_type_id, + element_pointer_id, + variable.id, + &[index_id], + )); + let id = self.id_gen.next(); + block.body.push(Instruction::load( + result_type_id, + id, + element_pointer_id, + None, + )); + + Ok((id, variable)) + } + + /// Cache an expression for a value. + fn cache_expression_value( + &mut self, + ir_module: &crate::Module, ir_function: &crate::Function, fun_info: &FunctionInfo, expr_handle: Handle, block: &mut Block, function: &mut Function, ) -> Result<(), Error> { - let result_lookup_ty = match fun_info[expr_handle].ty { - TypeResolution::Handle(ty_handle) => LookupType::Handle(ty_handle), - TypeResolution::Value(ref inner) => { - LookupType::Local(self.physical_layout.make_local(inner).unwrap()) - } - }; - let result_type_id = self.get_type_id(&ir_module.types, result_lookup_ty)?; + let result_type_id = + self.get_expression_type_id(&ir_module.types, &fun_info[expr_handle].ty)?; let id = match ir_function.expressions[expr_handle] { crate::Expression::Access { base, index } => { @@ -1322,10 +1378,10 @@ impl Writer { 0 } else { let index_id = self.cached[index]; + let base_id = self.cached[base]; match *fun_info[base].ty.inner_with(&ir_module.types) { crate::TypeInner::Vector { .. } => { let id = self.id_gen.next(); - let base_id = self.cached[base]; block.body.push(Instruction::vector_extract_dynamic( result_type_id, id, @@ -1334,7 +1390,21 @@ impl Writer { )); id } - //TODO: support `crate::TypeInner::Array { .. }` ? + crate::TypeInner::Array { + base: ty_element, .. + } => { + let (id, variable) = self.promote_access_expression_to_variable( + &ir_module.types, + result_type_id, + base_id, + &fun_info[base].ty, + index_id, + ty_element, + block, + )?; + function.internal_variables.push(variable); + id + } ref other => { log::error!("Unable to access {:?}", other); return Err(Error::FeatureNotImplemented("access for type")); @@ -1376,17 +1446,35 @@ impl Writer { } crate::Expression::GlobalVariable(handle) => self.global_variables[handle.index()].id, crate::Expression::Constant(handle) => self.constant_ids[handle.index()], + crate::Expression::Splat { size, value } => { + let value_id = self.cached[value]; + self.temp_list.clear(); + self.temp_list.resize(size as usize, value_id); + + let id = self.id_gen.next(); + block.body.push(Instruction::composite_construct( + result_type_id, + id, + &self.temp_list, + )); + id + } crate::Expression::Compose { ty: _, ref components, } => { - //TODO: avoid allocation - let mut constituent_ids = Vec::with_capacity(components.len()); + self.temp_list.clear(); for &component in components { - let component_id = self.cached[component]; - constituent_ids.push(component_id); + self.temp_list.push(self.cached[component]); } - self.write_composite_construct(result_type_id, &constituent_ids, block) + + let id = self.id_gen.next(); + block.body.push(Instruction::composite_construct( + result_type_id, + id, + &self.temp_list, + )); + id } crate::Expression::Unary { op, expr } => { let id = self.id_gen.next(); @@ -1985,8 +2073,10 @@ impl Writer { }); id } - ref other => { - log::error!("unimplemented {:?}", other); + crate::Expression::ImageQuery { .. } + | crate::Expression::Relational { .. } + | crate::Expression::ArrayLength(_) => { + log::error!("unimplemented {:?}", ir_function.expressions[expr_handle]); return Err(Error::FeatureNotImplemented("expression")); } }; @@ -2013,17 +2103,17 @@ impl Writer { }; let result_type_id = self.get_type_id(&ir_module.types, result_lookup_ty)?; - self.temp_chain.clear(); + self.temp_list.clear(); let (root_id, class) = loop { expr_handle = match ir_function.expressions[expr_handle] { crate::Expression::Access { base, index } => { let index_id = self.cached[index]; - self.temp_chain.push(index_id); + self.temp_list.push(index_id); base } crate::Expression::AccessIndex { base, index } => { let const_id = self.get_index_constant(index, &ir_module.types)?; - self.temp_chain.push(const_id); + self.temp_list.push(const_id); base } crate::Expression::GlobalVariable(handle) => { @@ -2038,16 +2128,16 @@ impl Writer { } }; - let id = if self.temp_chain.is_empty() { + let id = if self.temp_list.is_empty() { root_id } else { - self.temp_chain.reverse(); + self.temp_list.reverse(); let id = self.id_gen.next(); block.body.push(Instruction::access_chain( result_type_id, id, root_id, - &self.temp_chain, + &self.temp_list, )); id }; @@ -2439,12 +2529,9 @@ impl Writer { result, } => { let id = self.id_gen.next(); - //TODO: avoid heap allocation - let mut argument_ids = vec![]; - + self.temp_list.clear(); for &argument in arguments { - let arg_id = self.cached[argument]; - argument_ids.push(arg_id); + self.temp_list.push(self.cached[argument]); } let type_id = match result { @@ -2465,7 +2552,7 @@ impl Writer { type_id, id, self.lookup_function[&local_function], - argument_ids.as_slice(), + &self.temp_list, )); } } @@ -2534,7 +2621,7 @@ impl Writer { // then all types, some of them may rely on constants and struct type set for (handle, _) in ir_module.types.iter() { - self.write_type_declaration_arena(&ir_module.types, &mod_info.layouter, handle)?; + self.write_type_declaration_arena(&ir_module.types, handle)?; } // the all the composite constants, they rely on types diff --git a/third_party/rust/naga/src/back/wgsl/keywords.rs b/third_party/rust/naga/src/back/wgsl/keywords.rs new file mode 100644 index 000000000000..a0ec86810fc0 --- /dev/null +++ b/third_party/rust/naga/src/back/wgsl/keywords.rs @@ -0,0 +1,126 @@ +// https://gpuweb.github.io/gpuweb/wgsl/#keyword-summary +pub const RESERVED: &[&str] = &[ + // Type-defining keywords + "ARRAY", + "BOOL", + "FLOAT32", + "INT32", + "MAT2x2", + "MAT2x3", + "MAT2x4", + "MAT3x2", + "MAT3x3", + "MAT3x4", + "MAT4x2", + "MAT4x3", + "MAT4x4", + "POINTER", + "SAMPLER", + "SAMPLER_COMPARISON", + "STRUCT", + "TEXTURE_1D", + "TEXTURE_2D", + "TEXTURE_2D_ARRAY", + "TEXTURE_3D", + "TEXTURE_CUBE", + "TEXTURE_CUBE_ARRAY", + "TEXTURE_MULTISAMPLED_2D", + "TEXTURE_STORAGE_1D", + "TEXTURE_STORAGE_2D", + "TEXTURE_STORAGE_2D_ARRAY", + "TEXTURE_STORAGE_3D", + "TEXTURE_DEPTH_2D", + "TEXTURE_DEPTH_2D_ARRAY", + "TEXTURE_DEPTH_CUBE", + "TEXTURE_DEPTH_CUBE_ARRAY", + "UINT32", + "VEC2", + "VEC3", + "VEC4", + // Other keywords + "BITCAST", + "BLOCK", + "BREAK", + "CASE", + "CONTINUE", + "CONTINUING", + "DEFAULT", + "DISCARD", + "ELSE", + "ELSE_IF", + "ENABLE", + "FALLTHROUGH", + "FALSE", + "FN", + "FOR", + "FUNCTION", + "IF", + "LET", + "LOOP", + "PRIVATE", + "RETURN", + "STORAGE", + "SWITCH", + "TRUE", + "TYPE", + "UNIFORM", + "VAR", + "WORKGROUP", + // Image format keywords + "R8UNORM", + "R8SNORM", + "R8UINT", + "R8SINT", + "R16UINT", + "R16SINT", + "R16FLOAT", + "RG8UNORM", + "RG8SNORM", + "RG8UINT", + "RG8SINT", + "R32UINT", + "R32SINT", + "R32FLOAT", + "RG16UINT", + "RG16SINT", + "RG16FLOAT", + "RGBA8UNORM", + "RGBA8UNORM-SRGB", + "RGBA8SNORM", + "RGBA8UINT", + "RGBA8SINT", + "BGRA8UNORM", + "BGRA8UNORM-SRGB", + "RGB10A2UNORM", + "RG11B10FLOAT", + "RG32UINT", + "RG32SINT", + "RG32FLOAT", + "RGBA16UINT", + "RGBA16SINT", + "RGBA16FLOAT", + "RGBA32UINT", + "RGBA32SINT", + "RGBA32FLOAT", + // Reserved Keywords + "asm", + "bf16", + "do", + "enum", + "f16", + "f64", + "i8", + "i16", + "i64", + "const", + "typedef", + "u8", + "u16", + "u64", + "unless", + "using", + "while", + "regardless", + "premerge", + "handle", +]; diff --git a/third_party/rust/naga/src/back/wgsl/mod.rs b/third_party/rust/naga/src/back/wgsl/mod.rs new file mode 100644 index 000000000000..e785b57a128a --- /dev/null +++ b/third_party/rust/naga/src/back/wgsl/mod.rs @@ -0,0 +1,23 @@ +mod keywords; +mod writer; + +use std::io::Error as IoError; +use std::string::FromUtf8Error; +use thiserror::Error; + +pub use writer::Writer; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + IoError(#[from] IoError), + #[error(transparent)] + Utf8(#[from] FromUtf8Error), +} + +pub fn write_string(module: &crate::Module) -> Result { + let mut w = Writer::new(Vec::new()); + w.write(module)?; + let output = String::from_utf8(w.finish())?; + Ok(output) +} diff --git a/third_party/rust/naga/src/back/wgsl/writer.rs b/third_party/rust/naga/src/back/wgsl/writer.rs new file mode 100644 index 000000000000..206e96d11e5e --- /dev/null +++ b/third_party/rust/naga/src/back/wgsl/writer.rs @@ -0,0 +1,144 @@ +use super::Error; +use crate::FastHashMap; +use crate::{ + back::wgsl::keywords::RESERVED, Function, Module, ShaderStage, StructLevel, TypeInner, +}; +use crate::{ + proc::{NameKey, Namer}, + StructMember, +}; +use std::io::Write; + +const _INDENT: &str = " "; + +/// Shorthand result used internally by the backend +type BackendResult = Result<(), Error>; + +enum Decoration { + VertexStage, + FragmentStage, + ComputeStage { workgroup_size: [u32; 3] }, + Block, +} + +pub struct Writer { + out: W, + names: FastHashMap, + namer: Namer, +} + +impl Writer { + pub fn new(out: W) -> Self { + Writer { + out, + names: FastHashMap::default(), + namer: Namer::default(), + } + } + + pub fn write(&mut self, module: &Module) -> BackendResult { + self.names.clear(); + self.namer.reset(module, RESERVED, &mut self.names); + + // Write all structs + for (handle, ty) in module.types.iter() { + if let TypeInner::Struct { + level, ref members, .. + } = ty.inner + { + let name = &self.names[&NameKey::Type(handle)].clone(); + let block = level == StructLevel::Root; + self.write_struct(name, block, members)?; + writeln!(self.out)?; + } + } + + for (_, ep) in module.entry_points.iter().enumerate() { + let decoration = match ep.stage { + ShaderStage::Vertex => Decoration::VertexStage, + ShaderStage::Fragment => Decoration::FragmentStage, + ShaderStage::Compute => Decoration::ComputeStage { + workgroup_size: ep.workgroup_size, + }, + }; + + self.write_decoration(decoration)?; + // Add a newline after decoration + writeln!(self.out)?; + self.write_function(&ep.function)?; + } + + // Add a newline at the end of file + writeln!(self.out)?; + + Ok(()) + } + + /// Helper method used to write structs + /// https://gpuweb.github.io/gpuweb/wgsl/#functions + /// + /// # Notes + /// Ends in a newline + fn write_function(&mut self, func: &Function) -> BackendResult { + write!(self.out, "fn {}(", func.name.as_ref().unwrap())?; // TODO: unnamed function? + write!(self.out, ")")?; + + write!(self.out, "{{")?; + write!(self.out, "}}")?; + Ok(()) + } + + /// Helper method to write a decoration + /// + /// # Notes + /// Adds no leading or trailing whitespace + fn write_decoration(&mut self, decoration: Decoration) -> BackendResult { + write!(self.out, "[[")?; + match decoration { + Decoration::VertexStage => write!(self.out, "stage(vertex)")?, + Decoration::FragmentStage => write!(self.out, "stage(fragment)")?, + Decoration::ComputeStage { workgroup_size } => { + write!( + self.out, + "{}", + format!( + "stage(compute), workgroup_size({}, {}, {})", + workgroup_size[0], workgroup_size[1], workgroup_size[2] + ) + )?; + } + Decoration::Block => { + write!(self.out, "block")?; + } + }; + write!(self.out, "]]")?; + + Ok(()) + } + + /// Helper method used to write structs + /// + /// # Notes + /// Ends in a newline + fn write_struct( + &mut self, + name: &str, + block: bool, + _members: &[StructMember], + ) -> BackendResult { + if block { + self.write_decoration(Decoration::Block)?; + writeln!(self.out)?; + } + write!(self.out, "struct {} {{", name)?; + write!(self.out, "}}")?; + + writeln!(self.out)?; + + Ok(()) + } + + pub fn finish(self) -> W { + self.out + } +} diff --git a/third_party/rust/naga/src/front/glsl/ast.rs b/third_party/rust/naga/src/front/glsl/ast.rs index 78f914af585e..a832a6fde207 100644 --- a/third_party/rust/naga/src/front/glsl/ast.rs +++ b/third_party/rust/naga/src/front/glsl/ast.rs @@ -2,7 +2,8 @@ use super::{super::Typifier, constants::ConstantSolver, error::ErrorKind}; use crate::{ proc::ResolveContext, Arena, BinaryOperator, Binding, Constant, Expression, FastHashMap, Function, FunctionArgument, GlobalVariable, Handle, Interpolation, LocalVariable, Module, - RelationalFunction, ResourceBinding, ShaderStage, Statement, StorageClass, Type, UnaryOperator, + RelationalFunction, ResourceBinding, Sampling, ShaderStage, Statement, StorageClass, Type, + UnaryOperator, }; #[derive(Debug)] @@ -226,6 +227,7 @@ pub enum TypeQualifier { ResourceBinding(ResourceBinding), Binding(Binding), Interpolation(Interpolation), + Sampling(Sampling), } #[derive(Debug)] diff --git a/third_party/rust/naga/src/front/glsl/constants.rs b/third_party/rust/naga/src/front/glsl/constants.rs index c68d2b5f726d..372ff170416f 100644 --- a/third_party/rust/naga/src/front/glsl/constants.rs +++ b/third_party/rust/naga/src/front/glsl/constants.rs @@ -49,6 +49,8 @@ pub enum ConstantSolvingError { InvalidUnaryOpArg, #[error("Cannot apply the binary op to the arguments")] InvalidBinaryOpArgs, + #[error("Splat type is not registered")] + SplatType, } impl<'a> ConstantSolver<'a> { @@ -64,6 +66,28 @@ impl<'a> ConstantSolver<'a> { self.access(base, self.constant_index(index)?) } + Expression::Splat { + size, + value: splat_value, + } => { + let tgt = self.solve(splat_value)?; + let ty = match self.constants[tgt].inner { + ConstantInner::Scalar { ref value, width } => { + let kind = value.scalar_kind(); + self.types + .fetch_if(|t| t.inner == crate::TypeInner::Vector { size, kind, width }) + } + ConstantInner::Composite { .. } => None, + }; + Ok(self.constants.fetch_or_append(Constant { + name: None, + specialization: None, + inner: ConstantInner::Composite { + ty: ty.ok_or(ConstantSolvingError::SplatType)?, + components: vec![tgt; size as usize], + }, + })) + } Expression::Compose { ty, ref components } => { let components = components .iter() diff --git a/third_party/rust/naga/src/front/glsl/functions.rs b/third_party/rust/naga/src/front/glsl/functions.rs index e1492e84b842..ed3908fcae8d 100644 --- a/third_party/rust/naga/src/front/glsl/functions.rs +++ b/third_party/rust/naga/src/front/glsl/functions.rs @@ -241,11 +241,7 @@ impl Program<'_> { } else { let ty = &self.module.types[var.ty]; // anonymous structs - if let TypeInner::Struct { - block: _, - ref members, - } = ty.inner - { + if let TypeInner::Struct { ref members, .. } = ty.inner { let base = self .context .expressions diff --git a/third_party/rust/naga/src/front/glsl/lex.rs b/third_party/rust/naga/src/front/glsl/lex.rs index 6f72c5c80f86..08874dfeea9a 100644 --- a/third_party/rust/naga/src/front/glsl/lex.rs +++ b/third_party/rust/naga/src/front/glsl/lex.rs @@ -66,8 +66,8 @@ impl<'a> Iterator for Lexer<'a> { "flat" => Token::Interpolation((meta, crate::Interpolation::Flat)), "noperspective" => Token::Interpolation((meta, crate::Interpolation::Linear)), "smooth" => Token::Interpolation((meta, crate::Interpolation::Perspective)), - "centroid" => Token::Interpolation((meta, crate::Interpolation::Centroid)), - "sample" => Token::Interpolation((meta, crate::Interpolation::Sample)), + "centroid" => Token::Sampling((meta, crate::Sampling::Centroid)), + "sample" => Token::Sampling((meta, crate::Sampling::Sample)), // values "true" => Token::BoolConstant((meta, true)), "false" => Token::BoolConstant((meta, false)), diff --git a/third_party/rust/naga/src/front/glsl/parser.rs b/third_party/rust/naga/src/front/glsl/parser.rs index 0d255d6d5044..276529b0b41c 100644 --- a/third_party/rust/naga/src/front/glsl/parser.rs +++ b/third_party/rust/naga/src/front/glsl/parser.rs @@ -10,7 +10,7 @@ pomelo! { ConstantInner, Expression, Function, FunctionArgument, FunctionResult, GlobalVariable, Handle, Interpolation, - LocalVariable, ResourceBinding, ScalarValue, ScalarKind, + LocalVariable, ResourceBinding, Sampling, ScalarValue, ScalarKind, Statement, StorageAccess, StorageClass, StructMember, SwitchCase, Type, TypeInner, UnaryOperator, }; @@ -120,6 +120,8 @@ pomelo! { %type storage_qualifier StorageQualifier; %type interpolation_qualifier Interpolation; %type Interpolation Interpolation; + %type sampling_qualifier Sampling; + %type Sampling Sampling; // types %type fully_specified_type (Vec, Option>); @@ -514,15 +516,21 @@ pomelo! { if i.1 == "gl_PerVertex" { None } else { - let block = !t.is_empty(); + let level = if t.is_empty() { + //TODO + crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() } + } else { + crate::StructLevel::Root + }; Some(VarDeclaration { type_qualifiers: t, ids_initializers: vec![(None, None)], ty: extra.module.types.fetch_or_append(Type{ name: Some(i.1), inner: TypeInner::Struct { - block, + level, members: sdl, + span: 0, //TODO }, }), }) @@ -531,15 +539,21 @@ pomelo! { declaration ::= type_qualifier(t) Identifier(i1) LeftBrace struct_declaration_list(sdl) RightBrace Identifier(i2) Semicolon { - let block = !t.is_empty(); + let level = if t.is_empty() { + //TODO + crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() } + } else { + crate::StructLevel::Root + }; Some(VarDeclaration { type_qualifiers: t, ids_initializers: vec![(Some(i2.1), None)], ty: extra.module.types.fetch_or_append(Type{ name: Some(i1.1), inner: TypeInner::Struct { - block, + level, members: sdl, + span: 0, //TODO }, }), }) @@ -601,10 +615,15 @@ pomelo! { i } + sampling_qualifier ::= Sampling((_, s)) { + s + } + layout_qualifier ::= Layout LeftParen layout_qualifier_id_list(l) RightParen { - if let Some(&(_, loc)) = l.iter().find(|&q| q.0.as_str() == "location") { + if let Some(&(_, location)) = l.iter().find(|&q| q.0.as_str() == "location") { let interpolation = None; //TODO - StructLayout::Binding(Binding::Location(loc, interpolation)) + let sampling = None; //TODO + StructLayout::Binding(Binding::Location { location, interpolation, sampling }) } else if let Some(&(_, binding)) = l.iter().find(|&q| q.0.as_str() == "binding") { let group = if let Some(&(_, set)) = l.iter().find(|&q| q.0.as_str() == "set") { set @@ -658,6 +677,9 @@ pomelo! { single_type_qualifier ::= interpolation_qualifier(i) { TypeQualifier::Interpolation(i) } + single_type_qualifier ::= sampling_qualifier(i) { + TypeQualifier::Sampling(i) + } // single_type_qualifier ::= invariant_qualifier; // single_type_qualifier ::= precise_qualifier; @@ -706,8 +728,9 @@ pomelo! { Type{ name: Some(i.1), inner: TypeInner::Struct { - block: false, + level: crate::StructLevel::Normal { alignment: crate::Alignment::new(1).unwrap() }, members: vec![], + span: 0, } } } @@ -729,8 +752,7 @@ pomelo! { binding: None, //TODO //TODO: if the struct is a uniform struct, these values have to reflect // std140 layout. Otherwise, std430. - size: None, - align: None, + offset: 0, }).collect() } else { return Err(ErrorKind::SemanticError("Struct member can't be void".into())) @@ -1121,8 +1143,16 @@ pomelo! { let interpolation = d.type_qualifiers.iter().find_map(|tq| { if let TypeQualifier::Interpolation(interp) = *tq { Some(interp) } else { None } }); - if let Some(Binding::Location(_, ref mut interp)) = binding { + let sampling = d.type_qualifiers.iter().find_map(|tq| { + if let TypeQualifier::Sampling(samp) = *tq { Some(samp) } else { None } + }); + if let Some(Binding::Location { + interpolation: ref mut interp, + sampling: ref mut samp, + .. + }) = binding { *interp = interpolation; + *samp = sampling; } for (id, _initializer) in d.ids_initializers { diff --git a/third_party/rust/naga/src/front/glsl/variables.rs b/third_party/rust/naga/src/front/glsl/variables.rs index d08c59347ef8..1adf2596442e 100644 --- a/third_party/rust/naga/src/front/glsl/variables.rs +++ b/third_party/rust/naga/src/front/glsl/variables.rs @@ -133,10 +133,7 @@ impl Program<'_> { meta: TokenMetadata, ) -> Result, ErrorKind> { match *self.resolve_type(expression)? { - TypeInner::Struct { - block: _, - ref members, - } => { + TypeInner::Struct { ref members, .. } => { let index = members .iter() .position(|m| m.name == Some(name.into())) diff --git a/third_party/rust/naga/src/front/spv/error.rs b/third_party/rust/naga/src/front/spv/error.rs index 0893f9cd362d..ea5bbb377487 100644 --- a/third_party/rust/naga/src/front/spv/error.rs +++ b/third_party/rust/naga/src/front/spv/error.rs @@ -54,6 +54,5 @@ pub enum Error { InvalidEdgeClassification, FunctionCallCycle(spirv::Word), // incomplete implementation error - UnsupportedRowMajorMatrix, UnsupportedMatrixStride(spirv::Word), } diff --git a/third_party/rust/naga/src/front/spv/flow.rs b/third_party/rust/naga/src/front/spv/flow.rs index 3a96b5405b60..5dd0c3b7c737 100644 --- a/third_party/rust/naga/src/front/spv/flow.rs +++ b/third_party/rust/naga/src/front/spv/flow.rs @@ -338,13 +338,24 @@ impl FlowGraph { condition, true_id, false_id, - } => body.push(crate::Statement::If { - condition, - accept: self - .naga_traverse(self.block_to_node[&true_id], Some(merge_node_index))?, - reject: self - .naga_traverse(self.block_to_node[&false_id], Some(merge_node_index))?, - }), + } => { + let true_node_index = self.block_to_node[&true_id]; + let false_node_index = self.block_to_node[&false_id]; + + body.push(crate::Statement::If { + condition, + accept: if true_node_index == merge_node_index { + vec![crate::Statement::Break] + } else { + self.naga_traverse(true_node_index, Some(merge_node_index))? + }, + reject: if false_node_index == merge_node_index { + vec![crate::Statement::Break] + } else { + self.naga_traverse(false_node_index, Some(merge_node_index))? + }, + }); + } Terminator::Branch { target_id } => body.extend( self.naga_traverse(self.block_to_node[&target_id], Some(merge_node_index))?, ), diff --git a/third_party/rust/naga/src/front/spv/function.rs b/third_party/rust/naga/src/front/spv/function.rs index ba38cea69d84..15e969d5d32d 100644 --- a/third_party/rust/naga/src/front/spv/function.rs +++ b/third_party/rust/naga/src/front/spv/function.rs @@ -63,6 +63,9 @@ impl> super::Parser { } pub(super) fn parse_function(&mut self, module: &mut crate::Module) -> Result<(), Error> { + self.lookup_expression.clear(); + self.lookup_load_override.clear(); + let result_type_id = self.next()?; let fun_id = self.next()?; let _fun_control = self.next()?; @@ -210,9 +213,10 @@ impl> super::Parser { }); let mut arg = arg.clone(); if ep.stage == crate::ShaderStage::Fragment { - if let Some(crate::Binding::Location(_, ref mut interpolation @ None)) = - arg.binding - { + if let Some(crate::Binding::Location { + interpolation: ref mut interpolation @ None, + .. + }) = arg.binding { *interpolation = Some(crate::Interpolation::Perspective); // default } @@ -248,13 +252,7 @@ impl> super::Parser { // unrecognized binding, skip continue; } - members.push(crate::StructMember { - name: sm.name.clone(), - ty: sm.ty, - binding: sm.binding.clone(), - size: None, - align: None, - }); + members.push(sm.clone()); components.push(function.expressions.append( crate::Expression::AccessIndex { base: expr_handle, @@ -268,8 +266,7 @@ impl> super::Parser { name: None, ty: result.ty, binding: result.binding.clone(), - size: None, - align: None, + offset: 0, }); // populate just the globals first, then do `Load` in a // separate step, so that we can get a range. @@ -317,10 +314,9 @@ impl> super::Parser { *component = function.expressions.append(load_expr); } - match members.len() { - 0 => {} - 1 => { - let member = members.remove(0); + match &members[..] { + [] => {} + [member] => { function.body.push(crate::Statement::Emit( function.expressions.range_from(old_len), )); @@ -329,15 +325,18 @@ impl> super::Parser { }); function.result = Some(crate::FunctionResult { ty: member.ty, - binding: member.binding, + binding: member.binding.clone(), }); } _ => { let ty = module.types.append(crate::Type { name: None, inner: crate::TypeInner::Struct { - block: false, + level: crate::StructLevel::Normal { + alignment: crate::Alignment::new(1).unwrap(), + }, members, + span: 0xFFFF, // shouldn't matter }, }); let result_expr = function @@ -362,6 +361,8 @@ impl> super::Parser { }); } + module.apply_common_default_interpolation(); + self.lookup_expression.clear(); self.lookup_sampled_image.clear(); Ok(()) diff --git a/third_party/rust/naga/src/front/spv/mod.rs b/third_party/rust/naga/src/front/spv/mod.rs index 0d13d9714d4c..e4d7a1c7156e 100644 --- a/third_party/rust/naga/src/front/spv/mod.rs +++ b/third_party/rust/naga/src/front/spv/mod.rs @@ -16,6 +16,13 @@ populated at the start of an entry point. The outputs are saved at the end. The function associated with an entry point is wrapped in another function, such that we can handle any `Return` statements without problems. +## Row-major matrices + +We don't handle them natively, since the IR only expects column majority. +Instead, we detect when such matrix is accessed in the `OpAccessChain`, +and we generate a parallel expression that loads the value, but transposed. +This value then gets used instead of `OpLoad` result later on. + !*/ #![allow(dead_code)] @@ -41,6 +48,7 @@ use std::{convert::TryInto, num::NonZeroU32, path::PathBuf}; pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[ spirv::Capability::Shader, + spirv::Capability::VulkanMemoryModel, spirv::Capability::ClipDistance, spirv::Capability::CullDistance, spirv::Capability::SampleRateShading, @@ -60,7 +68,7 @@ pub const SUPPORTED_CAPABILITIES: &[spirv::Capability] = &[ spirv::Capability::UniformBufferArrayDynamicIndexing, spirv::Capability::StorageBufferArrayDynamicIndexing, ]; -pub const SUPPORTED_EXTENSIONS: &[&str] = &[]; +pub const SUPPORTED_EXTENSIONS: &[&str] = &["SPV_KHR_vulkan_memory_model"]; pub const SUPPORTED_EXT_SETS: &[&str] = &["GLSL.std.450"]; #[derive(Copy, Clone)] @@ -192,7 +200,7 @@ bitflags::bitflags! { } } -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum Majority { Column, Row, @@ -212,6 +220,7 @@ struct Decoration { matrix_stride: Option, matrix_major: Option, interpolation: Option, + sampling: Option, flags: DecorationFlags, } @@ -243,10 +252,11 @@ impl Decoration { } => map_builtin(built_in).map(crate::Binding::BuiltIn), Decoration { built_in: None, - location: Some(loc), + location: Some(location), interpolation, + sampling, .. - } => Ok(crate::Binding::Location(loc, interpolation)), + } => Ok(crate::Binding::Location { location, interpolation, sampling }), _ => Err(Error::MissingDecoration(spirv::Decoration::Location)), } } @@ -300,6 +310,21 @@ struct LookupExpression { type_id: spirv::Word, } +#[derive(Debug)] +struct LookupMember { + type_id: spirv::Word, + // This is true for either matrices, or arrays of matrices (yikes). + row_major: bool, +} + +#[derive(Clone, Debug)] +enum LookupLoadOverride { + /// For arrays of matrices, we track them but not loading yet. + Pending, + /// For matrices, vectors, and scalars, we pre-load the data. + Loaded(Handle), +} + #[derive(Clone, Debug)] struct Assignment { to: Handle, @@ -337,7 +362,7 @@ pub struct Parser { ext_glsl_id: Option, future_decor: FastHashMap, future_member_decor: FastHashMap<(spirv::Word, MemberIndex), Decoration>, - lookup_member_type_id: FastHashMap<(Handle, MemberIndex), spirv::Word>, + lookup_member: FastHashMap<(Handle, MemberIndex), LookupMember>, handle_sampling: FastHashMap, image::SamplingFlags>, lookup_type: FastHashMap, lookup_void_type: Option, @@ -346,6 +371,8 @@ pub struct Parser { lookup_constant: FastHashMap, lookup_variable: FastHashMap, lookup_expression: FastHashMap, + // Load overrides are used to work around row-major matrices + lookup_load_override: FastHashMap, lookup_sampled_image: FastHashMap, lookup_function_type: FastHashMap, lookup_function: FastHashMap>, @@ -373,13 +400,14 @@ impl> Parser { future_decor: FastHashMap::default(), future_member_decor: FastHashMap::default(), handle_sampling: FastHashMap::default(), - lookup_member_type_id: FastHashMap::default(), + lookup_member: FastHashMap::default(), lookup_type: FastHashMap::default(), lookup_void_type: None, lookup_storage_buffer_types: FastHashSet::default(), lookup_constant: FastHashMap::default(), lookup_variable: FastHashMap::default(), lookup_expression: FastHashMap::default(), + lookup_load_override: FastHashMap::default(), lookup_sampled_image: FastHashMap::default(), lookup_function_type: FastHashMap::default(), lookup_function: FastHashMap::default(), @@ -478,10 +506,10 @@ impl> Parser { dec.interpolation = Some(crate::Interpolation::Flat); } spirv::Decoration::Centroid => { - dec.interpolation = Some(crate::Interpolation::Centroid); + dec.sampling = Some(crate::Sampling::Centroid); } spirv::Decoration::Sample => { - dec.interpolation = Some(crate::Interpolation::Sample); + dec.sampling = Some(crate::Sampling::Sample); } spirv::Decoration::NonReadable => { dec.flags |= DecorationFlags::NON_READABLE; @@ -636,11 +664,11 @@ impl> Parser { let root_lookup = self.lookup_type.lookup(root_type_id)?; let (count, child_type_id) = match type_arena[root_lookup.handle].inner { crate::TypeInner::Struct { ref members, .. } => { - let child_type_id = *self - .lookup_member_type_id + let child_member = self + .lookup_member .get(&(root_lookup.handle, selection)) .ok_or(Error::InvalidAccessType(root_type_id))?; - (members.len(), child_type_id) + (members.len(), child_member.type_id) } // crate::TypeInner::Array //TODO? crate::TypeInner::Vector { size, .. } @@ -797,6 +825,7 @@ impl> Parser { struct AccessExpression { base_handle: Handle, type_id: spirv::Word, + load_override: Option, } inst.expect_at_least(4)?; @@ -813,50 +842,84 @@ impl> Parser { AccessExpression { base_handle: lexp.handle, type_id: lty.base_id.ok_or(Error::InvalidAccessType(lexp.type_id))?, + load_override: self.lookup_load_override.get(&base_id).cloned(), } }; for _ in 4..inst.wc { let access_id = self.next()?; log::trace!("\t\t\tlooking up index expr {:?}", access_id); let index_expr = self.lookup_expression.lookup(access_id)?.clone(); - let index_type_handle = self.lookup_type.lookup(index_expr.type_id)?.handle; - match type_arena[index_type_handle].inner { - crate::TypeInner::Scalar { - kind: crate::ScalarKind::Uint, - .. + let index_expr_data = &expressions[index_expr.handle]; + let index_maybe = match *index_expr_data { + crate::Expression::Constant(const_handle) => { + Some(const_arena[const_handle].to_array_length().ok_or( + Error::InvalidAccess(crate::Expression::Constant(const_handle)), + )?) } - | crate::TypeInner::Scalar { - kind: crate::ScalarKind::Sint, - .. - } => (), - ref other => { - log::warn!("access index type {:?}", other); - return Err(Error::UnsupportedType(index_type_handle)); - } - } + _ => None, + }; + log::trace!("\t\t\tlooking up type {:?}", acex.type_id); let type_lookup = self.lookup_type.lookup(acex.type_id)?; acex = match type_arena[type_lookup.handle].inner { + // can only index a struct with a constant crate::TypeInner::Struct { .. } => { - let index = match expressions[index_expr.handle] { - crate::Expression::Constant(const_handle) => { - match const_arena[const_handle].inner { - crate::ConstantInner::Scalar { - width: 4, - value: crate::ScalarValue::Uint(v), - } => v as u32, - crate::ConstantInner::Scalar { - width: 4, - value: crate::ScalarValue::Sint(v), - } => v as u32, - _ => { - return Err(Error::InvalidAccess( - crate::Expression::Constant(const_handle), - )) + let index = index_maybe + .ok_or_else(|| Error::InvalidAccess(index_expr_data.clone()))?; + let lookup_member = self + .lookup_member + .get(&(type_lookup.handle, index)) + .ok_or(Error::InvalidAccessType(acex.type_id))?; + let base_handle = + expressions.append(crate::Expression::AccessIndex { + base: acex.base_handle, + index, + }); + AccessExpression { + base_handle, + type_id: lookup_member.type_id, + load_override: if lookup_member.row_major { + debug_assert!(acex.load_override.is_none()); + let sub_type_lookup = + self.lookup_type.lookup(lookup_member.type_id)?; + Some(match type_arena[sub_type_lookup.handle].inner { + // load it transposed, to match column major expectations + crate::TypeInner::Matrix { .. } => { + let loaded = + expressions.append(crate::Expression::Load { + pointer: base_handle, + }); + let transposed = + expressions.append(crate::Expression::Math { + fun: crate::MathFunction::Transpose, + arg: loaded, + arg1: None, + arg2: None, + }); + LookupLoadOverride::Loaded(transposed) } - } + _ => LookupLoadOverride::Pending, + }) + } else { + None + }, + } + } + // we can't dynamically index matrices, so expecting constant index here + crate::TypeInner::Matrix { .. } => { + let index = index_maybe + .ok_or_else(|| Error::InvalidAccess(index_expr_data.clone()))?; + let load_override = match acex.load_override { + // We are indexing inside a row-major matrix + Some(LookupLoadOverride::Loaded(load_expr)) => { + let sub_expr = + expressions.append(crate::Expression::AccessIndex { + base: load_expr, + index, + }); + Some(LookupLoadOverride::Loaded(sub_expr)) } - ref other => return Err(Error::InvalidAccess(other.clone())), + _ => None, }; AccessExpression { base_handle: expressions.append( @@ -865,24 +928,62 @@ impl> Parser { index, }, ), - type_id: *self - .lookup_member_type_id - .get(&(type_lookup.handle, index)) + type_id: type_lookup + .base_id .ok_or(Error::InvalidAccessType(acex.type_id))?, + load_override, } } - _ => AccessExpression { - base_handle: expressions.append(crate::Expression::Access { + // This must be a vector or an array. + _ => { + let base_handle = expressions.append(crate::Expression::Access { base: acex.base_handle, index: index_expr.handle, - }), - type_id: type_lookup - .base_id - .ok_or(Error::InvalidAccessType(acex.type_id))?, - }, + }); + let load_override = match acex.load_override { + // If there is a load override in place, then we always end up + // with a side-loaded value here. + Some(lookup_load_override) => { + let sub_expr = match lookup_load_override { + // We must be indexing into the array of row-major matrices. + // Let's load the result of indexing and transpose it. + LookupLoadOverride::Pending => { + let loaded = + expressions.append(crate::Expression::Load { + pointer: base_handle, + }); + expressions.append(crate::Expression::Math { + fun: crate::MathFunction::Transpose, + arg: loaded, + arg1: None, + arg2: None, + }) + } + // We are indexing inside a row-major matrix. + LookupLoadOverride::Loaded(load_expr) => expressions + .append(crate::Expression::Access { + base: load_expr, + index: index_expr.handle, + }), + }; + Some(LookupLoadOverride::Loaded(sub_expr)) + } + None => None, + }; + AccessExpression { + base_handle, + type_id: type_lookup + .base_id + .ok_or(Error::InvalidAccessType(acex.type_id))?, + load_override, + } + } }; } + if let Some(load_expr) = acex.load_override { + self.lookup_load_override.insert(result_id, load_expr); + } let lookup_expression = LookupExpression { handle: acex.base_handle, type_id: result_type_id, @@ -997,10 +1098,12 @@ impl> Parser { log::trace!("\t\t\tlooking up type {:?}", lexp.type_id); let type_lookup = self.lookup_type.lookup(lexp.type_id)?; let type_id = match type_arena[type_lookup.handle].inner { - crate::TypeInner::Struct { .. } => *self - .lookup_member_type_id - .get(&(type_lookup.handle, index)) - .ok_or(Error::InvalidAccessType(lexp.type_id))?, + crate::TypeInner::Struct { .. } => { + self.lookup_member + .get(&(type_lookup.handle, index)) + .ok_or(Error::InvalidAccessType(lexp.type_id))? + .type_id + } crate::TypeInner::Array { .. } | crate::TypeInner::Vector { .. } | crate::TypeInner::Matrix { .. } => type_lookup @@ -1071,9 +1174,17 @@ impl> Parser { let lexp = self.lookup_expression.lookup(comp_id)?; components.push(lexp.handle); } - let expr = crate::Expression::Compose { - ty: self.lookup_type.lookup(result_type_id)?.handle, - components, + let ty = self.lookup_type.lookup(result_type_id)?.handle; + let first = components[0]; + let expr = match type_arena[ty].inner { + // this is an optimization to detect the splat + crate::TypeInner::Vector { size, .. } + if components.len() == size as usize + && components[1..].iter().all(|&c| c == first) => + { + crate::Expression::Splat { size, value: first } + } + _ => crate::Expression::Compose { ty, components }, }; self.lookup_expression.insert( id, @@ -1100,9 +1211,13 @@ impl> Parser { crate::TypeInner::Image { .. } | crate::TypeInner::Sampler { .. } => { base_lexp.handle } - _ => expressions.append(crate::Expression::Load { - pointer: base_lexp.handle, - }), + _ => match self.lookup_load_override.get(&pointer_id) { + Some(&LookupLoadOverride::Loaded(handle)) => handle, + //Note: we aren't handling `LookupLoadOverride::Pending` properly here + _ => expressions.append(crate::Expression::Load { + pointer: base_lexp.handle, + }), + }, }; self.lookup_expression.insert( @@ -2301,36 +2416,14 @@ impl> Parser { let vector_type_lookup = self.lookup_type.lookup(vector_type_id)?; let inner = match module.types[vector_type_lookup.handle].inner { - crate::TypeInner::Vector { size, width, .. } => { - if let Some(Decoration { - matrix_stride: Some(stride), - .. - }) = decor - { - if stride.get() != (size as u32) * (width as u32) { - return Err(Error::UnsupportedMatrixStride(stride.get())); - } - } - crate::TypeInner::Matrix { - columns: map_vector_size(num_columns)?, - rows: size, - width, - } - } + crate::TypeInner::Vector { size, width, .. } => crate::TypeInner::Matrix { + columns: map_vector_size(num_columns)?, + rows: size, + width, + }, _ => return Err(Error::InvalidInnerType(vector_type_id)), }; - if let Some(Decoration { - matrix_major: Some(ref major), - .. - }) = decor - { - match *major { - Majority::Column => (), - Majority::Row => return Err(Error::UnsupportedRowMajorMatrix), - } - } - self.lookup_type.insert( id, LookupType { @@ -2419,17 +2512,21 @@ impl> Parser { let length_id = self.next()?; let length_const = self.lookup_constant.lookup(length_id)?; - let decor = self.future_decor.remove(&id); + let decor = self.future_decor.remove(&id).unwrap_or_default(); + let base = self.lookup_type.lookup(type_id)?.handle; let inner = crate::TypeInner::Array { - base: self.lookup_type.lookup(type_id)?.handle, + base, size: crate::ArraySize::Constant(length_const.handle), - stride: decor.as_ref().and_then(|dec| dec.array_stride), + stride: match decor.array_stride { + Some(stride) => stride.get(), + None => module.types[base].inner.span(&module.constants), + }, }; self.lookup_type.insert( id, LookupType { handle: module.types.append(crate::Type { - name: decor.and_then(|dec| dec.name), + name: decor.name, inner, }), base_id: Some(type_id), @@ -2448,17 +2545,21 @@ impl> Parser { let id = self.next()?; let type_id = self.next()?; - let decor = self.future_decor.remove(&id); + let decor = self.future_decor.remove(&id).unwrap_or_default(); + let base = self.lookup_type.lookup(type_id)?.handle; let inner = crate::TypeInner::Array { base: self.lookup_type.lookup(type_id)?.handle, size: crate::ArraySize::Dynamic, - stride: decor.as_ref().and_then(|dec| dec.array_stride), + stride: match decor.array_stride { + Some(stride) => stride.get(), + None => module.types[base].inner.span(&module.constants), + }, }; self.lookup_type.insert( id, LookupType { handle: module.types.append(crate::Type { - name: decor.and_then(|dec| dec.name), + name: decor.name, inner, }), base_id: Some(type_id), @@ -2478,28 +2579,72 @@ impl> Parser { let parent_decor = self.future_decor.remove(&id); let block_decor = parent_decor.as_ref().and_then(|decor| decor.block.clone()); - let mut members = Vec::with_capacity(inst.wc as usize - 2); - let mut member_type_ids = Vec::with_capacity(members.capacity()); + let mut members = Vec::::with_capacity(inst.wc as usize - 2); + let mut member_lookups = Vec::with_capacity(members.capacity()); for i in 0..u32::from(inst.wc) - 2 { let type_id = self.next()?; - member_type_ids.push(type_id); let ty = self.lookup_type.lookup(type_id)?.handle; let decor = self .future_member_decor .remove(&(id, i)) .unwrap_or_default(); + + member_lookups.push(LookupMember { + type_id, + row_major: decor.matrix_major == Some(Majority::Row), + }); + let binding = decor.io_binding().ok(); + let offset = match decor.offset { + Some(offset) => offset, + None => match members.last() { + Some(member) => { + //TODO: is this needed? + // If offsets are required, we can just put 0 here + member.offset + module.types[member.ty].inner.span(&module.constants) + } + None => 0, + }, + }; + + if let crate::TypeInner::Matrix { + columns: _, + rows, + width, + } = module.types[ty].inner + { + if let Some(stride) = decor.matrix_stride { + if stride.get() != (rows as u32) * (width as u32) { + return Err(Error::UnsupportedMatrixStride(stride.get())); + } + } + } + members.push(crate::StructMember { name: decor.name, ty, binding, - size: None, //TODO - align: None, + offset, }); } + //TODO: we should be able to do better than this. + const STRUCT_ALIGNMENT: u32 = 16; + let inner = crate::TypeInner::Struct { - block: block_decor.is_some(), + level: match block_decor { + Some(_) => crate::StructLevel::Root, + None => crate::StructLevel::Normal { + alignment: crate::Alignment::new(STRUCT_ALIGNMENT).unwrap(), + }, + }, + span: match members.last() { + Some(member) => { + let end = member.offset + module.types[member.ty].inner.span(&module.constants); + ((end - 1) | (STRUCT_ALIGNMENT - 1)) + 1 + } + None => STRUCT_ALIGNMENT, + }, members, }; let ty_handle = module.types.append(crate::Type { @@ -2510,9 +2655,9 @@ impl> Parser { if block_decor == Some(Block { buffer: true }) { self.lookup_storage_buffer_types.insert(ty_handle); } - for (i, type_id) in member_type_ids.into_iter().enumerate() { - self.lookup_member_type_id - .insert((ty_handle, i as u32), type_id); + for (i, member_lookup) in member_lookups.into_iter().enumerate() { + self.lookup_member + .insert((ty_handle, i as u32), member_lookup); } self.lookup_type.insert( id, diff --git a/third_party/rust/naga/src/front/wgsl/conv.rs b/third_party/rust/naga/src/front/wgsl/conv.rs index 396dbd24a576..227327ad5ec1 100644 --- a/third_party/rust/naga/src/front/wgsl/conv.rs +++ b/third_party/rust/naga/src/front/wgsl/conv.rs @@ -44,10 +44,16 @@ pub fn map_interpolation(word: &str) -> Result> match word { "linear" => Ok(crate::Interpolation::Linear), "flat" => Ok(crate::Interpolation::Flat), - "centroid" => Ok(crate::Interpolation::Centroid), - "sample" => Ok(crate::Interpolation::Sample), "perspective" => Ok(crate::Interpolation::Perspective), - _ => Err(Error::UnknownDecoration(word)), + _ => Err(Error::UnknownAttribute(word)), + } +} + +pub fn map_sampling(word: &str) -> Result> { + match word { + "centroid" => Ok(crate::Sampling::Centroid), + "sample" => Ok(crate::Sampling::Sample), + _ => Err(Error::UnknownAttribute(word)), } } diff --git a/third_party/rust/naga/src/front/wgsl/layout.rs b/third_party/rust/naga/src/front/wgsl/layout.rs new file mode 100644 index 000000000000..e17d5548e1d9 --- /dev/null +++ b/third_party/rust/naga/src/front/wgsl/layout.rs @@ -0,0 +1,115 @@ +use crate::arena::{Arena, Handle}; +use std::{num::NonZeroU32, ops}; + +/// Alignment information for a type. +#[derive(Clone, Copy, Debug, Hash, PartialEq)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub struct TypeLayout { + pub size: u32, + pub alignment: crate::Alignment, +} + +/// Helper processor that derives the sizes of all types. +/// It uses the default layout algorithm/table, described in +/// https://github.com/gpuweb/gpuweb/issues/1393 +#[derive(Debug, Default)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +pub struct Layouter { + layouts: Vec, +} + +impl Layouter { + pub fn clear(&mut self) { + self.layouts.clear(); + } + + pub fn round_up(alignment: crate::Alignment, offset: u32) -> u32 { + match offset & (alignment.get() - 1) { + 0 => offset, + other => offset + alignment.get() - other, + } + } + + pub fn member_placement( + &self, + offset: u32, + ty: Handle, + align: Option, + size: Option, + ) -> (ops::Range, crate::Alignment) { + let layout = self.layouts[ty.index()]; + let alignment = align.unwrap_or(layout.alignment); + let start = Self::round_up(alignment, offset); + let span = match size { + Some(size) => size.get(), + None => layout.size, + }; + (start..start + span, alignment) + } + + pub fn update(&mut self, types: &Arena, constants: &Arena) { + use crate::TypeInner as Ti; + for (_, ty) in types.iter().skip(self.layouts.len()) { + let size = ty.inner.span(constants); + let layout = match ty.inner { + Ti::Scalar { width, .. } => TypeLayout { + size, + alignment: crate::Alignment::new(width as u32).unwrap(), + }, + Ti::Vector { + size: vec_size, + width, + .. + } => TypeLayout { + size, + alignment: { + let count = if vec_size >= crate::VectorSize::Tri { + 4 + } else { + 2 + }; + crate::Alignment::new((count * width) as u32).unwrap() + }, + }, + Ti::Matrix { + columns: _, + rows, + width, + } => TypeLayout { + size, + alignment: { + let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 }; + crate::Alignment::new((count * width) as u32).unwrap() + }, + }, + Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout { + size, + alignment: crate::Alignment::new(1).unwrap(), + }, + Ti::Array { stride, .. } => TypeLayout { + size, + alignment: crate::Alignment::new(stride).unwrap(), + }, + Ti::Struct { + ref level, + members: _, + span, + } => TypeLayout { + size: span, + alignment: match *level { + crate::StructLevel::Root => crate::Alignment::new(1).unwrap(), + crate::StructLevel::Normal { alignment } => alignment, + }, + }, + Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout { + size, + alignment: crate::Alignment::new(1).unwrap(), + }, + }; + debug_assert!(ty.inner.span(constants) <= layout.size); + self.layouts.push(layout); + } + } +} diff --git a/third_party/rust/naga/src/front/wgsl/mod.rs b/third_party/rust/naga/src/front/wgsl/mod.rs index 9eb8c4f96884..8d4baa4c493c 100644 --- a/third_party/rust/naga/src/front/wgsl/mod.rs +++ b/third_party/rust/naga/src/front/wgsl/mod.rs @@ -3,13 +3,14 @@ //! [wgsl]: https://gpuweb.github.io/gpuweb/wgsl.html mod conv; +mod layout; mod lexer; #[cfg(test)] mod tests; use crate::{ arena::{Arena, Handle}, - proc::{ensure_block_returns, ResolveContext, ResolveError}, + proc::{ensure_block_returns, ResolveContext, ResolveError, TypeResolution}, FastHashMap, }; @@ -83,8 +84,8 @@ pub enum Error<'a> { UnknownImport(&'a str), #[error("unknown storage class: `{0}`")] UnknownStorageClass(&'a str), - #[error("unknown decoration: `{0}`")] - UnknownDecoration(&'a str), + #[error("unknown attribute: `{0}`")] + UnknownAttribute(&'a str), #[error("unknown scalar kind: `{0}`")] UnknownScalarKind(&'a str), #[error("unknown builtin: `{0}`")] @@ -111,18 +112,19 @@ pub enum Error<'a> { ZeroSizeOrAlign, #[error("not a composite type: {0:?}")] NotCompositeType(Handle), - #[error("Input/output binding is not consistent: location {0:?}, built-in {1:?} and interpolation {2:?}")] + #[error("Input/output binding is not consistent: location {0:?}, built-in {1:?}, interpolation {2:?}, and sampling {3:?}")] InconsistentBinding( Option, Option, Option, + Option, ), #[error("call to local `{0}(..)` can't be resolved")] UnknownLocalFunction(&'a str), #[error("builtin {0:?} is not implemented")] UnimplementedBuiltin(crate::BuiltIn), #[error("expression {0} doesn't match its given type {1:?}")] - ConstTypeMismatch(&'a str, Handle), + LetTypeMismatch(&'a str, Handle), #[error("other error")] Other, } @@ -327,12 +329,50 @@ impl<'a> ExpressionContext<'a, '_, '_> { let mut left = parser(lexer, self.reborrow())?; while let Some(op) = classifier(lexer.peek().0) { let _ = lexer.next(); - let expression = crate::Expression::Binary { - op, - left, - right: parser(lexer, self.reborrow())?, - }; - left = self.expressions.append(expression); + let right = parser(lexer, self.reborrow())?; + left = self + .expressions + .append(crate::Expression::Binary { op, left, right }); + } + Ok(left) + } + + fn parse_binary_splat_op( + &mut self, + lexer: &mut Lexer<'a>, + classifier: impl Fn(Token<'a>) -> Option, + mut parser: impl FnMut( + &mut Lexer<'a>, + ExpressionContext<'a, '_, '_>, + ) -> Result, Error<'a>>, + ) -> Result, Error<'a>> { + let mut left = parser(lexer, self.reborrow())?; + while let Some(op) = classifier(lexer.peek().0) { + let _ = lexer.next(); + let mut right = parser(lexer, self.reborrow())?; + // insert splats, if needed by the non-'*' operations + if op != crate::BinaryOperator::Multiply { + let left_size = match *self.resolve_type(left)? { + crate::TypeInner::Vector { size, .. } => Some(size), + _ => None, + }; + match (left_size, self.resolve_type(right)?) { + (Some(size), &crate::TypeInner::Scalar { .. }) => { + right = self + .expressions + .append(crate::Expression::Splat { size, value: right }); + } + (None, &crate::TypeInner::Vector { size, .. }) => { + left = self + .expressions + .append(crate::Expression::Splat { size, value: left }); + } + _ => {} + } + } + left = self + .expressions + .append(crate::Expression::Binary { op, left, right }); } Ok(left) } @@ -404,14 +444,14 @@ impl Composition { } #[derive(Default)] -struct TypeDecoration { +struct TypeAttributes { stride: Option, access: crate::StorageAccess, } #[derive(Clone, Debug, PartialEq)] pub enum Scope { - Decoration, + Attribute, ImportDecl, VariableDecl, TypeDecl, @@ -431,6 +471,7 @@ struct BindingParser { location: Option, built_in: Option, interpolation: Option, + sampling: Option, } impl BindingParser { @@ -451,24 +492,33 @@ impl BindingParser { lexer.expect(Token::Paren('('))?; let raw = lexer.next_ident()?; self.interpolation = Some(conv::map_interpolation(raw)?); + if lexer.skip(Token::Separator(',')) { + let raw = lexer.next_ident()?; + self.sampling = Some(conv::map_sampling(raw)?); + } lexer.expect(Token::Paren(')'))?; } - _ => return Err(Error::UnknownDecoration(name)), + _ => return Err(Error::UnknownAttribute(name)), } Ok(()) } fn finish<'a>(self) -> Result, Error<'a>> { - match (self.location, self.built_in, self.interpolation) { - (None, None, None) => Ok(None), - (Some(loc), None, interpolation) => { - Ok(Some(crate::Binding::Location(loc, interpolation))) + match (self.location, self.built_in, self.interpolation, self.sampling) { + (None, None, None, None) => Ok(None), + (Some(location), None, interpolation, sampling) => { + // Before handing over the completed `Module`, we call + // `apply_common_default_interpolation` to ensure that the interpolation and + // sampling have been explicitly specified on all vertex shader output and fragment + // shader input user bindings, so leaving them potentially `None` here is fine. + Ok(Some(crate::Binding::Location { location, interpolation, sampling })) } - (None, Some(bi), None) => Ok(Some(crate::Binding::BuiltIn(bi))), - (location, built_in, interpolation) => Err(Error::InconsistentBinding( + (None, Some(bi), None, None) => Ok(Some(crate::Binding::BuiltIn(bi))), + (location, built_in, interpolation, sampling) => Err(Error::InconsistentBinding( location, built_in, interpolation, + sampling, )), } } @@ -560,6 +610,7 @@ impl<'a> std::error::Error for ParseError<'a> { pub struct Parser { scopes: Vec, lookup_type: FastHashMap>, + layouter: layout::Layouter, } impl Parser { @@ -567,6 +618,7 @@ impl Parser { Parser { scopes: Vec::new(), lookup_type: FastHashMap::default(), + layouter: Default::default(), } } @@ -988,7 +1040,7 @@ impl Parser { lexer, name, None, - TypeDecoration::default(), + TypeAttributes::default(), type_arena, const_arena, )?; @@ -1070,14 +1122,19 @@ impl Parser { //TODO: resolve the duplicate call in `parse_singular_expression` expr } else { - let inner = self.parse_type_decl_impl( - lexer, - TypeDecoration::default(), - word, - ctx.types, - ctx.constants, - )?; - let kind = inner.scalar_kind(); + let ty_resolution = match self.lookup_type.get(word) { + Some(&handle) => TypeResolution::Handle(handle), + None => { + let inner = self.parse_type_decl_impl( + lexer, + TypeAttributes::default(), + word, + ctx.types, + ctx.constants, + )?; + TypeResolution::Value(inner) + } + }; lexer.expect(Token::Paren('('))?; let mut components = Vec::new(); @@ -1089,22 +1146,40 @@ impl Parser { } lexer.expect(Token::Paren(')'))?; let expr = if components.is_empty() { - let last_component_inner = ctx.resolve_type(last_component)?; - match (&inner, last_component_inner) { + // We can't use the `TypeInner` returned by this because + // `resolve_type` borrows context mutably. + // Use it to insert into the right maps, + // and then grab it again immutably. + ctx.resolve_type(last_component)?; + match ( + ty_resolution.inner_with(ctx.types), + ctx.typifier.get(last_component, ctx.types), + ) { ( + &crate::TypeInner::Vector { size, .. }, &crate::TypeInner::Scalar { .. }, + ) => crate::Expression::Splat { + size, + value: last_component, + }, + ( + &crate::TypeInner::Scalar { kind, .. }, &crate::TypeInner::Scalar { .. }, ) | ( - &crate::TypeInner::Matrix { .. }, - &crate::TypeInner::Matrix { .. }, - ) - | ( - &crate::TypeInner::Vector { .. }, + &crate::TypeInner::Vector { kind, .. }, &crate::TypeInner::Vector { .. }, ) => crate::Expression::As { expr: last_component, - kind: kind.ok_or(Error::BadTypeCast(word))?, + kind, + convert: true, + }, + ( + &crate::TypeInner::Matrix { .. }, + &crate::TypeInner::Matrix { .. }, + ) => crate::Expression::As { + expr: last_component, + kind: crate::ScalarKind::Float, convert: true, }, _ => { @@ -1112,8 +1187,13 @@ impl Parser { } } } else { + let ty = match ty_resolution { + TypeResolution::Handle(handle) => handle, + TypeResolution::Value(inner) => { + ctx.types.fetch_or_append(crate::Type { name: None, inner }) + } + }; components.push(last_component); - let ty = ctx.types.fetch_or_append(crate::Type { name: None, inner }); crate::Expression::Compose { ty, components } }; ctx.expressions.append(expr) @@ -1174,6 +1254,7 @@ impl Parser { crate::TypeInner::Vector { size, kind, width } => { match Composition::make(handle, size, name, name_span, ctx.expressions)? { + //TODO: Swizzling in IR Composition::Multi(size, components) => { let inner = crate::TypeInner::Vector { size, kind, width }; crate::Expression::Compose { @@ -1197,6 +1278,7 @@ impl Parser { name_span, ctx.expressions, )? { + //TODO: is this really supported? Composition::Multi(columns, components) => { let inner = crate::TypeInner::Matrix { columns, @@ -1351,7 +1433,7 @@ impl Parser { }, // additive_expression |lexer, mut context| { - context.parse_binary_op( + context.parse_binary_splat_op( lexer, |token| match token { Token::Operation('+') => Some(crate::BinaryOperator::Add), @@ -1362,7 +1444,7 @@ impl Parser { }, // multiplicative_expression |lexer, mut context| { - context.parse_binary_op( + context.parse_binary_splat_op( lexer, |token| match token { Token::Operation('*') => { @@ -1506,14 +1588,17 @@ impl Parser { lexer: &mut Lexer<'a>, type_arena: &mut Arena, const_arena: &mut Arena, - ) -> Result, Error<'a>> { + ) -> Result<(Vec, u32, crate::Alignment), Error<'a>> { + let mut offset = 0; + let mut alignment = crate::Alignment::new(1).unwrap(); let mut members = Vec::new(); + lexer.expect(Token::Paren('{'))?; loop { let (mut size, mut align) = (None, None); let mut bind_parser = BindingParser::default(); if lexer.skip(Token::DoubleParen('[')) { - self.scopes.push(Scope::Decoration); + self.scopes.push(Scope::Attribute); let mut ready = true; loop { match lexer.next() { @@ -1543,7 +1628,7 @@ impl Parser { } ready = false; } - other => return Err(Error::Unexpected(other, "decoration separator")), + other => return Err(Error::Unexpected(other, "attribute separator")), } } self.scopes.pop(); @@ -1551,19 +1636,23 @@ impl Parser { let name = match lexer.next() { (Token::Word(word), _) => word, - (Token::Paren('}'), _) => return Ok(members), + (Token::Paren('}'), _) => return Ok((members, offset, alignment)), other => return Err(Error::Unexpected(other, "field name")), }; lexer.expect(Token::Separator(':'))?; let (ty, _access) = self.parse_type_decl(lexer, None, type_arena, const_arena)?; lexer.expect(Token::Separator(';'))?; + self.layouter.update(type_arena, const_arena); + let (range, align) = self.layouter.member_placement(offset, ty, align, size); + alignment = alignment.max(align); + offset = range.end; + members.push(crate::StructMember { name: Some(name.to_owned()), ty, binding: bind_parser.finish()?, - size, - align, + offset: range.start, }); } } @@ -1571,7 +1660,7 @@ impl Parser { fn parse_type_decl_impl<'a>( &mut self, lexer: &mut Lexer<'a>, - decoration: TypeDecoration, + attribute: TypeAttributes, word: &'a str, type_arena: &mut Arena, const_arena: &mut Arena, @@ -1708,12 +1797,12 @@ impl Parser { crate::ArraySize::Dynamic }; lexer.expect_generic_paren('>')?; + let stride = match attribute.stride { + Some(stride) => stride.get(), + None => type_arena[base].inner.span(const_arena), + }; - crate::TypeInner::Array { - base, - size, - stride: decoration.stride, - } + crate::TypeInner::Array { base, size, stride } } "sampler" => crate::TypeInner::Sampler { comparison: false }, "sampler_comparison" => crate::TypeInner::Sampler { comparison: true }, @@ -1853,13 +1942,13 @@ impl Parser { }) } - /// Parse type declaration of a given name and decoration. + /// Parse type declaration of a given name and attribute. fn parse_type_decl_name<'a>( &mut self, lexer: &mut Lexer<'a>, name: &'a str, debug_name: Option<&'a str>, - decoration: TypeDecoration, + attribute: TypeAttributes, type_arena: &mut Arena, const_arena: &mut Arena, ) -> Result, Error<'a>> { @@ -1867,7 +1956,7 @@ impl Parser { Some(&handle) => handle, None => { let inner = - self.parse_type_decl_impl(lexer, decoration, name, type_arena, const_arena)?; + self.parse_type_decl_impl(lexer, attribute, name, type_arena, const_arena)?; type_arena.fetch_or_append(crate::Type { name: debug_name.map(|s| s.to_string()), inner, @@ -1884,15 +1973,15 @@ impl Parser { const_arena: &mut Arena, ) -> Result<(Handle, crate::StorageAccess), Error<'a>> { self.scopes.push(Scope::TypeDecl); - let mut decoration = TypeDecoration::default(); + let mut attribute = TypeAttributes::default(); if lexer.skip(Token::DoubleParen('[')) { - self.scopes.push(Scope::Decoration); + self.scopes.push(Scope::Attribute); loop { match lexer.next() { (Token::Word("access"), _) => { lexer.expect(Token::Paren('('))?; - decoration.access = match lexer.next_ident()? { + attribute.access = match lexer.next_ident()? { "read" => crate::StorageAccess::LOAD, "write" => crate::StorageAccess::STORE, "read_write" => crate::StorageAccess::all(), @@ -1902,28 +1991,22 @@ impl Parser { } (Token::Word("stride"), _) => { lexer.expect(Token::Paren('('))?; - decoration.stride = Some( + attribute.stride = Some( NonZeroU32::new(lexer.next_uint_literal()?).ok_or(Error::ZeroStride)?, ); lexer.expect(Token::Paren(')'))?; } (Token::DoubleParen(']'), _) => break, - other => return Err(Error::Unexpected(other, "type decoration")), + other => return Err(Error::Unexpected(other, "type attribute")), } } self.scopes.pop(); } - let storage_access = decoration.access; + let storage_access = attribute.access; let name = lexer.next_ident()?; - let handle = self.parse_type_decl_name( - lexer, - name, - debug_name, - decoration, - type_arena, - const_arena, - )?; + let handle = + self.parse_type_decl_name(lexer, name, debug_name, attribute, type_arena, const_arena)?; self.scopes.pop(); Ok((handle, storage_access)) } @@ -1995,7 +2078,7 @@ impl Parser { self.scopes.push(Scope::Statement); let mut emitter = super::Emitter::default(); match word { - "const" => { + "let" => { emitter.start(context.expressions); let name = lexer.next_ident()?; let given_ty = if lexer.skip(Token::Separator(':')) { @@ -2022,7 +2105,7 @@ impl Parser { given_inner, expr_inner ); - return Err(Error::ConstTypeMismatch(name, ty)); + return Err(Error::LetTypeMismatch(name, ty)); } } block.extend(emitter.finish(context.expressions)); @@ -2361,7 +2444,7 @@ impl Parser { } let mut bind_parser = BindingParser::default(); - self.scopes.push(Scope::Decoration); + self.scopes.push(Scope::Attribute); loop { let word = lexer.next_ident()?; bind_parser.parse(lexer, word)?; @@ -2370,7 +2453,7 @@ impl Parser { break; } (Token::Separator(','), _) => {} - other => return Err(Error::Unexpected(other, "decoration separator")), + other => return Err(Error::Unexpected(other, "attribute separator")), } } self.scopes.pop(); @@ -2465,7 +2548,7 @@ impl Parser { module: &mut crate::Module, lookup_global_expression: &mut FastHashMap<&'a str, crate::Expression>, ) -> Result> { - // read decorations + // read attributes let mut binding = None; // Perspective is the default qualifier. let mut stage = None; @@ -2475,7 +2558,7 @@ impl Parser { if lexer.skip(Token::DoubleParen('[')) { let (mut bind_index, mut bind_group) = (None, None); - self.scopes.push(Scope::Decoration); + self.scopes.push(Scope::Attribute); loop { match lexer.next_ident()? { "binding" => { @@ -2527,14 +2610,14 @@ impl Parser { }; early_depth_test = Some(crate::EarlyDepthTest { conservative }); } - word => return Err(Error::UnknownDecoration(word)), + word => return Err(Error::UnknownAttribute(word)), } match lexer.next() { (Token::DoubleParen(']'), _) => { break; } (Token::Separator(','), _) => {} - other => return Err(Error::Unexpected(other, "decoration separator")), + other => return Err(Error::Unexpected(other, "attribute separator")), } } if let (Some(group), Some(index)) = (bind_group, bind_index) { @@ -2551,13 +2634,18 @@ impl Parser { (Token::Separator(';'), _) => {} (Token::Word("struct"), _) => { let name = lexer.next_ident()?; - let members = + let (members, span, alignment) = self.parse_struct_body(lexer, &mut module.types, &mut module.constants)?; let ty = module.types.fetch_or_append(crate::Type { name: Some(name.to_string()), inner: crate::TypeInner::Struct { - block: is_block, + level: if is_block { + crate::StructLevel::Root + } else { + crate::StructLevel::Normal { alignment } + }, members, + span, }, }); self.lookup_type.insert(name.to_owned(), ty); @@ -2575,7 +2663,7 @@ impl Parser { self.lookup_type.insert(name.to_owned(), ty); lexer.expect(Token::Separator(';'))?; } - (Token::Word("const"), _) => { + (Token::Word("let"), _) => { let (name, explicit_ty, _access) = self.parse_variable_ident_decl( lexer, &mut module.types, @@ -2602,7 +2690,7 @@ impl Parser { crate::ConstantInner::Composite { ty, components: _ } => ty == explicit_ty, }; if !type_match { - return Err(Error::ConstTypeMismatch(name, explicit_ty)); + return Err(Error::LetTypeMismatch(name, explicit_ty)); } //TODO: check `ty` against `const_handle`. lexer.expect(Token::Separator(';'))?; @@ -2663,7 +2751,7 @@ impl Parser { match binding { None => Ok(true), - // we had the decoration but no var? + // we had the attribute but no var? Some(_) => Err(Error::Other), } } @@ -2671,6 +2759,7 @@ impl Parser { pub fn parse<'a>(&mut self, source: &'a str) -> Result> { self.scopes.clear(); self.lookup_type.clear(); + self.layouter.clear(); let mut module = crate::Module::default(); let mut lexer = Lexer::new(source); @@ -2684,6 +2773,7 @@ impl Parser { log::error!("Reached the end of file, but scopes are not closed"); return Err(Error::Other.as_parse_error(lexer.source)); }; + module.apply_common_default_interpolation(); return Ok(module); } } diff --git a/third_party/rust/naga/src/front/wgsl/tests.rs b/third_party/rust/naga/src/front/wgsl/tests.rs index 64da1fbd464e..d7428b65b039 100644 --- a/third_party/rust/naga/src/front/wgsl/tests.rs +++ b/third_party/rust/naga/src/front/wgsl/tests.rs @@ -16,8 +16,8 @@ fn parse_comment() { #[test] fn parse_types() { - parse_str("const a : i32 = 2;").unwrap(); - assert!(parse_str("const a : x32 = 2;").is_err()); + parse_str("let a : i32 = 2;").unwrap(); + assert!(parse_str("let a : x32 = 2;").is_err()); parse_str("var t: texture_2d;").unwrap(); parse_str("var t: texture_cube_array;").unwrap(); parse_str("var t: texture_multisampled_2d;").unwrap(); @@ -30,14 +30,14 @@ fn parse_type_inference() { parse_str( " fn foo() { - const a = 2u; - const b: u32 = a; + let a = 2u; + let b: u32 = a; }", ) .unwrap(); assert!(parse_str( " - fn foo() { const c : i32 = 2.0; }", + fn foo() { let c : i32 = 2.0; }", ) .is_err()); } @@ -46,7 +46,7 @@ fn parse_type_inference() { fn parse_type_cast() { parse_str( " - const a : i32 = 2; + let a : i32 = 2; fn main() { var x: f32 = f32(a); x = f32(i32(a + 1) / 2); @@ -57,8 +57,8 @@ fn parse_type_cast() { parse_str( " fn main() { - const x: vec2 = vec2(1.0, 2.0); - const y: vec2 = vec2(x); + let x: vec2 = vec2(1.0, 2.0); + let y: vec2 = vec2(x); } ", ) @@ -201,7 +201,7 @@ fn parse_texture_load() { " var t: texture_3d; fn foo() { - const r: vec4 = textureLoad(t, vec3(0.0, 1.0, 2.0), 1); + let r: vec4 = textureLoad(t, vec3(0.0, 1.0, 2.0), 1); } ", ) @@ -210,7 +210,7 @@ fn parse_texture_load() { " var t: texture_multisampled_2d_array; fn foo() { - const r: vec4 = textureLoad(t, vec2(10, 20), 2, 3); + let r: vec4 = textureLoad(t, vec2(10, 20), 2, 3); } ", ) @@ -219,7 +219,7 @@ fn parse_texture_load() { " var t: [[access(read)]] texture_storage_1d_array; fn foo() { - const r: vec4 = textureLoad(t, 10, 2); + let r: vec4 = textureLoad(t, 10, 2); } ", ) @@ -247,8 +247,8 @@ fn parse_texture_query() { fn foo() { var dim: vec2 = textureDimensions(t); dim = textureDimensions(t, 0); - const layers: i32 = textureNumLayers(t); - const samples: i32 = textureNumSamples(t); + let layers: i32 = textureNumLayers(t); + let samples: i32 = textureNumSamples(t); } ", ) @@ -259,8 +259,8 @@ fn parse_texture_query() { fn parse_postfix() { parse_str( "fn foo() { - const x: f32 = vec4(1.0, 2.0, 3.0, 4.0).xyz.rgbr.aaaa.wz.g; - const y: f32 = fract(vec2(0.5, x)).x; + let x: f32 = vec4(1.0, 2.0, 3.0, 4.0).xyz.rgbr.aaaa.wz.g; + let y: f32 = fract(vec2(0.5, x)).x; }", ) .unwrap(); @@ -269,9 +269,9 @@ fn parse_postfix() { #[test] fn parse_expressions() { parse_str("fn foo() { - const x: f32 = select(0.0, 1.0, true); - const y: vec2 = select(vec2(1.0, 1.0), vec2(x, x), vec2(x < 0.5, x > 0.5)); - const z: bool = !(0.0 == 1.0); + let x: f32 = select(0.0, 1.0, true); + let y: vec2 = select(vec2(1.0, 1.0), vec2(x, x), vec2(x < 0.5, x > 0.5)); + let z: bool = !(0.0 == 1.0); }").unwrap(); } @@ -280,9 +280,27 @@ fn parse_pointers() { parse_str( "fn foo() { var x: f32 = 1.0; - const px = &x; - const py = frexp(0.5, px); + let px = &x; + let py = frexp(0.5, px); }", ) .unwrap(); } + +#[test] +fn parse_struct_instantiation() { + parse_str( + " + struct Foo { + a: f32; + b: vec3; + }; + + [[stage(fragment)]] + fn fs_main() { + var foo: Foo = Foo(0.0, vec3(0.0, 1.0, 42.0)); + } + ", + ) + .unwrap(); +} diff --git a/third_party/rust/naga/src/lib.rs b/third_party/rust/naga/src/lib.rs index 10cbdc1c8d13..b95fe251b4a1 100644 --- a/third_party/rust/naga/src/lib.rs +++ b/third_party/rust/naga/src/lib.rs @@ -166,8 +166,9 @@ pub enum BuiltIn { WorkGroupSize, } -/// Number of bytes. +/// Number of bytes per scalar. pub type Bytes = u8; +pub type Alignment = NonZeroU32; /// Number of components in a vector. #[repr(u8)] @@ -225,11 +226,23 @@ pub enum Interpolation { Linear, /// Indicates that no interpolation will be performed. Flat, - /// When used with multi-sampling rasterization, allow - /// a single interpolation location for an entire pixel. +} + +/// The sampling qualifiers of a binding or struct field. +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum Sampling { + /// Interpolate the value at the center of the pixel. + Center, + + /// Interpolate the value at a point that lies within all samples covered by + /// the fragment within the current primitive. In multisampling, use a + /// single value for all samples in the primitive. Centroid, - /// When used with multi-sampling rasterization, require - /// per-sample interpolation. + + /// Interpolate the value at each sample location. In multisampling, invoke + /// the fragment shader once per sample. Sample, } @@ -244,10 +257,8 @@ pub struct StructMember { pub ty: Handle, /// For I/O structs, defines the binding. pub binding: Option, - /// Overrides the size computed off the type. - pub size: Option, - /// Overrides the alignment computed off the type. - pub align: Option, + /// Offset from the beginning from the struct. + pub offset: u32, } /// The number of dimensions an image has. @@ -346,6 +357,18 @@ pub enum ImageClass { Storage(StorageFormat), } +/// Qualifier of the type level, at which a struct can be used. +#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +pub enum StructLevel { + /// This is a root level struct, it can't be nested inside + /// other composite types. + Root, + /// This is a normal struct, and it has to be aligned for nesting. + Normal { alignment: Alignment }, +} + /// A data type declared in the module. #[derive(Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize))] @@ -392,13 +415,13 @@ pub enum TypeInner { Array { base: Handle, size: ArraySize, - stride: Option, + stride: u32, }, /// User-defined structure. Struct { - /// This is a top-level host-shareable structure. - block: bool, + level: StructLevel, members: Vec, + span: u32, }, /// Possibly multidimensional array of texels. Image { @@ -454,7 +477,11 @@ pub enum Binding { /// Built-in shader variable. BuiltIn(BuiltIn), /// Indexed location. - Location(u32, Option), + Location { + location: u32, + interpolation: Option, + sampling: Option + }, } /// Pipeline binding information for global resources. @@ -672,6 +699,11 @@ pub enum Expression { }, /// Constant value. Constant(Handle), + /// Splat scalar into a vector. + Splat { + size: VectorSize, + value: Handle, + }, /// Composite expression. Compose { ty: Handle, diff --git a/third_party/rust/naga/src/proc/interpolator.rs b/third_party/rust/naga/src/proc/interpolator.rs new file mode 100644 index 000000000000..3a5e7e8cb78f --- /dev/null +++ b/third_party/rust/naga/src/proc/interpolator.rs @@ -0,0 +1,119 @@ +pub use crate::{Arena, Handle}; + +impl crate::Module { + /// Apply the usual default interpolation for vertex shader outputs and fragment shader inputs. + /// + /// For every [`Binding`] that is a vertex shader output or a fragment shader + /// input, and that has an `interpolation` or `sampling` of `None`, assign a + /// default interpolation and sampling as follows: + /// + /// - If the `Binding`'s type contains only 32-bit floating-point values or + /// vectors of such, default its interpolation to `Perspective` and its + /// sampling to `Center`. + /// + /// - Otherwise, mark its interpolation as `Flat`. + /// + /// When struct appear in input or output types, apply these rules to their + /// leaves, since those are the things that actually get assigned locations. + /// + /// This function is a utility front ends may use to satisfy the Naga IR's + /// requirement that all I/O `Binding`s from the vertex shader to the + /// fragment shader must have non-`None` `interpolation` values. This + /// requirement is meant to ensure that input languages' policies have been + /// applied appropriately. + /// + /// All the shader languages Naga supports have similar rules: + /// perspective-correct, center-sampled interpolation is the default for any + /// binding that can vary, and everything else either defaults to flat, or + /// requires an explicit flat qualifier/attribute/what-have-you. + /// + /// [`Binding`]: super::Binding + pub fn apply_common_default_interpolation(&mut self) { + use crate::{Binding, ScalarKind, Type, TypeInner}; + + /// Choose a default interpolation for a function argument or result. + /// + /// `binding` refers to the `Binding` whose type is `ty`. If `ty` is a struct, then it's the + /// bindings of the struct's members that we care about, and the binding of the struct + /// itself is meaningless, so `binding` should be `None`. + fn default_binding_or_struct(binding: &mut Option, + ty: Handle, + types: &mut Arena) + { + match types.get_mut(ty).inner { + // A struct. It's the individual members we care about, so recurse. + TypeInner::Struct { members: ref mut m, .. } => { + // To choose the right interpolations for `members`, we must consult other + // elements of `types`. But both `members` and the types it refers to are stored + // in `types`, and Rust won't let us mutate one element of the `Arena`'s `Vec` + // while reading others. + // + // So, temporarily swap the member list out its type, assign appropriate + // interpolations to its members, and then swap the list back in. + use std::mem::replace; + let mut members = replace(m, vec![]); + + for member in &mut members { + default_binding_or_struct(&mut member.binding, member.ty, types); + } + + // Swap the member list back in. It's essential that we call `types.get_mut` + // afresh here, rather than just using `m`: it's only because `m` was dead that + // we were able to pass `types` to the recursive call. + match types.get_mut(ty).inner { + TypeInner::Struct { members: ref mut m, .. } => replace(m, members), + _ => unreachable!("ty must be a struct"), + }; + } + + // Some interpolatable type. + // + // GLSL has 64-bit floats, but it won't interpolate them. WGSL and MSL only have + // 32-bit floats. SPIR-V has 16- and 64-bit float capabilities, but Vulkan is vague + // about what can and cannot be interpolated. + TypeInner::Scalar { kind: ScalarKind::Float, width: 4 } | + TypeInner::Vector { kind: ScalarKind::Float, width: 4, .. } => { + // unwrap: all `EntryPoint` arguments or return values must either be structures + // or have a `Binding`. + let binding = binding.as_mut().unwrap(); + if let Binding::Location { ref mut interpolation, ref mut sampling, .. } = *binding { + if interpolation.is_none() { + *interpolation = Some(crate::Interpolation::Perspective); + } + if sampling.is_none() && *interpolation != Some(crate::Interpolation::Flat) { + *sampling = Some(crate::Sampling::Center); + } + } + } + + // Some type that can't be interpolated. + _ => { + // unwrap: all `EntryPoint` arguments or return values must either be structures + // or have a `Binding`. + let binding = binding.as_mut().unwrap(); + if let Binding::Location { ref mut interpolation, ref mut sampling, .. } = *binding { + *interpolation = Some(crate::Interpolation::Flat); + *sampling = None; + } + } + } + } + + for ep in &mut self.entry_points { + let function = &mut ep.function; + match ep.stage { + crate::ShaderStage::Fragment => { + for arg in &mut function.arguments { + default_binding_or_struct(&mut arg.binding, arg.ty, &mut self.types); + } + } + crate::ShaderStage::Vertex => { + if let Some(result) = function.result.as_mut() { + default_binding_or_struct(&mut result.binding, result.ty, &mut self.types); + } + } + _ => (), + } + } + } +} diff --git a/third_party/rust/naga/src/proc/layouter.rs b/third_party/rust/naga/src/proc/layouter.rs deleted file mode 100644 index d8674f846eef..000000000000 --- a/third_party/rust/naga/src/proc/layouter.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::arena::{Arena, Handle}; -use std::{num::NonZeroU32, ops}; - -pub type Alignment = NonZeroU32; - -/// Alignment information for a type. -#[derive(Clone, Copy, Debug, Hash, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] -pub struct TypeLayout { - pub size: u32, - pub alignment: Alignment, -} - -/// Helper processor that derives the sizes of all types. -/// It uses the default layout algorithm/table, described in -/// https://github.com/gpuweb/gpuweb/issues/1393 -#[derive(Debug, Default)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] -pub struct Layouter { - layouts: Vec, -} - -impl Layouter { - pub fn new(types: &Arena, constants: &Arena) -> Self { - let mut this = Layouter::default(); - this.initialize(types, constants); - this - } - - pub fn round_up(alignment: NonZeroU32, offset: u32) -> u32 { - match offset & (alignment.get() - 1) { - 0 => offset, - other => offset + alignment.get() - other, - } - } - - pub fn member_placement( - &self, - offset: u32, - member: &crate::StructMember, - ) -> (ops::Range, NonZeroU32) { - let layout = self.layouts[member.ty.index()]; - let alignment = member.align.unwrap_or(layout.alignment); - let start = Self::round_up(alignment, offset); - let end = start - + match member.size { - Some(size) => size.get(), - None => layout.size, - }; - (start..end, alignment) - } - - pub fn initialize(&mut self, types: &Arena, constants: &Arena) { - use crate::TypeInner as Ti; - - self.layouts.clear(); - self.layouts.reserve(types.len()); - - for (_, ty) in types.iter() { - self.layouts.push(match ty.inner { - Ti::Scalar { kind: _, width } => TypeLayout { - size: width as u32, - alignment: Alignment::new(width as u32).unwrap(), - }, - Ti::Vector { - size, - kind: _, - width, - } => TypeLayout { - size: (size as u8 * width) as u32, - alignment: { - let count = if size >= crate::VectorSize::Tri { 4 } else { 2 }; - Alignment::new((count * width) as u32).unwrap() - }, - }, - Ti::Matrix { - columns, - rows, - width, - } => TypeLayout { - size: (columns as u8 * rows as u8 * width) as u32, - alignment: { - let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 }; - Alignment::new((count * width) as u32).unwrap() - }, - }, - Ti::Pointer { .. } | Ti::ValuePointer { .. } => TypeLayout { - size: 4, - alignment: Alignment::new(1).unwrap(), - }, - Ti::Array { base, size, stride } => { - let count = match size { - crate::ArraySize::Constant(handle) => { - constants[handle].to_array_length().unwrap() - } - // A dynamically-sized array has to have at least one element - crate::ArraySize::Dynamic => 1, - }; - let stride = match stride { - Some(value) => value, - None => { - let layout = &self.layouts[base.index()]; - let stride = Self::round_up(layout.alignment, layout.size); - Alignment::new(stride).unwrap() - } - }; - TypeLayout { - size: count * stride.get(), - alignment: stride, - } - } - Ti::Struct { - block: _, - ref members, - } => { - let mut total = 0; - let mut biggest_alignment = Alignment::new(1).unwrap(); - for member in members { - let (placement, alignment) = self.member_placement(total, member); - biggest_alignment = biggest_alignment.max(alignment); - total = placement.end; - } - TypeLayout { - size: Self::round_up(biggest_alignment, total), - alignment: biggest_alignment, - } - } - Ti::Image { .. } | Ti::Sampler { .. } => TypeLayout { - size: 0, - alignment: Alignment::new(1).unwrap(), - }, - }); - } - } -} - -impl ops::Index> for Layouter { - type Output = TypeLayout; - fn index(&self, handle: Handle) -> &TypeLayout { - &self.layouts[handle.index()] - } -} diff --git a/third_party/rust/naga/src/proc/mod.rs b/third_party/rust/naga/src/proc/mod.rs index 2bb277c70379..27f5039f4e2b 100644 --- a/third_party/rust/naga/src/proc/mod.rs +++ b/third_party/rust/naga/src/proc/mod.rs @@ -1,11 +1,10 @@ //! Module processing functionality. -mod layouter; +mod interpolator; mod namer; mod terminator; mod typifier; -pub use layouter::{Alignment, Layouter, TypeLayout}; pub use namer::{EntryPointIndex, NameKey, Namer}; pub use terminator::ensure_block_returns; pub use typifier::{ResolveContext, ResolveError, TypeResolution}; @@ -61,6 +60,8 @@ impl super::ScalarValue { } } +pub const POINTER_SPAN: u32 = 4; + impl super::TypeInner { pub fn scalar_kind(&self) -> Option { match *self { @@ -71,6 +72,39 @@ impl super::TypeInner { _ => None, } } + + pub fn span(&self, constants: &super::Arena) -> u32 { + match *self { + Self::Scalar { kind: _, width } => width as u32, + Self::Vector { + size, + kind: _, + width, + } => (size as u8 * width) as u32, + Self::Matrix { + columns, + rows, + width, + } => (columns as u8 * rows as u8 * width) as u32, + Self::Pointer { .. } | Self::ValuePointer { .. } => POINTER_SPAN, + Self::Array { + base: _, + size, + stride, + } => { + let count = match size { + super::ArraySize::Constant(handle) => { + constants[handle].to_array_length().unwrap() + } + // A dynamically-sized array has to have at least one element + super::ArraySize::Dynamic => 1, + }; + count * stride + } + Self::Struct { span, .. } => span, + Self::Image { .. } | Self::Sampler { .. } => 0, + } + } } impl super::MathFunction { @@ -179,7 +213,7 @@ impl crate::Binding { pub fn to_built_in(&self) -> Option { match *self { Self::BuiltIn(bi) => Some(bi), - Self::Location(..) => None, + Self::Location { .. } => None, } } } diff --git a/third_party/rust/naga/src/proc/namer.rs b/third_party/rust/naga/src/proc/namer.rs index 87ef357ac033..7f62ff170140 100644 --- a/third_party/rust/naga/src/proc/namer.rs +++ b/third_party/rust/naga/src/proc/namer.rs @@ -77,11 +77,7 @@ impl Namer { let ty_name = self.call_or(&ty.name, "type"); output.insert(NameKey::Type(ty_handle), ty_name); - if let crate::TypeInner::Struct { - block: _, - ref members, - } = ty.inner - { + if let crate::TypeInner::Struct { ref members, .. } = ty.inner { for (index, member) in members.iter().enumerate() { let name = self.call_or(&member.name, "member"); output.insert(NameKey::StructMember(ty_handle, index as u32), name); diff --git a/third_party/rust/naga/src/proc/typifier.rs b/third_party/rust/naga/src/proc/typifier.rs index 3183c5bd9ea4..1af4cf8b59a3 100644 --- a/third_party/rust/naga/src/proc/typifier.rs +++ b/third_party/rust/naga/src/proc/typifier.rs @@ -62,6 +62,18 @@ impl Clone for TypeResolution { } } +impl crate::ConstantInner { + pub fn resolve_type(&self) -> TypeResolution { + match *self { + Self::Scalar { width, ref value } => TypeResolution::Value(crate::TypeInner::Scalar { + kind: value.scalar_kind(), + width, + }), + Self::Composite { ty, components: _ } => TypeResolution::Handle(ty), + } + } +} + #[derive(Clone, Debug, Error, PartialEq)] pub enum ResolveError { #[error("Index {index} is out of bounds for expression {expr:?}")] @@ -79,6 +91,8 @@ pub enum ResolveError { ty: Handle, indexed: bool, }, + #[error("Invalid scalar {0:?}")] + InvalidScalar(Handle), #[error("Invalid pointer {0:?}")] InvalidPointer(Handle), #[error("Invalid image {0:?}")] @@ -178,10 +192,7 @@ impl<'a> ResolveContext<'a> { }) } Ti::Array { base, .. } => TypeResolution::Handle(base), - Ti::Struct { - block: _, - ref members, - } => { + Ti::Struct { ref members, .. } => { let member = members .get(index as usize) .ok_or(ResolveError::OutOfBoundsIndex { expr: base, index })?; @@ -234,10 +245,7 @@ impl<'a> ResolveContext<'a> { class, } } - Ti::Struct { - block: _, - ref members, - } => { + Ti::Struct { ref members, .. } => { let member = members .get(index as usize) .ok_or(ResolveError::OutOfBoundsIndex { expr: base, index })?; @@ -271,6 +279,15 @@ impl<'a> ResolveContext<'a> { } crate::ConstantInner::Composite { ty, components: _ } => TypeResolution::Handle(ty), }, + crate::Expression::Splat { size, value } => match *past(value).inner_with(types) { + Ti::Scalar { kind, width } => { + TypeResolution::Value(Ti::Vector { size, kind, width }) + } + ref other => { + log::error!("Scalar type {:?}", other); + return Err(ResolveError::InvalidScalar(value)); + } + }, crate::Expression::Compose { ty, .. } => TypeResolution::Handle(ty), crate::Expression::FunctionArgument(index) => { TypeResolution::Handle(self.arguments[index as usize].ty) diff --git a/third_party/rust/naga/src/valid/analyzer.rs b/third_party/rust/naga/src/valid/analyzer.rs index 94d7fecc9b86..7b0fff4df718 100644 --- a/third_party/rust/naga/src/valid/analyzer.rs +++ b/third_party/rust/naga/src/valid/analyzer.rs @@ -318,6 +318,10 @@ impl FunctionInfo { }, // always uniform E::Constant(_) => Uniformity::new(), + E::Splat { size: _, value } => Uniformity { + non_uniform_result: self.add_ref(value), + requirements: UniformityRequirements::empty(), + }, E::Compose { ref components, .. } => { let non_uniform_result = components .iter() @@ -340,7 +344,10 @@ impl FunctionInfo { _ => false, }, // only flat inputs are uniform - Some(crate::Binding::Location(_, Some(crate::Interpolation::Flat))) => true, + Some(crate::Binding::Location { + interpolation: Some(crate::Interpolation::Flat), + .. + }) => true, _ => false, }; Uniformity { diff --git a/third_party/rust/naga/src/valid/compose.rs b/third_party/rust/naga/src/valid/compose.rs new file mode 100644 index 000000000000..e25a7379d0aa --- /dev/null +++ b/third_party/rust/naga/src/valid/compose.rs @@ -0,0 +1,131 @@ +use crate::{ + arena::{Arena, Handle}, + proc::TypeResolution, +}; + +#[derive(Clone, Debug, thiserror::Error)] +#[cfg_attr(test, derive(PartialEq))] +pub enum ComposeError { + #[error("Compose type {0:?} doesn't exist")] + TypeDoesntExist(Handle), + #[error("Composing of type {0:?} can't be done")] + Type(Handle), + #[error("Composing expects {expected} components but {given} were given")] + ComponentCount { given: u32, expected: u32 }, + #[error("Composing {index}'s component type is not expected")] + ComponentType { index: u32 }, +} + +pub fn validate_compose( + self_ty_handle: Handle, + constant_arena: &Arena, + type_arena: &Arena, + component_resolutions: impl ExactSizeIterator, +) -> Result<(), ComposeError> { + use crate::TypeInner as Ti; + + let self_ty = type_arena + .try_get(self_ty_handle) + .ok_or(ComposeError::TypeDoesntExist(self_ty_handle))?; + match self_ty.inner { + // vectors are composed from scalars or other vectors + Ti::Vector { size, kind, width } => { + let mut total = 0; + for (index, comp_res) in component_resolutions.enumerate() { + total += match *comp_res.inner_with(type_arena) { + Ti::Scalar { + kind: comp_kind, + width: comp_width, + } if comp_kind == kind && comp_width == width => 1, + Ti::Vector { + size: comp_size, + kind: comp_kind, + width: comp_width, + } if comp_kind == kind && comp_width == width => comp_size as u32, + ref other => { + log::error!("Vector component[{}] type {:?}", index, other); + return Err(ComposeError::ComponentType { + index: index as u32, + }); + } + }; + } + if size as u32 != total { + return Err(ComposeError::ComponentCount { + expected: size as u32, + given: total, + }); + } + } + // matrix are composed from column vectors + Ti::Matrix { + columns, + rows, + width, + } => { + let inner = Ti::Vector { + size: rows, + kind: crate::ScalarKind::Float, + width, + }; + if columns as usize != component_resolutions.len() { + return Err(ComposeError::ComponentCount { + expected: columns as u32, + given: component_resolutions.len() as u32, + }); + } + for (index, comp_res) in component_resolutions.enumerate() { + if comp_res.inner_with(type_arena) != &inner { + log::error!("Matrix component[{}] type {:?}", index, comp_res); + return Err(ComposeError::ComponentType { + index: index as u32, + }); + } + } + } + Ti::Array { + base, + size: crate::ArraySize::Constant(handle), + stride: _, + } => { + let count = constant_arena[handle].to_array_length().unwrap(); + if count as usize != component_resolutions.len() { + return Err(ComposeError::ComponentCount { + expected: count, + given: component_resolutions.len() as u32, + }); + } + for (index, comp_res) in component_resolutions.enumerate() { + if comp_res.inner_with(type_arena) != &type_arena[base].inner { + log::error!("Array component[{}] type {:?}", index, comp_res); + return Err(ComposeError::ComponentType { + index: index as u32, + }); + } + } + } + Ti::Struct { ref members, .. } => { + if members.len() != component_resolutions.len() { + return Err(ComposeError::ComponentCount { + given: component_resolutions.len() as u32, + expected: members.len() as u32, + }); + } + for (index, (member, comp_res)) in members.iter().zip(component_resolutions).enumerate() + { + if comp_res.inner_with(type_arena) != &type_arena[member.ty].inner { + log::error!("Struct component[{}] type {:?}", index, comp_res); + return Err(ComposeError::ComponentType { + index: index as u32, + }); + } + } + } + ref other => { + log::error!("Composing of {:?}", other); + return Err(ComposeError::Type(self_ty_handle)); + } + } + + Ok(()) +} diff --git a/third_party/rust/naga/src/valid/expression.rs b/third_party/rust/naga/src/valid/expression.rs index b21f534886c8..1ec603ce71de 100644 --- a/third_party/rust/naga/src/valid/expression.rs +++ b/third_party/rust/naga/src/valid/expression.rs @@ -1,4 +1,4 @@ -use super::{FunctionInfo, ShaderStages, TypeFlags}; +use super::{compose::validate_compose, ComposeError, FunctionInfo, ShaderStages, TypeFlags}; use crate::{ arena::{Arena, Handle}, proc::ResolveError, @@ -31,14 +31,10 @@ pub enum ExpressionError { InvalidPointerType(Handle), #[error("Array length of {0:?} can't be done")] InvalidArrayType(Handle), - #[error("Compose type {0:?} doesn't exist")] - ComposeTypeDoesntExist(Handle), - #[error("Composing of type {0:?} can't be done")] - InvalidComposeType(Handle), - #[error("Composing expects {expected} components but {given} were given")] - InvalidComposeCount { given: u32, expected: u32 }, - #[error("Composing {0}'s component {1:?} is not expected")] - InvalidComponentType(u32, Handle), + #[error("Splatting {0:?} can't be done")] + InvalidSplatType(Handle), + #[error(transparent)] + Compose(#[from] ComposeError), #[error("Operation {0:?} can't work with {1:?}")] InvalidUnaryOperandType(crate::UnaryOperator, Handle), #[error("Operation {0:?} can't work with {1:?} and {2:?}")] @@ -179,10 +175,7 @@ impl super::Validator { } => module.constants[handle].to_array_length().unwrap(), Ti::Array { .. } => !0, // can't statically know, but need run-time checks Ti::Pointer { .. } => !0, //TODO - Ti::Struct { - ref members, - block: _, - } => members.len() as u32, + Ti::Struct { ref members, .. } => members.len() as u32, ref other => { log::error!("Indexing of {:?}", other); return Err(ExpressionError::InvalidBaseType(base)); @@ -200,121 +193,25 @@ impl super::Validator { .ok_or(ExpressionError::ConstantDoesntExist(handle))?; ShaderStages::all() } + E::Splat { size: _, value } => match *resolver.resolve(value)? { + Ti::Scalar { .. } => ShaderStages::all(), + ref other => { + log::error!("Splat scalar type {:?}", other); + return Err(ExpressionError::InvalidSplatType(value)); + } + }, E::Compose { ref components, ty } => { - match module - .types - .try_get(ty) - .ok_or(ExpressionError::ComposeTypeDoesntExist(ty))? - .inner - { - // vectors are composed from scalars or other vectors - Ti::Vector { size, kind, width } => { - let mut total = 0; - for (index, &comp) in components.iter().enumerate() { - total += match *resolver.resolve(comp)? { - Ti::Scalar { - kind: comp_kind, - width: comp_width, - } if comp_kind == kind && comp_width == width => 1, - Ti::Vector { - size: comp_size, - kind: comp_kind, - width: comp_width, - } if comp_kind == kind && comp_width == width => comp_size as u32, - ref other => { - log::error!("Vector component[{}] type {:?}", index, other); - return Err(ExpressionError::InvalidComponentType( - index as u32, - comp, - )); - } - }; - } - if size as u32 != total { - return Err(ExpressionError::InvalidComposeCount { - expected: size as u32, - given: total, - }); - } - } - // matrix are composed from column vectors - Ti::Matrix { - columns, - rows, - width, - } => { - let inner = Ti::Vector { - size: rows, - kind: Sk::Float, - width, - }; - if columns as usize != components.len() { - return Err(ExpressionError::InvalidComposeCount { - expected: columns as u32, - given: components.len() as u32, - }); - } - for (index, &comp) in components.iter().enumerate() { - let tin = resolver.resolve(comp)?; - if tin != &inner { - log::error!("Matrix component[{}] type {:?}", index, tin); - return Err(ExpressionError::InvalidComponentType( - index as u32, - comp, - )); - } - } - } - Ti::Array { - base, - size: crate::ArraySize::Constant(handle), - stride: _, - } => { - let count = module.constants[handle].to_array_length().unwrap(); - if count as usize != components.len() { - return Err(ExpressionError::InvalidComposeCount { - expected: count, - given: components.len() as u32, - }); - } - let base_inner = &module.types[base].inner; - for (index, &comp) in components.iter().enumerate() { - let tin = resolver.resolve(comp)?; - if tin != base_inner { - log::error!("Array component[{}] type {:?}", index, tin); - return Err(ExpressionError::InvalidComponentType( - index as u32, - comp, - )); - } - } - } - Ti::Struct { - block: _, - ref members, - } => { - for (index, (member, &comp)) in members.iter().zip(components).enumerate() { - let tin = resolver.resolve(comp)?; - if tin != &module.types[member.ty].inner { - log::error!("Struct component[{}] type {:?}", index, tin); - return Err(ExpressionError::InvalidComponentType( - index as u32, - comp, - )); - } - } - if members.len() != components.len() { - return Err(ExpressionError::InvalidComposeCount { - given: components.len() as u32, - expected: members.len() as u32, - }); - } - } - ref other => { - log::error!("Composing of {:?}", other); - return Err(ExpressionError::InvalidComposeType(ty)); + for &handle in components { + if handle >= root { + return Err(ExpressionError::ForwardDependency(handle)); } } + validate_compose( + ty, + &module.constants, + &module.types, + components.iter().map(|&handle| info[handle].ty.clone()), + )?; ShaderStages::all() } E::FunctionArgument(index) => { @@ -598,10 +495,10 @@ impl super::Validator { }; let good = match query { crate::ImageQuery::NumLayers => arrayed, + crate::ImageQuery::Size { level: None } => true, crate::ImageQuery::Size { level: Some(_) } | crate::ImageQuery::NumLevels => can_level, - crate::ImageQuery::Size { level: None } - | crate::ImageQuery::NumSamples => !can_level, + crate::ImageQuery::NumSamples => !can_level, }; if !good { return Err(ExpressionError::InvalidImageClass(class)); @@ -946,7 +843,7 @@ impl super::Validator { _ => return Err(ExpressionError::InvalidArgumentType(fun, 0, arg)), } } - Mf::Atan2 | Mf::Pow | Mf::Distance => { + Mf::Atan2 | Mf::Pow | Mf::Distance | Mf::Step => { let arg1_ty = match (arg1_ty, arg2_ty) { (Some(ty1), None) => ty1, _ => return Err(ExpressionError::WrongArgumentCount(fun)), @@ -1003,7 +900,7 @@ impl super::Validator { )); } } - Mf::Dot | Mf::Outer | Mf::Cross | Mf::Step | Mf::Reflect => { + Mf::Dot | Mf::Outer | Mf::Cross | Mf::Reflect => { let arg1_ty = match (arg1_ty, arg2_ty) { (Some(ty1), None) => ty1, _ => return Err(ExpressionError::WrongArgumentCount(fun)), diff --git a/third_party/rust/naga/src/valid/interface.rs b/third_party/rust/naga/src/valid/interface.rs index 576f4448c33e..63541895b9ac 100644 --- a/third_party/rust/naga/src/valid/interface.rs +++ b/third_party/rust/naga/src/valid/interface.rs @@ -36,6 +36,8 @@ pub enum VaryingError { InvalidType(Handle), #[error("Interpolation is not valid")] InvalidInterpolation, + #[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")] + MissingInterpolation, #[error("BuiltIn {0:?} is not available at this stage")] InvalidBuiltInStage(crate::BuiltIn), #[error("BuiltIn type for {0:?} is invalid")] @@ -206,24 +208,37 @@ impl VaryingContext<'_> { return Err(VaryingError::InvalidBuiltInType(built_in)); } } - crate::Binding::Location(location, interpolation) => { + crate::Binding::Location { location, interpolation, sampling } => { if !self.location_mask.insert(location as usize) { return Err(VaryingError::BindingCollision { location }); } - let needs_interpolation = - self.stage == crate::ShaderStage::Fragment && !self.output; - if !needs_interpolation && interpolation.is_some() { - return Err(VaryingError::InvalidInterpolation); - } + + // Values passed from the vertex shader to the fragment shader must have their + // interpolation defaulted (i.e. not `None`) by the front end, as appropriate for + // that language. For anything other than floating-point scalars and vectors, the + // interpolation must be `Flat`. + let needs_interpolation = match self.stage { + crate::ShaderStage::Vertex => self.output, + crate::ShaderStage::Fragment => !self.output, + _ => false, + }; + + // It doesn't make sense to specify a sampling when `interpolation` is `Flat`, but + // SPIR-V and GLSL both explicitly tolerate such combinations of decorators / + // qualifiers, so we won't complain about that here. + let _ = sampling; + match ty_inner.scalar_kind() { - Some(crate::ScalarKind::Float) => {} - Some(_) - if needs_interpolation - && interpolation != Some(crate::Interpolation::Flat) => - { - return Err(VaryingError::InvalidInterpolation); + Some(crate::ScalarKind::Float) => { + if needs_interpolation && interpolation.is_none() { + return Err(VaryingError::MissingInterpolation); + } + } + Some(_) => { + if needs_interpolation && interpolation != Some(crate::Interpolation::Flat) { + return Err(VaryingError::InvalidInterpolation); + } } - Some(_) => {} None => return Err(VaryingError::InvalidType(self.ty)), } } @@ -239,8 +254,9 @@ impl VaryingContext<'_> { match self.types[self.ty].inner { //TODO: check the member types crate::TypeInner::Struct { - block: false, + level: crate::StructLevel::Normal { .. }, ref members, + .. } => { for (index, member) in members.iter().enumerate() { self.ty = member.ty; @@ -272,12 +288,9 @@ impl super::Validator { let (allowed_storage_access, required_type_flags, is_resource) = match var.class { crate::StorageClass::Function => return Err(GlobalVariableError::InvalidUsage), crate::StorageClass::Storage => { - if let Err((ty_handle, ref disalignment)) = type_info.storage_layout { + if let Err((ty_handle, disalignment)) = type_info.storage_layout { if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) { - return Err(GlobalVariableError::Alignment( - ty_handle, - disalignment.clone(), - )); + return Err(GlobalVariableError::Alignment(ty_handle, disalignment)); } } ( @@ -287,12 +300,9 @@ impl super::Validator { ) } crate::StorageClass::Uniform => { - if let Err((ty_handle, ref disalignment)) = type_info.uniform_layout { + if let Err((ty_handle, disalignment)) = type_info.uniform_layout { if self.flags.contains(ValidationFlags::STRUCT_LAYOUTS) { - return Err(GlobalVariableError::Alignment( - ty_handle, - disalignment.clone(), - )); + return Err(GlobalVariableError::Alignment(ty_handle, disalignment)); } } ( diff --git a/third_party/rust/naga/src/valid/mod.rs b/third_party/rust/naga/src/valid/mod.rs index 0ecf12e3322c..9ef3bb312168 100644 --- a/third_party/rust/naga/src/valid/mod.rs +++ b/third_party/rust/naga/src/valid/mod.rs @@ -1,4 +1,5 @@ mod analyzer; +mod compose; mod expression; mod function; mod interface; @@ -6,7 +7,6 @@ mod r#type; use crate::{ arena::{Arena, Handle}, - proc::Layouter, FastHashSet, }; use bit_set::BitSet; @@ -16,6 +16,7 @@ use std::ops; // merge the corresponding matches over expressions and statements. pub use analyzer::{ExpressionInfo, FunctionInfo, GlobalUse, Uniformity, UniformityRequirements}; +pub use compose::ComposeError; pub use expression::ExpressionError; pub use function::{CallError, FunctionError, LocalVariableError}; pub use interface::{EntryPointError, GlobalVariableError, VaryingError}; @@ -34,6 +35,8 @@ bitflags::bitflags! { const CONTROL_FLOW_UNIFORMITY = 0x4; /// Host-shareable structure layouts. const STRUCT_LAYOUTS = 0x8; + /// Constants. + const CONSTANTS = 0x10; } } @@ -54,7 +57,6 @@ bitflags::bitflags! { pub struct ModuleInfo { functions: Vec, entry_points: Vec, - pub layouter: Layouter, } impl ops::Index> for ModuleInfo { @@ -83,6 +85,8 @@ pub enum ConstantError { UnresolvedComponent(Handle), #[error("The array size handle {0:?} can not be resolved")] UnresolvedSize(Handle), + #[error(transparent)] + Compose(#[from] ComposeError), } #[derive(Clone, Debug, thiserror::Error)] @@ -193,25 +197,25 @@ impl Validator { } crate::ConstantInner::Composite { ty, ref components } => { match types[ty].inner { - crate::TypeInner::Array { - size: crate::ArraySize::Dynamic, - .. - } => { - return Err(ConstantError::InvalidType); - } crate::TypeInner::Array { size: crate::ArraySize::Constant(size_handle), .. - } => { - if handle <= size_handle { - return Err(ConstantError::UnresolvedSize(size_handle)); - } + } if handle <= size_handle => { + return Err(ConstantError::UnresolvedSize(size_handle)); } - _ => {} //TODO + _ => {} } if let Some(&comp) = components.iter().find(|&&comp| handle <= comp) { return Err(ConstantError::UnresolvedComponent(comp)); } + compose::validate_compose( + ty, + constants, + types, + components + .iter() + .map(|&component| constants[component].inner.resolve_type()), + )?; } } Ok(()) @@ -221,21 +225,21 @@ impl Validator { pub fn validate(&mut self, module: &crate::Module) -> Result { self.reset_types(module.types.len()); - let layouter = Layouter::new(&module.types, &module.constants); - - for (handle, constant) in module.constants.iter() { - self.validate_constant(handle, &module.constants, &module.types) - .map_err(|error| ValidationError::Constant { - handle, - name: constant.name.clone().unwrap_or_default(), - error, - })?; + if self.flags.contains(ValidationFlags::CONSTANTS) { + for (handle, constant) in module.constants.iter() { + self.validate_constant(handle, &module.constants, &module.types) + .map_err(|error| ValidationError::Constant { + handle, + name: constant.name.clone().unwrap_or_default(), + error, + })?; + } } // doing after the globals, so that `type_flags` is ready for (handle, ty) in module.types.iter() { let ty_info = self - .validate_type(ty, handle, &module.constants, &layouter) + .validate_type(handle, &module.types, &module.constants) .map_err(|error| ValidationError::Type { handle, name: ty.name.clone().unwrap_or_default(), @@ -256,7 +260,6 @@ impl Validator { let mut mod_info = ModuleInfo { functions: Vec::with_capacity(module.functions.len()), entry_points: Vec::with_capacity(module.entry_points.len()), - layouter, }; for (handle, fun) in module.functions.iter() { diff --git a/third_party/rust/naga/src/valid/type.rs b/third_party/rust/naga/src/valid/type.rs index c3622f289e04..ff34e81fe8b7 100644 --- a/third_party/rust/naga/src/valid/type.rs +++ b/third_party/rust/naga/src/valid/type.rs @@ -1,7 +1,4 @@ -use crate::{ - arena::{Arena, Handle}, - proc::Layouter, -}; +use crate::arena::{Arena, Handle}; bitflags::bitflags! { #[repr(transparent)] @@ -19,14 +16,20 @@ bitflags::bitflags! { } } -#[derive(Clone, Debug, thiserror::Error)] +#[derive(Clone, Copy, Debug, thiserror::Error)] pub enum Disalignment { #[error("The array stride {stride} is not a multiple of the required alignment {alignment}")] ArrayStride { stride: u32, alignment: u32 }, - #[error("The struct size {size}, is not a multiple of the required alignment {alignment}")] - StructSize { size: u32, alignment: u32 }, + #[error("The struct span {span}, is not a multiple of the required alignment {alignment}")] + StructSpan { span: u32, alignment: u32 }, + #[error("The struct span {alignment}, is not a multiple of the member[{member_index}] alignment {member_alignment}")] + StructAlignment { + alignment: u32, + member_index: u32, + member_alignment: u32, + }, #[error("The struct member[{index}] offset {offset} is not a multiple of the required alignment {alignment}")] - Member { + MemberOffset { index: u32, offset: u32, alignment: u32, @@ -49,26 +52,66 @@ pub enum TypeError { InvalidArrayBaseType(Handle), #[error("The constant {0:?} can not be used for an array size")] InvalidArraySizeConstant(Handle), - #[error( - "Array stride {stride} is not a multiple of the base element alignment {base_alignment}" - )] - UnalignedArrayStride { stride: u32, base_alignment: u32 }, #[error("Array stride {stride} is smaller than the base element size {base_size}")] InsufficientArrayStride { stride: u32, base_size: u32 }, #[error("Field '{0}' can't be dynamically-sized, has type {1:?}")] InvalidDynamicArray(String, Handle), - #[error("Structure member[{index}] size {size} is not a sufficient to hold {base_size}")] - InsufficientMemberSize { - index: u32, - size: u32, - base_size: u32, - }, + #[error("Structure member[{index}] at {offset} overlaps the previous member")] + MemberOverlap { index: u32, offset: u32 }, + #[error( + "Structure member[{index}] at {offset} and size {size} crosses the structure boundary" + )] + MemberOutOfBounds { index: u32, offset: u32, size: u32 }, #[error("The composite type contains a block structure")] NestedBlock, } // Only makes sense if `flags.contains(HOST_SHARED)` -type LayoutCompatibility = Result<(), (Handle, Disalignment)>; +type LayoutCompatibility = Result, (Handle, Disalignment)>; + +fn check_member_layout( + accum: &mut LayoutCompatibility, + member: &crate::StructMember, + member_index: u32, + member_layout: LayoutCompatibility, + struct_level: crate::StructLevel, + ty_handle: Handle, +) { + *accum = match (*accum, member_layout) { + (Ok(cur_alignment), Ok(align)) => { + let align = align.unwrap().get(); + if member.offset % align != 0 { + Err(( + ty_handle, + Disalignment::MemberOffset { + index: member_index, + offset: member.offset, + alignment: align, + }, + )) + } else { + match struct_level { + crate::StructLevel::Normal { alignment } if alignment.get() % align != 0 => { + Err(( + ty_handle, + Disalignment::StructAlignment { + alignment: alignment.get(), + member_index, + member_alignment: align, + }, + )) + } + _ => { + let combined_alignment = + ((cur_alignment.unwrap().get() - 1) | (align - 1)) + 1; + Ok(crate::Alignment::new(combined_alignment)) + } + } + } + } + (Err(e), _) | (_, Err(e)) => Err(e), + }; +} // For the uniform buffer alignment, array strides and struct sizes must be multiples of 16. const UNIFORM_LAYOUT_ALIGNMENT_MASK: u32 = 0xF; @@ -81,19 +124,20 @@ pub(super) struct TypeInfo { } impl TypeInfo { - fn new() -> Self { + fn dummy() -> Self { TypeInfo { flags: TypeFlags::empty(), - uniform_layout: Ok(()), - storage_layout: Ok(()), + uniform_layout: Ok(None), + storage_layout: Ok(None), } } - fn from_flags(flags: TypeFlags) -> Self { + fn new(flags: TypeFlags, align: u32) -> Self { + let alignment = crate::Alignment::new(align); TypeInfo { flags, - uniform_layout: Ok(()), - storage_layout: Ok(()), + uniform_layout: Ok(alignment), + storage_layout: Ok(alignment), } } } @@ -108,45 +152,64 @@ impl super::Validator { pub(super) fn reset_types(&mut self, size: usize) { self.types.clear(); - self.types.resize(size, TypeInfo::new()); + self.types.resize(size, TypeInfo::dummy()); } pub(super) fn validate_type( &self, - ty: &crate::Type, handle: Handle, + types: &Arena, constants: &Arena, - layouter: &Layouter, ) -> Result { use crate::TypeInner as Ti; - Ok(match ty.inner { - Ti::Scalar { kind, width } | Ti::Vector { kind, width, .. } => { + Ok(match types[handle].inner { + Ti::Scalar { kind, width } => { if !Self::check_width(kind, width) { return Err(TypeError::InvalidWidth(kind, width)); } - TypeInfo::from_flags( + TypeInfo::new( TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::INTERFACE | TypeFlags::HOST_SHARED, + width as u32, ) } - Ti::Matrix { width, .. } => { + Ti::Vector { size, kind, width } => { + if !Self::check_width(kind, width) { + return Err(TypeError::InvalidWidth(kind, width)); + } + let count = if size >= crate::VectorSize::Tri { 4 } else { 2 }; + TypeInfo::new( + TypeFlags::DATA + | TypeFlags::SIZED + | TypeFlags::INTERFACE + | TypeFlags::HOST_SHARED, + count * (width as u32), + ) + } + Ti::Matrix { + columns: _, + rows, + width, + } => { if !Self::check_width(crate::ScalarKind::Float, width) { return Err(TypeError::InvalidWidth(crate::ScalarKind::Float, width)); } - TypeInfo::from_flags( + let count = if rows >= crate::VectorSize::Tri { 4 } else { 2 }; + TypeInfo::new( TypeFlags::DATA | TypeFlags::SIZED | TypeFlags::INTERFACE | TypeFlags::HOST_SHARED, + count * (width as u32), ) } Ti::Pointer { base, class: _ } => { if base >= handle { return Err(TypeError::UnresolvedBase(base)); } - TypeInfo::from_flags(TypeFlags::DATA | TypeFlags::SIZED) + TypeInfo::new(TypeFlags::DATA | TypeFlags::SIZED, 0) } Ti::ValuePointer { size: _, @@ -157,7 +220,7 @@ impl super::Validator { if !Self::check_width(kind, width) { return Err(TypeError::InvalidWidth(kind, width)); } - TypeInfo::from_flags(TypeFlags::SIZED) + TypeInfo::new(TypeFlags::SIZED, 0) } Ti::Array { base, size, stride } => { if base >= handle { @@ -171,23 +234,50 @@ impl super::Validator { return Err(TypeError::NestedBlock); } - let base_layout = &layouter[base]; - if let Some(stride) = stride { - if stride.get() % base_layout.alignment.get() != 0 { - return Err(TypeError::UnalignedArrayStride { - stride: stride.get(), - base_alignment: base_layout.alignment.get(), - }); - } - if stride.get() < base_layout.size { - return Err(TypeError::InsufficientArrayStride { - stride: stride.get(), - base_size: base_layout.size, - }); - } + let base_size = types[base].inner.span(constants); + if stride < base_size { + return Err(TypeError::InsufficientArrayStride { stride, base_size }); } - let (sized_flag, uniform_layout) = match size { + let uniform_layout = match base_info.uniform_layout { + Ok(base_alignment) => { + // combine the alignment requirements + let align = ((base_alignment.unwrap().get() - 1) + | UNIFORM_LAYOUT_ALIGNMENT_MASK) + + 1; + if stride % align != 0 { + Err(( + handle, + Disalignment::ArrayStride { + stride, + alignment: align, + }, + )) + } else { + Ok(crate::Alignment::new(align)) + } + } + Err(e) => Err(e), + }; + let storage_layout = match base_info.storage_layout { + Ok(base_alignment) => { + let align = base_alignment.unwrap().get(); + if stride % align != 0 { + Err(( + handle, + Disalignment::ArrayStride { + stride, + alignment: align, + }, + )) + } else { + Ok(base_alignment) + } + } + Err(e) => Err(e), + }; + + let sized_flag = match size { crate::ArraySize::Constant(const_handle) => { match constants.try_get(const_handle) { Some(&crate::Constant { @@ -216,43 +306,32 @@ impl super::Validator { } } - let effective_stride = match stride { - Some(stride) => stride.get(), - None => base_layout.size, - }; - let uniform_layout = - if effective_stride & UNIFORM_LAYOUT_ALIGNMENT_MASK == 0 { - base_info.uniform_layout.clone() - } else { - Err(( - handle, - Disalignment::ArrayStride { - stride: effective_stride, - alignment: UNIFORM_LAYOUT_ALIGNMENT_MASK + 1, - }, - )) - }; - (TypeFlags::SIZED, uniform_layout) + TypeFlags::SIZED } //Note: this will be detected at the struct level - crate::ArraySize::Dynamic => (TypeFlags::empty(), Ok(())), + crate::ArraySize::Dynamic => TypeFlags::empty(), }; let base_mask = TypeFlags::HOST_SHARED | TypeFlags::INTERFACE; TypeInfo { flags: TypeFlags::DATA | (base_info.flags & base_mask) | sized_flag, uniform_layout, - storage_layout: base_info.storage_layout.clone(), + storage_layout, } } - Ti::Struct { block, ref members } => { - let mut flags = TypeFlags::DATA - | TypeFlags::SIZED - | TypeFlags::HOST_SHARED - | TypeFlags::INTERFACE; - let mut uniform_layout = Ok(()); - let mut storage_layout = Ok(()); - let mut offset = 0; + Ti::Struct { + level, + ref members, + span, + } => { + let mut ti = TypeInfo::new( + TypeFlags::DATA + | TypeFlags::SIZED + | TypeFlags::HOST_SHARED + | TypeFlags::INTERFACE, + 1, + ); + let mut min_offset = 0; for (i, member) in members.iter().enumerate() { if member.ty >= handle { return Err(TypeError::UnresolvedBase(member.ty)); @@ -261,36 +340,55 @@ impl super::Validator { if !base_info.flags.contains(TypeFlags::DATA) { return Err(TypeError::InvalidData(member.ty)); } - if block && !base_info.flags.contains(TypeFlags::INTERFACE) { + if level == crate::StructLevel::Root + && !base_info.flags.contains(TypeFlags::INTERFACE) + { return Err(TypeError::InvalidBlockType(member.ty)); } if base_info.flags.contains(TypeFlags::BLOCK) { return Err(TypeError::NestedBlock); } - flags &= base_info.flags; + ti.flags &= base_info.flags; - let base_layout = &layouter[member.ty]; - let (range, _alignment) = layouter.member_placement(offset, member); - if range.end - range.start < base_layout.size { - return Err(TypeError::InsufficientMemberSize { + if member.offset < min_offset { + //HACK: this could be nicer. We want to allow some structures + // to not bother with offsets/alignments if they are never + // used for host sharing. + if member.offset == 0 { + ti.flags.set(TypeFlags::HOST_SHARED, false); + } else { + return Err(TypeError::MemberOverlap { + index: i as u32, + offset: member.offset, + }); + } + } + let base_size = types[member.ty].inner.span(constants); + min_offset = member.offset + base_size; + if min_offset > span { + return Err(TypeError::MemberOutOfBounds { index: i as u32, - size: range.end - range.start, - base_size: base_layout.size, + offset: member.offset, + size: base_size, }); } - if range.start % base_layout.alignment.get() != 0 { - let result = Err(( - handle, - Disalignment::Member { - index: i as u32, - offset: range.start, - alignment: base_layout.alignment.get(), - }, - )); - uniform_layout = uniform_layout.or_else(|_| result.clone()); - storage_layout = storage_layout.or(result); - } - offset = range.end; + + check_member_layout( + &mut ti.uniform_layout, + member, + i as u32, + base_info.uniform_layout, + level, + handle, + ); + check_member_layout( + &mut ti.storage_layout, + member, + i as u32, + base_info.storage_layout, + level, + handle, + ); // only the last field can be unsized if !base_info.flags.contains(TypeFlags::SIZED) { @@ -298,40 +396,33 @@ impl super::Validator { let name = member.name.clone().unwrap_or_default(); return Err(TypeError::InvalidDynamicArray(name, member.ty)); } - if uniform_layout.is_ok() { - uniform_layout = + if ti.uniform_layout.is_ok() { + ti.uniform_layout = Err((handle, Disalignment::UnsizedMember { index: i as u32 })); } } - - uniform_layout = uniform_layout.or_else(|_| base_info.uniform_layout.clone()); - storage_layout = storage_layout.or_else(|_| base_info.storage_layout.clone()); } - if block { - flags |= TypeFlags::BLOCK; + if let crate::StructLevel::Root = level { + ti.flags |= TypeFlags::BLOCK; } // disabled temporarily, see https://github.com/gpuweb/gpuweb/issues/1558 const CHECK_STRUCT_SIZE: bool = false; if CHECK_STRUCT_SIZE - && uniform_layout.is_ok() - && offset & UNIFORM_LAYOUT_ALIGNMENT_MASK != 0 + && ti.uniform_layout.is_ok() + && span & UNIFORM_LAYOUT_ALIGNMENT_MASK != 0 { - uniform_layout = Err(( + ti.uniform_layout = Err(( handle, - Disalignment::StructSize { - size: offset, + Disalignment::StructSpan { + span, alignment: UNIFORM_LAYOUT_ALIGNMENT_MASK + 1, }, )); } - TypeInfo { - flags, - uniform_layout, - storage_layout, - } + ti } - Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::from_flags(TypeFlags::empty()), + Ti::Image { .. } | Ti::Sampler { .. } => TypeInfo::new(TypeFlags::empty(), 0), }) } } diff --git a/third_party/rust/naga/tests/errors.rs b/third_party/rust/naga/tests/errors.rs index 2f159c74425d..e9077220d38b 100644 --- a/third_party/rust/naga/tests/errors.rs +++ b/third_party/rust/naga/tests/errors.rs @@ -1,99 +1,99 @@ #[cfg(feature = "wgsl-in")] -macro_rules! err { - ($value:expr, @$snapshot:literal) => { - ::insta::assert_snapshot!( - naga::front::wgsl::parse_str($value) - .expect_err("expected parser error") - .emit_to_string(), - @$snapshot - ); - }; +fn check(input: &str, snapshot: &str) { + let output = naga::front::wgsl::parse_str(input) + .expect_err("expected parser error") + .emit_to_string(); + if output != snapshot { + for diff in diff::lines(&output, snapshot) { + match diff { + diff::Result::Left(l) => println!("-{}", l), + diff::Result::Both(l, _) => println!(" {}", l), + diff::Result::Right(r) => println!("+{}", r), + } + } + panic!("Error snapshot failed"); + } } #[cfg(feature = "wgsl-in")] #[test] fn function_without_identifier() { - err!( + check( "fn () {}", - @r###" - error: expected identifier, found '(' - ┌─ wgsl:1:4 - │ - 1 │ fn () {} - │ ^ expected identifier + r###"error: expected identifier, found '(' + ┌─ wgsl:1:4 + │ +1 │ fn () {} + │ ^ expected identifier - "### +"###, ); } #[cfg(feature = "wgsl-in")] #[test] fn invalid_integer() { - err!( + check( "fn foo([location(1.)] x: i32) {}", - @r###" - error: expected identifier, found '[' - ┌─ wgsl:1:8 - │ - 1 │ fn foo([location(1.)] x: i32) {} - │ ^ expected identifier + r###"error: expected identifier, found '[' + ┌─ wgsl:1:8 + │ +1 │ fn foo([location(1.)] x: i32) {} + │ ^ expected identifier - "### +"###, ); } #[cfg(feature = "wgsl-in")] #[test] fn invalid_float() { - err!( - "const scale: f32 = 1.1.;", - @r###" - error: expected floating-point literal, found `1.1.` - ┌─ wgsl:1:20 - │ - 1 │ const scale: f32 = 1.1.; - │ ^^^^ expected floating-point literal + check( + "let scale: f32 = 1.1.;", + r###"error: expected floating-point literal, found `1.1.` + ┌─ wgsl:1:18 + │ +1 │ let scale: f32 = 1.1.; + │ ^^^^ expected floating-point literal - "### +"###, ); } #[cfg(feature = "wgsl-in")] #[test] fn invalid_scalar_width() { - err!( - "const scale: f32 = 1.1f1000;", - @r###" - error: invalid width of `1000` for literal - ┌─ wgsl:1:20 - │ - 1 │ const scale: f32 = 1.1f1000; - │ ^^^^^^^^ invalid width - │ - = note: valid width is 32 + check( + "let scale: f32 = 1.1f1000;", + r###"error: invalid width of `1000` for literal + ┌─ wgsl:1:18 + │ +1 │ let scale: f32 = 1.1f1000; + │ ^^^^^^^^ invalid width + │ + = note: valid width is 32 - "### +"###, ); } #[cfg(feature = "wgsl-in")] #[test] fn invalid_accessor() { - err!( + check( r###" - [[stage(vertex)]] - fn vs_main() { - var color: vec3 = vec3(1.0, 2.0, 3.0); - var i: f32 = color.a; - } - "###, - @r###" - error: invalid field accessor `a` - ┌─ wgsl:5:32 - │ - 5 │ var i: f32 = color.a; - │ ^ invalid accessor +[[stage(vertex)]] +fn vs_main() { + var color: vec3 = vec3(1.0, 2.0, 3.0); + var i: f32 = color.a; +} +"###, + r###"error: invalid field accessor `a` + ┌─ wgsl:5:24 + │ +5 │ var i: f32 = color.a; + │ ^ invalid accessor - "### +"###, ); } diff --git a/third_party/rust/naga/tests/in/access.param.ron b/third_party/rust/naga/tests/in/access.param.ron new file mode 100644 index 000000000000..52f49f360fb7 --- /dev/null +++ b/third_party/rust/naga/tests/in/access.param.ron @@ -0,0 +1,7 @@ +( + spv_version: (1, 1), + spv_capabilities: [ Shader, Image1D, Sampled1D ], + spv_debug: true, + spv_adjust_coordinate_space: false, + msl_custom: false, +) diff --git a/third_party/rust/naga/tests/in/access.wgsl b/third_party/rust/naga/tests/in/access.wgsl new file mode 100644 index 000000000000..c5f6c27e7443 --- /dev/null +++ b/third_party/rust/naga/tests/in/access.wgsl @@ -0,0 +1,8 @@ +// This snapshot tests accessing various containers, dereferencing pointers. + +[[stage(vertex)]] +fn foo([[builtin(vertex_index)]] vi: u32) -> [[builtin(position)]] vec4 { + let array = array(1, 2, 3, 4, 5); + let value = array[vi]; + return vec4(vec4(value)); +} diff --git a/third_party/rust/naga/tests/in/boids.param.ron b/third_party/rust/naga/tests/in/boids.param.ron index 16eca7eba47f..551feceded55 100644 --- a/third_party/rust/naga/tests/in/boids.param.ron +++ b/third_party/rust/naga/tests/in/boids.param.ron @@ -4,9 +4,18 @@ spv_capabilities: [ Shader ], spv_debug: true, spv_adjust_coordinate_space: false, - mtl_bindings: { - (stage: Compute, group: 0, binding: 0): (buffer: Some(0), mutable: false), - (stage: Compute, group: 0, binding: 1): (buffer: Some(1), mutable: true), - (stage: Compute, group: 0, binding: 2): (buffer: Some(2), mutable: true), - } + msl_custom: true, + msl: ( + lang_version: (2, 0), + binding_map: { + (stage: Compute, group: 0, binding: 0): (buffer: Some(0), mutable: false), + (stage: Compute, group: 0, binding: 1): (buffer: Some(1), mutable: true), + (stage: Compute, group: 0, binding: 2): (buffer: Some(2), mutable: true), + }, + push_constants_map: ( + ), + inline_samplers: [], + spirv_cross_compatibility: false, + fake_missing_bindings: false, + ), ) diff --git a/third_party/rust/naga/tests/in/boids.wgsl b/third_party/rust/naga/tests/in/boids.wgsl index 935d8ee08c2f..dc5bd7ea39a3 100644 --- a/third_party/rust/naga/tests/in/boids.wgsl +++ b/third_party/rust/naga/tests/in/boids.wgsl @@ -1,4 +1,4 @@ -const NUM_PARTICLES: u32 = 1500u; +let NUM_PARTICLES: u32 = 1500u; struct Particle { pos : vec2; @@ -28,7 +28,7 @@ struct Particles { // https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp [[stage(compute), workgroup_size(64)]] fn main([[builtin(global_invocation_id)]] global_invocation_id : vec3) { - const index : u32 = global_invocation_id.x; + let index : u32 = global_invocation_id.x; if (index >= NUM_PARTICLES) { return; } @@ -73,10 +73,10 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id : vec3) { } } if (cMassCount > 0) { - cMass = cMass * (1.0 / f32(cMassCount)) - vPos; + cMass = cMass / f32(cMassCount) - vPos; } if (cVelCount > 0) { - cVel = cVel * (1.0 / f32(cVelCount)); + cVel = cVel / f32(cVelCount); } vVel = vVel + (cMass * params.rule1Scale) + diff --git a/third_party/rust/naga/tests/in/collatz.param.ron b/third_party/rust/naga/tests/in/collatz.param.ron index e27b19568167..984ca763e08c 100644 --- a/third_party/rust/naga/tests/in/collatz.param.ron +++ b/third_party/rust/naga/tests/in/collatz.param.ron @@ -4,7 +4,5 @@ spv_capabilities: [ Shader ], spv_debug: true, spv_adjust_coordinate_space: false, - mtl_bindings: { - (stage: Compute, group: 0, binding: 0): (buffer: Some(0), mutable: true), - } + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/empty.param.ron b/third_party/rust/naga/tests/in/empty.param.ron index cd1d89ab8928..6de22960da95 100644 --- a/third_party/rust/naga/tests/in/empty.param.ron +++ b/third_party/rust/naga/tests/in/empty.param.ron @@ -3,6 +3,5 @@ spv_capabilities: [ Shader ], spv_debug: false, spv_adjust_coordinate_space: false, - mtl_bindings: { - } + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/image-copy.param.ron b/third_party/rust/naga/tests/in/image-copy.param.ron index 297ffec8d807..52f49f360fb7 100644 --- a/third_party/rust/naga/tests/in/image-copy.param.ron +++ b/third_party/rust/naga/tests/in/image-copy.param.ron @@ -3,8 +3,5 @@ spv_capabilities: [ Shader, Image1D, Sampled1D ], spv_debug: true, spv_adjust_coordinate_space: false, - mtl_bindings: { - (stage: Compute, group: 0, binding: 1): (texture: Some(0), mutable: false), - (stage: Compute, group: 0, binding: 2): (texture: Some(1), mutable: true), - } + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/image-copy.wgsl b/third_party/rust/naga/tests/in/image-copy.wgsl index cb09083b9af2..157d08146141 100644 --- a/third_party/rust/naga/tests/in/image-copy.wgsl +++ b/third_party/rust/naga/tests/in/image-copy.wgsl @@ -9,8 +9,8 @@ fn main( //TODO: https://github.com/gpuweb/gpuweb/issues/1590 //[[builtin(workgroup_size)]] wg_size: vec3 ) { - const dim = textureDimensions(image_src); - const itc = dim * vec2(local_id.xy) % vec2(10, 20); - const value = textureLoad(image_src, itc); + let dim = textureDimensions(image_src); + let itc = dim * vec2(local_id.xy) % vec2(10, 20); + let value = textureLoad(image_src, itc); textureStore(image_dst, itc.x, value); } diff --git a/third_party/rust/naga/tests/in/interpolate.param.ron b/third_party/rust/naga/tests/in/interpolate.param.ron new file mode 100644 index 000000000000..804665025c4f --- /dev/null +++ b/third_party/rust/naga/tests/in/interpolate.param.ron @@ -0,0 +1,8 @@ +( + spv_version: (1, 0), + spv_capabilities: [ Shader, SampleRateShading ], + spv_debug: true, + spv_adjust_coordinate_space: true, + msl_custom: false, + glsl_desktop_version: Some(400) +) diff --git a/third_party/rust/naga/tests/in/interpolate.wgsl b/third_party/rust/naga/tests/in/interpolate.wgsl new file mode 100644 index 000000000000..51eb4fde7466 --- /dev/null +++ b/third_party/rust/naga/tests/in/interpolate.wgsl @@ -0,0 +1,29 @@ +struct FragmentInput { + [[builtin(position)]] position: vec4; + [[location(0), interpolate(flat)]] flat : u32; + [[location(1), interpolate(linear)]] linear : f32; + [[location(2), interpolate(linear,centroid)]] linear_centroid : vec2; + [[location(3), interpolate(linear,sample)]] linear_sample : vec3; + [[location(4), interpolate(perspective)]] perspective : vec4; + [[location(5), interpolate(perspective,centroid)]] perspective_centroid : f32; + [[location(6), interpolate(perspective,sample)]] perspective_sample : f32; +}; + +[[stage(vertex)]] +fn main() -> FragmentInput { + var out: FragmentInput; + + out.position = vec4(2.0, 4.0, 5.0, 6.0); + out.flat = 8u32; + out.linear = 27.0; + out.linear_centroid = vec2(64.0, 125.0); + out.linear_sample = vec3(216.0, 343.0, 512.0); + out.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; + + return out; +} + +[[stage(fragment)]] +fn main(val : FragmentInput) { } diff --git a/third_party/rust/naga/tests/in/operators.param.ron b/third_party/rust/naga/tests/in/operators.param.ron new file mode 100644 index 000000000000..bd5e5acc2941 --- /dev/null +++ b/third_party/rust/naga/tests/in/operators.param.ron @@ -0,0 +1,7 @@ +( + spv_version: (1, 0), + spv_capabilities: [ Shader ], + spv_debug: false, + spv_adjust_coordinate_space: false, + msl_custom: false, +) diff --git a/third_party/rust/naga/tests/in/operators.wgsl b/third_party/rust/naga/tests/in/operators.wgsl new file mode 100644 index 000000000000..7808e6e7c57f --- /dev/null +++ b/third_party/rust/naga/tests/in/operators.wgsl @@ -0,0 +1,6 @@ +[[stage(vertex)]] +fn splat() -> [[builtin(position)]] vec4 { + let a = (1.0 + vec2(2.0) - 3.0) / 4.0; + let b = vec4(5) % 2; + return a.xyxy + vec4(b); +} diff --git a/third_party/rust/naga/tests/in/quad-glsl.param.ron b/third_party/rust/naga/tests/in/quad-glsl.param.ron index 3fe357ca6cdf..efded54c2816 100644 --- a/third_party/rust/naga/tests/in/quad-glsl.param.ron +++ b/third_party/rust/naga/tests/in/quad-glsl.param.ron @@ -3,5 +3,5 @@ spv_capabilities: [ Shader ], spv_debug: true, spv_adjust_coordinate_space: true, - mtl_bindings: {} + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/quad.param.ron b/third_party/rust/naga/tests/in/quad.param.ron index fcddac8b50c1..efded54c2816 100644 --- a/third_party/rust/naga/tests/in/quad.param.ron +++ b/third_party/rust/naga/tests/in/quad.param.ron @@ -3,8 +3,5 @@ spv_capabilities: [ Shader ], spv_debug: true, spv_adjust_coordinate_space: true, - mtl_bindings: { - (stage: Fragment, group: 0, binding: 0): (texture: Some(0)), - (stage: Fragment, group: 0, binding: 1): (sampler: Some(0)), - } + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/quad.wgsl b/third_party/rust/naga/tests/in/quad.wgsl index 6283687ef790..0cd0187a8f81 100644 --- a/third_party/rust/naga/tests/in/quad.wgsl +++ b/third_party/rust/naga/tests/in/quad.wgsl @@ -1,5 +1,5 @@ // vertex -const c_scale: f32 = 1.2; +let c_scale: f32 = 1.2; struct VertexOutput { [[location(0)]] uv : vec2; @@ -8,10 +8,7 @@ struct VertexOutput { [[stage(vertex)]] fn main([[location(0)]] pos : vec2, [[location(1)]] uv : vec2) -> VertexOutput { - var out: VertexOutput; - out.uv = uv; - out.position = vec4(c_scale * pos, 0.0, 1.0); - return out; + return VertexOutput(uv, vec4(c_scale * pos, 0.0, 1.0)); } // fragment @@ -20,12 +17,12 @@ fn main([[location(0)]] pos : vec2, [[location(1)]] uv : vec2) -> Vert [[stage(fragment)]] fn main([[location(0)]] uv : vec2) -> [[location(0)]] vec4 { - const color = textureSample(u_texture, u_sampler, uv); + let color = textureSample(u_texture, u_sampler, uv); if (color.a == 0.0) { discard; } // forcing the expression here to be emitted in order to check the // uniformity of the control flow a bit more strongly. - const premultiplied = color.a * color; + let premultiplied = color.a * color; return premultiplied; } diff --git a/third_party/rust/naga/tests/in/shadow.param.ron b/third_party/rust/naga/tests/in/shadow.param.ron index 643ac437be2a..dfa9978c3dcf 100644 --- a/third_party/rust/naga/tests/in/shadow.param.ron +++ b/third_party/rust/naga/tests/in/shadow.param.ron @@ -1,13 +1,8 @@ ( - spv_flow_dump_prefix: "", - spv_version: (1, 2), - spv_capabilities: [ Shader ], - spv_debug: true, - spv_adjust_coordinate_space: true, - mtl_bindings: { - (stage: Fragment, group: 0, binding: 0): (buffer: Some(0), mutable: false), - (stage: Fragment, group: 0, binding: 1): (buffer: Some(1), mutable: false), - (stage: Fragment, group: 0, binding: 2): (texture: Some(0), mutable: false), - (stage: Fragment, group: 0, binding: 3): (sampler: Some(0), mutable: false), - } + spv_flow_dump_prefix: "", + spv_version: (1, 2), + spv_capabilities: [ Shader ], + spv_debug: true, + spv_adjust_coordinate_space: true, + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/in/shadow.wgsl b/third_party/rust/naga/tests/in/shadow.wgsl index f40802cb43ed..9cd5253bccab 100644 --- a/third_party/rust/naga/tests/in/shadow.wgsl +++ b/third_party/rust/naga/tests/in/shadow.wgsl @@ -28,21 +28,20 @@ fn fetch_shadow(light_id: u32, homogeneous_coords: vec4) -> f32 { if (homogeneous_coords.w <= 0.0) { return 1.0; } - const flip_correction = vec2(0.5, -0.5); - const proj_correction = 1.0 / homogeneous_coords.w; - const light_local = homogeneous_coords.xy * flip_correction * proj_correction + vec2(0.5, 0.5); - return textureSampleCompare(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z * proj_correction); + let flip_correction = vec2(0.5, -0.5); + let light_local = homogeneous_coords.xy * flip_correction / homogeneous_coords.w + vec2(0.5, 0.5); + return textureSampleCompare(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z / homogeneous_coords.w); } -const c_ambient: vec3 = vec3(0.05, 0.05, 0.05); -const c_max_lights: u32 = 10u; +let c_ambient: vec3 = vec3(0.05, 0.05, 0.05); +let c_max_lights: u32 = 10u; [[stage(fragment)]] fn fs_main( [[location(0)]] raw_normal: vec3, [[location(1)]] position: vec4 ) -> [[location(0)]] vec4 { - const normal: vec3 = normalize(raw_normal); + let normal: vec3 = normalize(raw_normal); // accumulate color var color: vec3 = c_ambient; var i: u32 = 0u; @@ -50,10 +49,10 @@ fn fs_main( if (i >= min(u_globals.num_lights.x, c_max_lights)) { break; } - const light = s_lights.data[i]; - const shadow = fetch_shadow(i, light.proj * position); - const light_dir = normalize(light.pos.xyz - position.xyz); - const diffuse = max(0.0, dot(normal, light_dir)); + let light = s_lights.data[i]; + let shadow = fetch_shadow(i, light.proj * position); + let light_dir = normalize(light.pos.xyz - position.xyz); + let diffuse = max(0.0, dot(normal, light_dir)); color = color + shadow * diffuse * light.color.xyz; continuing { i = i + 1u; diff --git a/third_party/rust/naga/tests/in/skybox.param.ron b/third_party/rust/naga/tests/in/skybox.param.ron index 23735691209a..aae6af7cae13 100644 --- a/third_party/rust/naga/tests/in/skybox.param.ron +++ b/third_party/rust/naga/tests/in/skybox.param.ron @@ -4,9 +4,30 @@ spv_capabilities: [ Shader ], spv_debug: false, spv_adjust_coordinate_space: false, - mtl_bindings: { - (stage: Vertex, group: 0, binding: 0): (buffer: Some(0)), - (stage: Fragment, group: 0, binding: 1): (texture: Some(0)), - (stage: Fragment, group: 0, binding: 2): (sampler: Some(1)), - } + msl_custom: true, + msl: ( + lang_version: (2, 1), + binding_map: { + (stage: Vertex, group: 0, binding: 0): (buffer: Some(0)), + (stage: Fragment, group: 0, binding: 1): (texture: Some(0)), + (stage: Fragment, group: 0, binding: 2): (sampler: Some(Inline(0))), + }, + push_constants_map: ( + ), + inline_samplers: [ + ( + coord: Normalized, + address: (ClampToEdge, ClampToEdge, ClampToEdge), + mag_filter: Linear, + min_filter: Linear, + mip_filter: None, + border_color: TransparentBlack, + compare_func: Never, + lod_clamp: Some((start: 0.5, end: 10.0)), + max_anisotropy: Some(8), + ), + ], + spirv_cross_compatibility: false, + fake_missing_bindings: false, + ) ) diff --git a/third_party/rust/naga/tests/in/skybox.wgsl b/third_party/rust/naga/tests/in/skybox.wgsl index 32ad80ca11e2..d5cb051262c4 100644 --- a/third_party/rust/naga/tests/in/skybox.wgsl +++ b/third_party/rust/naga/tests/in/skybox.wgsl @@ -16,19 +16,16 @@ fn vs_main([[builtin(vertex_index)]] vertex_index: u32) -> VertexOutput { // hacky way to draw a large triangle var tmp1: i32 = i32(vertex_index) / 2; var tmp2: i32 = i32(vertex_index) & 1; - const pos = vec4( + let pos = vec4( f32(tmp1) * 4.0 - 1.0, f32(tmp2) * 4.0 - 1.0, 0.0, 1.0 ); - const inv_model_view = transpose(mat3x3(r_data.view.x.xyz, r_data.view.y.xyz, r_data.view.z.xyz)); - const unprojected = r_data.proj_inv * pos; - var out: VertexOutput; - out.uv = inv_model_view * unprojected.xyz; - out.position = pos; - return out; + let inv_model_view = transpose(mat3x3(r_data.view.x.xyz, r_data.view.y.xyz, r_data.view.z.xyz)); + let unprojected = r_data.proj_inv * pos; + return VertexOutput(pos, inv_model_view * unprojected.xyz); } [[group(0), binding(1)]] diff --git a/third_party/rust/naga/tests/in/texture-array.param.ron b/third_party/rust/naga/tests/in/texture-array.param.ron index 6e3432a8a3c0..b46594e31957 100644 --- a/third_party/rust/naga/tests/in/texture-array.param.ron +++ b/third_party/rust/naga/tests/in/texture-array.param.ron @@ -4,9 +4,5 @@ spv_capabilities: [ Shader ], spv_debug: true, spv_adjust_coordinate_space: false, - mtl_bindings: { - (stage: Fragment, group: 0, binding: 0): (texture: Some(0)), - (stage: Fragment, group: 0, binding: 1): (texture: Some(1)), - (stage: Fragment, group: 0, binding: 2): (sampler: Some(0)), - } + msl_custom: false, ) diff --git a/third_party/rust/naga/tests/out/access.msl b/third_party/rust/naga/tests/out/access.msl new file mode 100644 index 000000000000..8c9d1c2260f0 --- /dev/null +++ b/third_party/rust/naga/tests/out/access.msl @@ -0,0 +1,15 @@ +#include +#include + +typedef int type3[5]; + +struct fooInput { +}; +struct fooOutput { + metal::float4 member [[position]]; +}; +vertex fooOutput foo( + metal::uint vi [[vertex_id]] +) { + return fooOutput { static_cast(type3 {1, 2, 3, 4, 5}[vi]) }; +} diff --git a/third_party/rust/naga/tests/out/access.spvasm b/third_party/rust/naga/tests/out/access.spvasm new file mode 100644 index 000000000000..985b9a840860 --- /dev/null +++ b/third_party/rust/naga/tests/out/access.spvasm @@ -0,0 +1,50 @@ +; SPIR-V +; Version: 1.1 +; Generator: rspirv +; Bound: 31 +OpCapability Image1D +OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %19 "foo" %14 %17 +OpSource GLSL 450 +OpName %14 "vi" +OpName %19 "foo" +OpDecorate %12 ArrayStride 4 +OpDecorate %14 BuiltIn VertexIndex +OpDecorate %17 BuiltIn Position +%2 = OpTypeVoid +%4 = OpTypeInt 32 1 +%3 = OpConstant %4 5 +%5 = OpConstant %4 1 +%6 = OpConstant %4 2 +%7 = OpConstant %4 3 +%8 = OpConstant %4 4 +%9 = OpTypeInt 32 0 +%11 = OpTypeFloat 32 +%10 = OpTypeVector %11 4 +%12 = OpTypeArray %4 %3 +%15 = OpTypePointer Input %9 +%14 = OpVariable %15 Input +%18 = OpTypePointer Output %10 +%17 = OpVariable %18 Output +%20 = OpTypeFunction %2 +%23 = OpTypePointer Function %12 +%26 = OpTypePointer Function %4 +%28 = OpTypeVector %4 4 +%19 = OpFunction %2 None %20 +%13 = OpLabel +%24 = OpVariable %23 Function +%16 = OpLoad %9 %14 +OpBranch %21 +%21 = OpLabel +%22 = OpCompositeConstruct %12 %5 %6 %7 %8 %3 +OpStore %24 %22 +%25 = OpAccessChain %26 %24 %16 +%27 = OpLoad %4 %25 +%29 = OpCompositeConstruct %28 %27 %27 %27 %27 +%30 = OpConvertSToF %10 %29 +OpStore %17 %30 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/boids.msl b/third_party/rust/naga/tests/out/boids.msl new file mode 100644 index 000000000000..f8aa787805e4 --- /dev/null +++ b/third_party/rust/naga/tests/out/boids.msl @@ -0,0 +1,99 @@ +#include +#include + +constexpr constant unsigned NUM_PARTICLES = 1500u; +struct Particle { + metal::float2 pos; + metal::float2 vel; +}; +struct SimParams { + float deltaT; + float rule1Distance; + float rule2Distance; + float rule3Distance; + float rule1Scale; + float rule2Scale; + float rule3Scale; +}; +typedef Particle type3[1]; +struct Particles { + type3 particles; +}; + +struct main1Input { +}; +kernel void main1( + metal::uint3 global_invocation_id [[thread_position_in_grid]] +, constant SimParams& params [[buffer(0)]] +, constant Particles& particlesSrc [[buffer(1)]] +, device Particles& particlesDst [[buffer(2)]] +) { + metal::float2 vPos; + metal::float2 vVel; + metal::float2 cMass; + metal::float2 cVel; + metal::float2 colVel; + int cMassCount = 0; + int cVelCount = 0; + metal::float2 pos1; + metal::float2 vel1; + metal::uint i = 0u; + if (global_invocation_id.x >= NUM_PARTICLES) { + return; + } + vPos = particlesSrc.particles[global_invocation_id.x].pos; + vVel = particlesSrc.particles[global_invocation_id.x].vel; + cMass = metal::float2(0.0, 0.0); + cVel = metal::float2(0.0, 0.0); + colVel = metal::float2(0.0, 0.0); + bool loop_init = true; + while(true) { + if (!loop_init) { + i = i + 1u; + } + loop_init = false; + if (i >= NUM_PARTICLES) { + break; + } + if (i == global_invocation_id.x) { + continue; + } + pos1 = particlesSrc.particles[i].pos; + vel1 = particlesSrc.particles[i].vel; + if (metal::distance(pos1, vPos) < params.rule1Distance) { + cMass = cMass + pos1; + cMassCount = cMassCount + 1; + } + if (metal::distance(pos1, vPos) < params.rule2Distance) { + colVel = colVel - (pos1 - vPos); + } + if (metal::distance(pos1, vPos) < params.rule3Distance) { + cVel = cVel + vel1; + cVelCount = cVelCount + 1; + } + } + if (cMassCount > 0) { + cMass = (cMass / static_cast(cMassCount)) - vPos; + } + if (cVelCount > 0) { + cVel = cVel / static_cast(cVelCount); + } + vVel = ((vVel + (cMass * params.rule1Scale)) + (colVel * params.rule2Scale)) + (cVel * params.rule3Scale); + vVel = metal::normalize(vVel) * metal::clamp(metal::length(vVel), 0.0, 0.1); + vPos = vPos + (vVel * params.deltaT); + if (vPos.x < -1.0) { + vPos.x = 1.0; + } + if (vPos.x > 1.0) { + vPos.x = -1.0; + } + if (vPos.y < -1.0) { + vPos.y = 1.0; + } + if (vPos.y > 1.0) { + vPos.y = -1.0; + } + particlesDst.particles[global_invocation_id.x].pos = vPos; + particlesDst.particles[global_invocation_id.x].vel = vVel; + return; +} diff --git a/third_party/rust/naga/tests/out/boids.msl.snap b/third_party/rust/naga/tests/out/boids.msl.snap deleted file mode 100644 index e690e2ccdf28..000000000000 --- a/third_party/rust/naga/tests/out/boids.msl.snap +++ /dev/null @@ -1,116 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant unsigned NUM_PARTICLES = 1500u; -constexpr constant float const_0f = 0.0; -constexpr constant int const_0i = 0; -constexpr constant unsigned const_0u = 0u; -constexpr constant int const_1i = 1; -constexpr constant unsigned const_1u = 1u; -constexpr constant float const_1f = 1.0; -constexpr constant float const_0_10f = 0.1; -constexpr constant float const_n1f = -1.0; -typedef metal::uint type; -typedef metal::float2 type1; -struct Particle { - type1 pos; - type1 vel; -}; -typedef float type2; -struct SimParams { - type2 deltaT; - type2 rule1Distance; - type2 rule2Distance; - type2 rule3Distance; - type2 rule1Scale; - type2 rule2Scale; - type2 rule3Scale; -}; -typedef Particle type3[1]; -struct Particles { - type3 particles; -}; -typedef metal::uint3 type4; -typedef int type5; -struct main1Input { -}; -kernel void main1( - type4 global_invocation_id [[thread_position_in_grid]] -, constant SimParams& params [[buffer(0)]] -, constant Particles& particlesSrc [[buffer(1)]] -, device Particles& particlesDst [[buffer(2)]] -) { - type1 vPos; - type1 vVel; - type1 cMass; - type1 cVel; - type1 colVel; - type5 cMassCount = const_0i; - type5 cVelCount = const_0i; - type1 pos1; - type1 vel1; - type i = const_0u; - if (global_invocation_id.x >= NUM_PARTICLES) { - return; - } - vPos = particlesSrc.particles[global_invocation_id.x].pos; - vVel = particlesSrc.particles[global_invocation_id.x].vel; - cMass = metal::float2(const_0f, const_0f); - cVel = metal::float2(const_0f, const_0f); - colVel = metal::float2(const_0f, const_0f); - bool loop_init = true; - while(true) { - if (!loop_init) { - i = i + const_1u; - } - loop_init = false; - if (i >= NUM_PARTICLES) { - break; - } - if (i == global_invocation_id.x) { - continue; - } - pos1 = particlesSrc.particles[i].pos; - vel1 = particlesSrc.particles[i].vel; - if (metal::distance(pos1, vPos) < params.rule1Distance) { - cMass = cMass + pos1; - cMassCount = cMassCount + const_1i; - } - if (metal::distance(pos1, vPos) < params.rule2Distance) { - colVel = colVel - (pos1 - vPos); - } - if (metal::distance(pos1, vPos) < params.rule3Distance) { - cVel = cVel + vel1; - cVelCount = cVelCount + const_1i; - } - } - if (cMassCount > const_0i) { - cMass = (cMass * (const_1f / static_cast(cMassCount))) - vPos; - } - if (cVelCount > const_0i) { - cVel = cVel * (const_1f / static_cast(cVelCount)); - } - vVel = ((vVel + (cMass * params.rule1Scale)) + (colVel * params.rule2Scale)) + (cVel * params.rule3Scale); - vVel = metal::normalize(vVel) * metal::clamp(metal::length(vVel), const_0f, const_0_10f); - vPos = vPos + (vVel * params.deltaT); - if (vPos.x < const_n1f) { - vPos.x = const_1f; - } - if (vPos.x > const_1f) { - vPos.x = const_n1f; - } - if (vPos.y < const_n1f) { - vPos.y = const_1f; - } - if (vPos.y > const_1f) { - vPos.y = const_n1f; - } - particlesDst.particles[global_invocation_id.x].pos = vPos; - particlesDst.particles[global_invocation_id.x].vel = vVel; - return; -} - diff --git a/third_party/rust/naga/tests/out/boids.spvasm.snap b/third_party/rust/naga/tests/out/boids.spvasm similarity index 93% rename from third_party/rust/naga/tests/out/boids.spvasm.snap rename to third_party/rust/naga/tests/out/boids.spvasm index ded452eaeefb..c9a05f398aaf 100644 --- a/third_party/rust/naga/tests/out/boids.spvasm.snap +++ b/third_party/rust/naga/tests/out/boids.spvasm @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: dis ---- ; SPIR-V ; Version: 1.0 ; Generator: rspirv @@ -42,7 +38,6 @@ OpName %36 "vel" OpName %37 "i" OpName %40 "global_invocation_id" OpName %43 "main" -OpName %43 "main" OpMemberDecorate %16 0 Offset 0 OpMemberDecorate %16 1 Offset 8 OpDecorate %17 Block @@ -74,9 +69,9 @@ OpDecorate %40 BuiltIn GlobalInvocationId %9 = OpConstant %4 0 %10 = OpConstant %8 1 %11 = OpConstant %4 1 -%12 = OpConstant %6 1.0 -%13 = OpConstant %6 0.1 -%14 = OpConstant %6 -1.0 +%12 = OpConstant %6 0.1 +%13 = OpConstant %6 -1.0 +%14 = OpConstant %6 1.0 %15 = OpTypeVector %6 2 %16 = OpTypeStruct %15 %15 %17 = OpTypeStruct %6 %6 %6 %6 %6 %6 %6 @@ -234,8 +229,8 @@ OpBranchConditional %124 %126 %125 %127 = OpLoad %15 %29 %128 = OpLoad %8 %32 %129 = OpConvertSToF %6 %128 -%130 = OpFDiv %6 %12 %129 -%131 = OpVectorTimesScalar %15 %127 %130 +%130 = OpCompositeConstruct %15 %129 %129 +%131 = OpFDiv %15 %127 %130 %132 = OpLoad %15 %26 %133 = OpFSub %15 %131 %132 OpStore %29 %133 @@ -249,8 +244,8 @@ OpBranchConditional %135 %137 %136 %138 = OpLoad %15 %30 %139 = OpLoad %8 %34 %140 = OpConvertSToF %6 %139 -%141 = OpFDiv %6 %12 %140 -%142 = OpVectorTimesScalar %15 %138 %141 +%141 = OpCompositeConstruct %15 %140 %140 +%142 = OpFDiv %15 %138 %141 OpStore %30 %142 OpBranch %136 %136 = OpLabel @@ -275,7 +270,7 @@ OpStore %28 %161 %163 = OpExtInst %15 %1 Normalize %162 %164 = OpLoad %15 %28 %165 = OpExtInst %6 %1 Length %164 -%166 = OpExtInst %6 %1 FClamp %165 %5 %13 +%166 = OpExtInst %6 %1 FClamp %165 %5 %12 %167 = OpVectorTimesScalar %15 %163 %166 OpStore %28 %167 %168 = OpLoad %15 %26 @@ -287,42 +282,42 @@ OpStore %28 %167 OpStore %26 %173 %174 = OpLoad %15 %26 %175 = OpCompositeExtract %6 %174 0 -%176 = OpFOrdLessThan %47 %175 %14 +%176 = OpFOrdLessThan %47 %175 %13 OpSelectionMerge %177 None OpBranchConditional %176 %178 %177 %178 = OpLabel %180 = OpAccessChain %179 %26 %7 -OpStore %180 %12 +OpStore %180 %14 OpBranch %177 %177 = OpLabel %181 = OpLoad %15 %26 %182 = OpCompositeExtract %6 %181 0 -%183 = OpFOrdGreaterThan %47 %182 %12 +%183 = OpFOrdGreaterThan %47 %182 %14 OpSelectionMerge %184 None OpBranchConditional %183 %185 %184 %185 = OpLabel %186 = OpAccessChain %179 %26 %7 -OpStore %186 %14 +OpStore %186 %13 OpBranch %184 %184 = OpLabel %187 = OpLoad %15 %26 %188 = OpCompositeExtract %6 %187 1 -%189 = OpFOrdLessThan %47 %188 %14 +%189 = OpFOrdLessThan %47 %188 %13 OpSelectionMerge %190 None OpBranchConditional %189 %191 %190 %191 = OpLabel %192 = OpAccessChain %179 %26 %10 -OpStore %192 %12 +OpStore %192 %14 OpBranch %190 %190 = OpLabel %193 = OpLoad %15 %26 %194 = OpCompositeExtract %6 %193 1 -%195 = OpFOrdGreaterThan %47 %194 %12 +%195 = OpFOrdGreaterThan %47 %194 %14 OpSelectionMerge %196 None OpBranchConditional %195 %197 %196 %197 = OpLabel %198 = OpAccessChain %179 %26 %10 -OpStore %198 %14 +OpStore %198 %13 OpBranch %196 %196 = OpLabel %199 = OpLoad %15 %26 @@ -332,4 +327,4 @@ OpStore %200 %199 %202 = OpAccessChain %53 %25 %7 %46 %10 OpStore %202 %201 OpReturn -OpFunctionEnd +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/collatz.info.ron.snap b/third_party/rust/naga/tests/out/collatz.info.ron similarity index 96% rename from third_party/rust/naga/tests/out/collatz.info.ron.snap rename to third_party/rust/naga/tests/out/collatz.info.ron index aff1363292ad..edf6a5a5a437 100644 --- a/third_party/rust/naga/tests/out/collatz.info.ron.snap +++ b/third_party/rust/naga/tests/out/collatz.info.ron @@ -1,12 +1,8 @@ ---- -source: tests/snapshots.rs -expression: output ---- ( functions: [ ( flags: ( - bits: 15, + bits: 31, ), available_stages: ( bits: 7, @@ -345,7 +341,7 @@ expression: output entry_points: [ ( flags: ( - bits: 15, + bits: 31, ), available_stages: ( bits: 7, @@ -498,24 +494,4 @@ expression: output ], ), ], - layouter: ( - layouts: [ - ( - size: 4, - alignment: 4, - ), - ( - size: 4, - alignment: 4, - ), - ( - size: 4, - alignment: 4, - ), - ( - size: 12, - alignment: 16, - ), - ], - ), -) +) \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/collatz.msl b/third_party/rust/naga/tests/out/collatz.msl new file mode 100644 index 000000000000..02a9761166f6 --- /dev/null +++ b/third_party/rust/naga/tests/out/collatz.msl @@ -0,0 +1,38 @@ +#include +#include + +typedef metal::uint type1[1]; +struct PrimeIndices { + type1 data; +}; + +metal::uint collatz_iterations( + metal::uint n_base +) { + metal::uint n; + metal::uint i = 0u; + n = n_base; + while(true) { + if (n <= 1u) { + break; + } + if ((n % 2u) == 0u) { + n = n / 2u; + } else { + n = (3u * n) + 1u; + } + i = i + 1u; + } + return i; +} + +struct main1Input { +}; +kernel void main1( + metal::uint3 global_id [[thread_position_in_grid]] +, device PrimeIndices& v_indices [[user(fake0), center_perspective]] +) { + metal::uint _e9 = collatz_iterations(v_indices.data[global_id.x]); + v_indices.data[global_id.x] = _e9; + return; +} diff --git a/third_party/rust/naga/tests/out/collatz.msl.snap b/third_party/rust/naga/tests/out/collatz.msl.snap deleted file mode 100644 index f921cb575c98..000000000000 --- a/third_party/rust/naga/tests/out/collatz.msl.snap +++ /dev/null @@ -1,48 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant unsigned const_0u = 0u; -constexpr constant unsigned const_1u = 1u; -constexpr constant unsigned const_2u = 2u; -constexpr constant unsigned const_3u = 3u; -typedef metal::uint type; -typedef type type1[1]; -struct PrimeIndices { - type1 data; -}; -typedef metal::uint3 type2; -type collatz_iterations( - type n_base -) { - type n; - type i = const_0u; - n = n_base; - while(true) { - if (n <= const_1u) { - break; - } - if ((n % const_2u) == const_0u) { - n = n / const_2u; - } else { - n = (const_3u * n) + const_1u; - } - i = i + const_1u; - } - return i; -} - -struct main1Input { -}; -kernel void main1( - type2 global_id [[thread_position_in_grid]] -, device PrimeIndices& v_indices [[buffer(0)]] -) { - type _expr9 = collatz_iterations(v_indices.data[global_id.x]); - v_indices.data[global_id.x] = _expr9; - return; -} - diff --git a/third_party/rust/naga/tests/out/collatz.ron.snap b/third_party/rust/naga/tests/out/collatz.ron similarity index 98% rename from third_party/rust/naga/tests/out/collatz.ron.snap rename to third_party/rust/naga/tests/out/collatz.ron index e4e9224c72c1..65f98a6e8fa0 100644 --- a/third_party/rust/naga/tests/out/collatz.ron.snap +++ b/third_party/rust/naga/tests/out/collatz.ron @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: output ---- ( types: [ ( @@ -16,22 +12,22 @@ expression: output inner: Array( base: 1, size: Dynamic, - stride: Some(4), + stride: 4, ), ), ( name: Some("PrimeIndices"), inner: Struct( - block: true, + level: Root, members: [ ( name: Some("data"), ty: 2, binding: None, - size: None, - align: None, + offset: 0, ), ], + span: 4, ), ), ( @@ -347,4 +343,4 @@ expression: output ), ), ], -) +) \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/collatz.spvasm.snap b/third_party/rust/naga/tests/out/collatz.spvasm similarity index 96% rename from third_party/rust/naga/tests/out/collatz.spvasm.snap rename to third_party/rust/naga/tests/out/collatz.spvasm index 9d56582b9ad1..929a4343d344 100644 --- a/third_party/rust/naga/tests/out/collatz.spvasm.snap +++ b/third_party/rust/naga/tests/out/collatz.spvasm @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: dis ---- ; SPIR-V ; Version: 1.0 ; Generator: rspirv @@ -21,7 +17,6 @@ OpName %15 "i" OpName %18 "collatz_iterations" OpName %45 "global_id" OpName %48 "main" -OpName %48 "main" OpDecorate %8 ArrayStride 4 OpDecorate %9 Block OpMemberDecorate %9 0 Offset 0 @@ -109,4 +104,4 @@ OpBranch %50 %60 = OpAccessChain %53 %11 %56 %52 OpStore %60 %59 OpReturn -OpFunctionEnd +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/empty-Compute.glsl.snap b/third_party/rust/naga/tests/out/empty.Compute.glsl similarity index 71% rename from third_party/rust/naga/tests/out/empty-Compute.glsl.snap rename to third_party/rust/naga/tests/out/empty.Compute.glsl index 4fbc229db66e..63328eab1894 100644 --- a/third_party/rust/naga/tests/out/empty-Compute.glsl.snap +++ b/third_party/rust/naga/tests/out/empty.Compute.glsl @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- #version 310 es precision highp float; @@ -13,4 +9,3 @@ void main() { return; } - diff --git a/third_party/rust/naga/tests/out/empty.hlsl b/third_party/rust/naga/tests/out/empty.hlsl new file mode 100644 index 000000000000..d1d3c9cb27a2 --- /dev/null +++ b/third_party/rust/naga/tests/out/empty.hlsl @@ -0,0 +1,5 @@ + +void main() +{ + return; +} diff --git a/third_party/rust/naga/tests/out/empty.msl.snap b/third_party/rust/naga/tests/out/empty.msl similarity index 62% rename from third_party/rust/naga/tests/out/empty.msl.snap rename to third_party/rust/naga/tests/out/empty.msl index 6cbbbb4bdd57..9b4ad48624ab 100644 --- a/third_party/rust/naga/tests/out/empty.msl.snap +++ b/third_party/rust/naga/tests/out/empty.msl @@ -1,12 +1,8 @@ ---- -source: tests/snapshots.rs -expression: msl ---- #include #include + kernel void main1( ) { return; } - diff --git a/third_party/rust/naga/tests/out/empty.spvasm.snap b/third_party/rust/naga/tests/out/empty.spvasm similarity index 83% rename from third_party/rust/naga/tests/out/empty.spvasm.snap rename to third_party/rust/naga/tests/out/empty.spvasm index bd9279de9a8c..47d3c1756549 100644 --- a/third_party/rust/naga/tests/out/empty.spvasm.snap +++ b/third_party/rust/naga/tests/out/empty.spvasm @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: dis ---- ; SPIR-V ; Version: 1.1 ; Generator: rspirv @@ -18,4 +14,4 @@ OpExecutionMode %4 LocalSize 1 1 1 OpBranch %6 %6 = OpLabel OpReturn -OpFunctionEnd +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/empty.wgsl b/third_party/rust/naga/tests/out/empty.wgsl new file mode 100644 index 000000000000..e89004345fd6 --- /dev/null +++ b/third_party/rust/naga/tests/out/empty.wgsl @@ -0,0 +1,2 @@ +[[stage(compute), workgroup_size(1, 1, 1)]] +fn main(){} diff --git a/third_party/rust/naga/tests/out/image-copy.msl b/third_party/rust/naga/tests/out/image-copy.msl new file mode 100644 index 000000000000..5d2134dbfe4a --- /dev/null +++ b/third_party/rust/naga/tests/out/image-copy.msl @@ -0,0 +1,16 @@ +#include +#include + + +struct main1Input { +}; +kernel void main1( + metal::uint3 local_id [[thread_position_in_threadgroup]] +, metal::texture2d image_src [[user(fake0), center_perspective]] +, metal::texture1d image_dst [[user(fake0), center_perspective]] +) { + metal::int2 _e12 = (int2(image_src.get_width(), image_src.get_height()) * static_cast(metal::uint2(local_id.x, local_id.y))) % metal::int2(10, 20); + metal::uint4 _e13 = image_src.read(metal::uint2(_e12)); + image_dst.write(_e13, metal::uint(_e12.x)); + return; +} diff --git a/third_party/rust/naga/tests/out/image-copy.msl.snap b/third_party/rust/naga/tests/out/image-copy.msl.snap deleted file mode 100644 index 81329b6bd3d6..000000000000 --- a/third_party/rust/naga/tests/out/image-copy.msl.snap +++ /dev/null @@ -1,27 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant int const_10i = 10; -constexpr constant int const_20i = 20; -typedef metal::texture2d type; -typedef metal::texture1d type1; -typedef metal::uint3 type2; -typedef metal::uint2 type3; -typedef metal::int2 type4; -struct main1Input { -}; -kernel void main1( - type2 local_id [[thread_position_in_threadgroup]] -, type image_src [[texture(0)]] -, type1 image_dst [[texture(1)]] -) { - metal::int2 _expr12 = (int2(image_src.get_width(), image_src.get_height()) * static_cast(metal::uint2(local_id.x, local_id.y))) % metal::int2(const_10i, const_20i); - metal::uint4 _expr13 = image_src.read(metal::uint2(_expr12)); - image_dst.write(_expr13, metal::uint(_expr12.x)); - return; -} - diff --git a/third_party/rust/naga/tests/out/interpolate.Fragment.glsl b/third_party/rust/naga/tests/out/interpolate.Fragment.glsl new file mode 100644 index 000000000000..b415997304b5 --- /dev/null +++ b/third_party/rust/naga/tests/out/interpolate.Fragment.glsl @@ -0,0 +1,25 @@ +#version 400 core +struct FragmentInput { + vec4 position; + uint flat1; + float linear; + vec2 linear_centroid; + vec3 linear_sample; + vec4 perspective; + float perspective_centroid; + float perspective_sample; +}; + +flat in uint _vs2fs_location0; +noperspective in float _vs2fs_location1; +noperspective centroid in vec2 _vs2fs_location2; +noperspective sample in vec3 _vs2fs_location3; +smooth in vec4 _vs2fs_location4; +smooth centroid in float _vs2fs_location5; +smooth sample in float _vs2fs_location6; + +void main() { + FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location5, _vs2fs_location6); + return; +} + diff --git a/third_party/rust/naga/tests/out/interpolate.Vertex.glsl b/third_party/rust/naga/tests/out/interpolate.Vertex.glsl new file mode 100644 index 000000000000..e287089a15e9 --- /dev/null +++ b/third_party/rust/naga/tests/out/interpolate.Vertex.glsl @@ -0,0 +1,41 @@ +#version 400 core +struct FragmentInput { + vec4 position; + uint flat1; + float linear; + vec2 linear_centroid; + vec3 linear_sample; + vec4 perspective; + float perspective_centroid; + float perspective_sample; +}; + +flat out uint _vs2fs_location0; +noperspective out float _vs2fs_location1; +noperspective centroid out vec2 _vs2fs_location2; +noperspective sample out vec3 _vs2fs_location3; +smooth out vec4 _vs2fs_location4; +smooth centroid out float _vs2fs_location5; +smooth sample out float _vs2fs_location6; + +void main() { + FragmentInput out1; + out1.position = vec4(2.0, 4.0, 5.0, 6.0); + out1.flat1 = 8u; + out1.linear = 27.0; + out1.linear_centroid = vec2(64.0, 125.0); + out1.linear_sample = vec3(216.0, 343.0, 512.0); + out1.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0); + out1.perspective_centroid = 2197.0; + out1.perspective_sample = 2744.0; + gl_Position = out1.position; + _vs2fs_location0 = out1.flat1; + _vs2fs_location1 = out1.linear; + _vs2fs_location2 = out1.linear_centroid; + _vs2fs_location3 = out1.linear_sample; + _vs2fs_location4 = out1.perspective; + _vs2fs_location5 = out1.perspective_centroid; + _vs2fs_location6 = out1.perspective_sample; + return; +} + diff --git a/third_party/rust/naga/tests/out/interpolate.msl b/third_party/rust/naga/tests/out/interpolate.msl new file mode 100644 index 000000000000..963e78b95ca0 --- /dev/null +++ b/third_party/rust/naga/tests/out/interpolate.msl @@ -0,0 +1,56 @@ +#include +#include + +struct FragmentInput { + metal::float4 position; + metal::uint flat; + float linear; + metal::float2 linear_centroid; + metal::float3 linear_sample; + metal::float4 perspective; + float perspective_centroid; + float perspective_sample; +}; + +struct main1Output { + metal::float4 position [[position]]; + metal::uint flat [[user(loc0), flat]]; + float linear [[user(loc1), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc2), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc3), sample_no_perspective]]; + metal::float4 perspective [[user(loc4), center_perspective]]; + float perspective_centroid [[user(loc5), centroid_perspective]]; + float perspective_sample [[user(loc6), sample_perspective]]; +}; +vertex main1Output main1( +) { + FragmentInput out; + out.position = metal::float4(2.0, 4.0, 5.0, 6.0); + out.flat = 8u; + out.linear = 27.0; + out.linear_centroid = metal::float2(64.0, 125.0); + out.linear_sample = metal::float3(216.0, 343.0, 512.0); + out.perspective = metal::float4(729.0, 1000.0, 1331.0, 1728.0); + out.perspective_centroid = 2197.0; + out.perspective_sample = 2744.0; + const auto _tmp = out; + return main1Output { _tmp.position, _tmp.flat, _tmp.linear, _tmp.linear_centroid, _tmp.linear_sample, _tmp.perspective, _tmp.perspective_centroid, _tmp.perspective_sample }; +} + + +struct main2Input { + metal::uint flat [[user(loc0), flat]]; + float linear [[user(loc1), center_no_perspective]]; + metal::float2 linear_centroid [[user(loc2), centroid_no_perspective]]; + metal::float3 linear_sample [[user(loc3), sample_no_perspective]]; + metal::float4 perspective [[user(loc4), center_perspective]]; + float perspective_centroid [[user(loc5), centroid_perspective]]; + float perspective_sample [[user(loc6), sample_perspective]]; +}; +fragment void main2( + main2Input varyings1 [[stage_in]] +, metal::float4 position [[position]] +) { + const FragmentInput val = { position, varyings1.flat, varyings1.linear, varyings1.linear_centroid, varyings1.linear_sample, varyings1.perspective, varyings1.perspective_centroid, varyings1.perspective_sample }; + return; +} diff --git a/third_party/rust/naga/tests/out/interpolate.spvasm b/third_party/rust/naga/tests/out/interpolate.spvasm new file mode 100644 index 000000000000..1fa0dfbd4db5 --- /dev/null +++ b/third_party/rust/naga/tests/out/interpolate.spvasm @@ -0,0 +1,210 @@ +; SPIR-V +; Version: 1.0 +; Generator: rspirv +; Bound: 109 +OpCapability Shader +OpCapability SampleRateShading +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %42 "main" %29 %31 %33 %35 %37 %39 %40 %41 +OpEntryPoint Fragment %107 "main" %86 %89 %92 %95 %98 %101 %103 %105 +OpExecutionMode %107 OriginUpperLeft +OpSource GLSL 450 +OpName %25 "FragmentInput" +OpMemberName %25 0 "position" +OpMemberName %25 1 "flat" +OpMemberName %25 2 "linear" +OpMemberName %25 3 "linear_centroid" +OpMemberName %25 4 "linear_sample" +OpMemberName %25 5 "perspective" +OpMemberName %25 6 "perspective_centroid" +OpMemberName %25 7 "perspective_sample" +OpName %26 "out" +OpName %29 "position" +OpName %31 "flat" +OpName %33 "linear" +OpName %35 "linear_centroid" +OpName %37 "linear_sample" +OpName %39 "perspective" +OpName %40 "perspective_centroid" +OpName %41 "perspective_sample" +OpName %42 "main" +OpName %86 "position" +OpName %89 "flat" +OpName %92 "linear" +OpName %95 "linear_centroid" +OpName %98 "linear_sample" +OpName %101 "perspective" +OpName %103 "perspective_centroid" +OpName %105 "perspective_sample" +OpName %107 "main" +OpMemberDecorate %25 0 Offset 0 +OpMemberDecorate %25 1 Offset 16 +OpMemberDecorate %25 2 Offset 20 +OpMemberDecorate %25 3 Offset 24 +OpMemberDecorate %25 4 Offset 32 +OpMemberDecorate %25 5 Offset 48 +OpMemberDecorate %25 6 Offset 64 +OpMemberDecorate %25 7 Offset 68 +OpDecorate %29 BuiltIn Position +OpDecorate %31 Location 0 +OpDecorate %31 Flat +OpDecorate %33 Location 1 +OpDecorate %33 NoPerspective +OpDecorate %35 Location 2 +OpDecorate %35 NoPerspective +OpDecorate %35 Centroid +OpDecorate %37 Location 3 +OpDecorate %37 NoPerspective +OpDecorate %37 Sample +OpDecorate %39 Location 4 +OpDecorate %40 Location 5 +OpDecorate %40 Centroid +OpDecorate %41 Location 6 +OpDecorate %41 Sample +OpDecorate %86 BuiltIn FragCoord +OpDecorate %89 Location 0 +OpDecorate %89 Flat +OpDecorate %92 Location 1 +OpDecorate %92 NoPerspective +OpDecorate %95 Location 2 +OpDecorate %95 NoPerspective +OpDecorate %95 Centroid +OpDecorate %98 Location 3 +OpDecorate %98 NoPerspective +OpDecorate %98 Sample +OpDecorate %101 Location 4 +OpDecorate %103 Location 5 +OpDecorate %103 Centroid +OpDecorate %105 Location 6 +OpDecorate %105 Sample +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%3 = OpConstant %4 2.0 +%5 = OpConstant %4 4.0 +%6 = OpConstant %4 5.0 +%7 = OpConstant %4 6.0 +%9 = OpTypeInt 32 0 +%8 = OpConstant %9 8 +%10 = OpConstant %4 27.0 +%11 = OpConstant %4 64.0 +%12 = OpConstant %4 125.0 +%13 = OpConstant %4 216.0 +%14 = OpConstant %4 343.0 +%15 = OpConstant %4 512.0 +%16 = OpConstant %4 729.0 +%17 = OpConstant %4 1000.0 +%18 = OpConstant %4 1331.0 +%19 = OpConstant %4 1728.0 +%20 = OpConstant %4 2197.0 +%21 = OpConstant %4 2744.0 +%22 = OpTypeVector %4 4 +%23 = OpTypeVector %4 2 +%24 = OpTypeVector %4 3 +%25 = OpTypeStruct %22 %9 %4 %23 %24 %22 %4 %4 +%27 = OpTypePointer Function %25 +%30 = OpTypePointer Output %22 +%29 = OpVariable %30 Output +%32 = OpTypePointer Output %9 +%31 = OpVariable %32 Output +%34 = OpTypePointer Output %4 +%33 = OpVariable %34 Output +%36 = OpTypePointer Output %23 +%35 = OpVariable %36 Output +%38 = OpTypePointer Output %24 +%37 = OpVariable %38 Output +%39 = OpVariable %30 Output +%40 = OpVariable %34 Output +%41 = OpVariable %34 Output +%43 = OpTypeFunction %2 +%45 = OpTypePointer Function %22 +%47 = OpTypeInt 32 1 +%48 = OpConstant %47 0 +%50 = OpTypePointer Function %9 +%51 = OpConstant %47 1 +%53 = OpTypePointer Function %4 +%54 = OpConstant %47 2 +%56 = OpTypePointer Function %23 +%58 = OpConstant %47 3 +%60 = OpTypePointer Function %24 +%62 = OpConstant %47 4 +%65 = OpConstant %47 5 +%67 = OpConstant %47 6 +%69 = OpConstant %47 7 +%74 = OpTypePointer Output %4 +%87 = OpTypePointer Input %22 +%86 = OpVariable %87 Input +%90 = OpTypePointer Input %9 +%89 = OpVariable %90 Input +%93 = OpTypePointer Input %4 +%92 = OpVariable %93 Input +%96 = OpTypePointer Input %23 +%95 = OpVariable %96 Input +%99 = OpTypePointer Input %24 +%98 = OpVariable %99 Input +%101 = OpVariable %87 Input +%103 = OpVariable %93 Input +%105 = OpVariable %93 Input +%42 = OpFunction %2 None %43 +%28 = OpLabel +%26 = OpVariable %27 Function +OpBranch %44 +%44 = OpLabel +%46 = OpCompositeConstruct %22 %3 %5 %6 %7 +%49 = OpAccessChain %45 %26 %48 +OpStore %49 %46 +%52 = OpAccessChain %50 %26 %51 +OpStore %52 %8 +%55 = OpAccessChain %53 %26 %54 +OpStore %55 %10 +%57 = OpCompositeConstruct %23 %11 %12 +%59 = OpAccessChain %56 %26 %58 +OpStore %59 %57 +%61 = OpCompositeConstruct %24 %13 %14 %15 +%63 = OpAccessChain %60 %26 %62 +OpStore %63 %61 +%64 = OpCompositeConstruct %22 %16 %17 %18 %19 +%66 = OpAccessChain %45 %26 %65 +OpStore %66 %64 +%68 = OpAccessChain %53 %26 %67 +OpStore %68 %20 +%70 = OpAccessChain %53 %26 %69 +OpStore %70 %21 +%71 = OpLoad %25 %26 +%72 = OpCompositeExtract %22 %71 0 +OpStore %29 %72 +%73 = OpAccessChain %74 %29 %51 +%75 = OpLoad %4 %73 +%76 = OpFNegate %4 %75 +OpStore %73 %76 +%77 = OpCompositeExtract %9 %71 1 +OpStore %31 %77 +%78 = OpCompositeExtract %4 %71 2 +OpStore %33 %78 +%79 = OpCompositeExtract %23 %71 3 +OpStore %35 %79 +%80 = OpCompositeExtract %24 %71 4 +OpStore %37 %80 +%81 = OpCompositeExtract %22 %71 5 +OpStore %39 %81 +%82 = OpCompositeExtract %4 %71 6 +OpStore %40 %82 +%83 = OpCompositeExtract %4 %71 7 +OpStore %41 %83 +OpReturn +OpFunctionEnd +%107 = OpFunction %2 None %43 +%84 = OpLabel +%88 = OpLoad %22 %86 +%91 = OpLoad %9 %89 +%94 = OpLoad %4 %92 +%97 = OpLoad %23 %95 +%100 = OpLoad %24 %98 +%102 = OpLoad %22 %101 +%104 = OpLoad %4 %103 +%106 = OpLoad %4 %105 +%85 = OpCompositeConstruct %25 %88 %91 %94 %97 %100 %102 %104 %106 +OpBranch %108 +%108 = OpLabel +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/operators.Vertex.glsl b/third_party/rust/naga/tests/out/operators.Vertex.glsl new file mode 100644 index 000000000000..97d6d3c20ed0 --- /dev/null +++ b/third_party/rust/naga/tests/out/operators.Vertex.glsl @@ -0,0 +1,11 @@ +#version 310 es + +precision highp float; + + +void main() { + vec2 _expr10 = (((vec2(1.0) + vec2(2.0)) - vec2(3.0)) / vec2(4.0)); + gl_Position = (vec4(_expr10[0], _expr10[1], _expr10[0], _expr10[1]) + vec4((ivec4(5) % ivec4(2)))); + return; +} + diff --git a/third_party/rust/naga/tests/out/operators.msl b/third_party/rust/naga/tests/out/operators.msl new file mode 100644 index 000000000000..2b21eab6249b --- /dev/null +++ b/third_party/rust/naga/tests/out/operators.msl @@ -0,0 +1,12 @@ +#include +#include + + +struct splatOutput { + metal::float4 member [[position]]; +}; +vertex splatOutput splat( +) { + metal::float2 _e10 = ((1.0 + 2.0) - 3.0) / 4.0; + return splatOutput { metal::float4(_e10.x, _e10.y, _e10.x, _e10.y) + static_cast(5 % 2) }; +} diff --git a/third_party/rust/naga/tests/out/operators.spvasm b/third_party/rust/naga/tests/out/operators.spvasm new file mode 100644 index 000000000000..6ee2477c364e --- /dev/null +++ b/third_party/rust/naga/tests/out/operators.spvasm @@ -0,0 +1,48 @@ +; SPIR-V +; Version: 1.0 +; Generator: rspirv +; Bound: 37 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %15 "splat" %13 +OpDecorate %13 BuiltIn Position +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%3 = OpConstant %4 1.0 +%5 = OpConstant %4 2.0 +%6 = OpConstant %4 3.0 +%7 = OpConstant %4 4.0 +%9 = OpTypeInt 32 1 +%8 = OpConstant %9 5 +%10 = OpConstant %9 2 +%11 = OpTypeVector %4 4 +%14 = OpTypePointer Output %11 +%13 = OpVariable %14 Output +%16 = OpTypeFunction %2 +%18 = OpTypeVector %4 2 +%26 = OpTypeVector %9 4 +%15 = OpFunction %2 None %16 +%12 = OpLabel +OpBranch %17 +%17 = OpLabel +%19 = OpCompositeConstruct %18 %5 %5 +%20 = OpCompositeConstruct %18 %3 %3 +%21 = OpFAdd %18 %20 %19 +%22 = OpCompositeConstruct %18 %6 %6 +%23 = OpFSub %18 %21 %22 +%24 = OpCompositeConstruct %18 %7 %7 +%25 = OpFDiv %18 %23 %24 +%27 = OpCompositeConstruct %26 %8 %8 %8 %8 +%28 = OpCompositeConstruct %26 %10 %10 %10 %10 +%29 = OpSMod %26 %27 %28 +%30 = OpCompositeExtract %4 %25 0 +%31 = OpCompositeExtract %4 %25 1 +%32 = OpCompositeExtract %4 %25 0 +%33 = OpCompositeExtract %4 %25 1 +%34 = OpCompositeConstruct %11 %30 %31 %32 %33 +%35 = OpConvertSToF %11 %29 +%36 = OpFAdd %11 %34 %35 +OpStore %13 %36 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/quad-glsl.ron.snap b/third_party/rust/naga/tests/out/quad-glsl.ron.snap deleted file mode 100644 index 2b8256eee016..000000000000 --- a/third_party/rust/naga/tests/out/quad-glsl.ron.snap +++ /dev/null @@ -1,224 +0,0 @@ ---- -source: tests/snapshots.rs -expression: output ---- -( - types: [ - ( - name: None, - inner: Scalar( - kind: Float, - width: 4, - ), - ), - ( - name: None, - inner: Vector( - size: Bi, - kind: Float, - width: 4, - ), - ), - ( - name: None, - inner: Vector( - size: Quad, - kind: Float, - width: 4, - ), - ), - ], - constants: [ - ( - name: None, - specialization: None, - inner: Scalar( - width: 4, - value: Float(1.2000000476837158), - ), - ), - ( - name: Some("c_scale"), - specialization: None, - inner: Scalar( - width: 4, - value: Float(1.2000000476837158), - ), - ), - ( - name: None, - specialization: None, - inner: Scalar( - width: 4, - value: Float(0), - ), - ), - ( - name: None, - specialization: None, - inner: Scalar( - width: 4, - value: Float(1), - ), - ), - ], - global_variables: [ - ( - name: Some("a_pos"), - class: Input, - binding: Some(Location(0)), - ty: 2, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ( - name: Some("a_uv"), - class: Input, - binding: Some(Location(1)), - ty: 2, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ( - name: Some("v_uv"), - class: Output, - binding: Some(Location(0)), - ty: 2, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ( - name: Some("gl_Position"), - class: Output, - binding: Some(BuiltIn(Position)), - ty: 3, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ( - name: Some("v_uv"), - class: Input, - binding: Some(Location(0)), - ty: 2, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ( - name: Some("o_color"), - class: Output, - binding: Some(Location(0)), - ty: 3, - init: None, - interpolation: None, - storage_access: ( - bits: 0, - ), - ), - ], - functions: [], - entry_points: { - (Fragment, "frag_main"): ( - early_depth_test: None, - workgroup_size: (0, 0, 0), - function: ( - name: Some("frag_main"), - arguments: [], - return_type: None, - local_variables: [], - expressions: [ - GlobalVariable(1), - GlobalVariable(2), - GlobalVariable(3), - GlobalVariable(4), - GlobalVariable(5), - GlobalVariable(6), - Constant(2), - Constant(4), - Constant(4), - Constant(4), - Constant(4), - Compose( - ty: 3, - components: [ - 8, - 9, - 10, - 11, - ], - ), - ], - body: [ - Store( - pointer: 6, - value: 12, - ), - Return( - value: None, - ), - ], - ), - ), - (Vertex, "vert_main"): ( - early_depth_test: None, - workgroup_size: (0, 0, 0), - function: ( - name: Some("vert_main"), - arguments: [], - return_type: None, - local_variables: [], - expressions: [ - Constant(1), - Constant(2), - GlobalVariable(1), - GlobalVariable(2), - GlobalVariable(3), - Constant(2), - GlobalVariable(4), - Binary( - op: Multiply, - left: 6, - right: 3, - ), - Constant(3), - Constant(4), - Compose( - ty: 3, - components: [ - 8, - 9, - 10, - ], - ), - ], - body: [ - Store( - pointer: 5, - value: 4, - ), - Store( - pointer: 7, - value: 11, - ), - Return( - value: None, - ), - ], - ), - ), - }, -) diff --git a/third_party/rust/naga/tests/out/quad-glsl.spvasm.snap b/third_party/rust/naga/tests/out/quad-glsl.spvasm.snap deleted file mode 100644 index 1c68ac0440f1..000000000000 --- a/third_party/rust/naga/tests/out/quad-glsl.spvasm.snap +++ /dev/null @@ -1,63 +0,0 @@ ---- -source: tests/snapshots.rs -expression: dis ---- -; SPIR-V -; Version: 1.0 -; Generator: rspirv -; Bound: 28 -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %8 "frag_main" %12 -OpEntryPoint Vertex %15 "vert_main" %25 %20 %18 %23 -OpExecutionMode %8 OriginUpperLeft -OpSource GLSL 450 -OpName %5 "c_scale" -OpName %8 "frag_main" -OpName %12 "o_color" -OpName %8 "frag_main" -OpName %15 "vert_main" -OpName %18 "v_uv" -OpName %20 "a_uv" -OpName %23 "gl_Position" -OpName %25 "a_pos" -OpName %15 "vert_main" -OpDecorate %12 Location 0 -OpDecorate %18 Location 0 -OpDecorate %20 Location 1 -OpDecorate %23 BuiltIn Position -OpDecorate %25 Location 0 -%2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpConstant %4 1.2 -%5 = OpConstant %4 1.2 -%6 = OpConstant %4 0.0 -%7 = OpConstant %4 1.0 -%9 = OpTypeFunction %2 -%11 = OpTypeVector %4 4 -%13 = OpTypePointer Output %11 -%12 = OpVariable %13 Output -%17 = OpTypeVector %4 2 -%19 = OpTypePointer Output %17 -%18 = OpVariable %19 Output -%21 = OpTypePointer Input %17 -%20 = OpVariable %21 Input -%23 = OpVariable %13 Output -%25 = OpVariable %21 Input -%8 = OpFunction %2 None %9 -%10 = OpLabel -%14 = OpCompositeConstruct %11 %7 %7 %7 %7 -OpStore %12 %14 -OpReturn -OpFunctionEnd -%15 = OpFunction %2 None %9 -%16 = OpLabel -%22 = OpLoad %17 %20 -OpStore %18 %22 -%26 = OpLoad %17 %25 -%24 = OpVectorTimesScalar %17 %26 %5 -%27 = OpCompositeConstruct %11 %24 %6 %7 -OpStore %23 %27 -OpReturn -OpFunctionEnd diff --git a/third_party/rust/naga/tests/out/quad-vert.msl b/third_party/rust/naga/tests/out/quad-vert.msl new file mode 100644 index 000000000000..9e0ff87e48ac --- /dev/null +++ b/third_party/rust/naga/tests/out/quad-vert.msl @@ -0,0 +1,54 @@ +#include +#include + +typedef float type6[1u]; +struct gl_PerVertex { + metal::float4 gl_Position; + float gl_PointSize; + type6 gl_ClipDistance; + type6 gl_CullDistance; +}; +struct type10 { + metal::float2 member; + metal::float4 gl_Position1; + float gl_PointSize1; + type6 gl_ClipDistance1; +}; + +void main1( + thread metal::float2& v_uv, + thread metal::float2 const& a_uv, + thread gl_PerVertex& _, + thread metal::float2 const& a_pos +) { + v_uv = a_uv; + metal::float2 _e13 = a_pos; + _.gl_Position = metal::float4(_e13.x, _e13.y, 0.0, 1.0); + return; +} + +struct main2Input { + metal::float2 a_uv1 [[attribute(1)]]; + metal::float2 a_pos1 [[attribute(0)]]; +}; +struct main2Output { + metal::float2 member [[user(loc0), center_perspective]]; + metal::float4 gl_Position1 [[position]]; + float gl_PointSize1 [[point_size]]; + type6 gl_ClipDistance1 [[clip_distance]]; +}; +vertex main2Output main2( + main2Input varyings [[stage_in]] +) { + metal::float2 v_uv = {}; + metal::float2 a_uv = {}; + gl_PerVertex _ = {}; + metal::float2 a_pos = {}; + const auto a_uv1 = varyings.a_uv1; + const auto a_pos1 = varyings.a_pos1; + a_uv = a_uv1; + a_pos = a_pos1; + main1(v_uv, a_uv, _, a_pos); + const auto _tmp = type10 {v_uv, _.gl_Position, _.gl_PointSize, {_.gl_ClipDistance[0]}}; + return main2Output { _tmp.member, _tmp.gl_Position1, _tmp.gl_PointSize1, {_tmp.gl_ClipDistance1[0]} }; +} diff --git a/third_party/rust/naga/tests/out/quad-vert.msl.snap b/third_party/rust/naga/tests/out/quad-vert.msl.snap deleted file mode 100644 index 16b352977103..000000000000 --- a/third_party/rust/naga/tests/out/quad-vert.msl.snap +++ /dev/null @@ -1,75 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant int const_0i = 0; -constexpr constant int const_1i = 1; -constexpr constant int const_2i = 2; -constexpr constant int const_3i = 3; -constexpr constant unsigned const_1u = 1u; -constexpr constant int const_0i1 = 0; -constexpr constant float const_0f = 0.0; -constexpr constant float const_1f = 1.0; -typedef float type; -typedef metal::float2 type1; -typedef thread type1 *type2; -typedef thread type1 *type3; -typedef metal::float4 type4; -typedef metal::uint type5; -typedef type type6[const_1u]; -struct gl_PerVertex { - type4 gl_Position; - type gl_PointSize; - type6 gl_ClipDistance; - type6 gl_CullDistance; -}; -typedef thread gl_PerVertex *type7; -typedef int type8; -typedef thread type4 *type9; -struct type10 { - type1 member; - type4 gl_Position1; - type gl_PointSize1; - type6 gl_ClipDistance1; -}; -void main1( - thread type1& v_uv, - thread type1 const& a_uv, - thread gl_PerVertex& _, - thread type1 const& a_pos -) { - v_uv = a_uv; - type1 _expr13 = a_pos; - _.gl_Position = metal::float4(_expr13.x, _expr13.y, const_0f, const_1f); - return; -} - -struct main2Input { - type1 a_uv1 [[attribute(1)]]; - type1 a_pos1 [[attribute(0)]]; -}; -struct main2Output { - type1 member [[user(loc0)]]; - type4 gl_Position1 [[position]]; - type gl_PointSize1 [[point_size]]; - type6 gl_ClipDistance1 [[clip_distance]]; -}; -vertex main2Output main2( - main2Input varyings [[stage_in]] -) { - type1 v_uv = {}; - type1 a_uv = {}; - gl_PerVertex _ = {}; - type1 a_pos = {}; - const auto a_uv1 = varyings.a_uv1; - const auto a_pos1 = varyings.a_pos1; - a_uv = a_uv1; - a_pos = a_pos1; - main1(v_uv, a_uv, _, a_pos); - const auto _tmp = type10 {v_uv, _.gl_Position, _.gl_PointSize, {_.gl_ClipDistance[0]}}; - return main2Output { _tmp.member, _tmp.gl_Position1, _tmp.gl_PointSize1, {_tmp.gl_ClipDistance1[0]} }; -} - diff --git a/third_party/rust/naga/tests/out/quad-Fragment.glsl.snap b/third_party/rust/naga/tests/out/quad.Fragment.glsl similarity index 80% rename from third_party/rust/naga/tests/out/quad-Fragment.glsl.snap rename to third_party/rust/naga/tests/out/quad.Fragment.glsl index 7d873bc7629a..8062e3d20010 100644 --- a/third_party/rust/naga/tests/out/quad-Fragment.glsl.snap +++ b/third_party/rust/naga/tests/out/quad.Fragment.glsl @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- #version 310 es precision highp float; @@ -13,7 +9,7 @@ struct VertexOutput { uniform highp sampler2D _group_0_binding_0; -layout(location = 0) in vec2 _vs2fs_location0; +smooth layout(location = 0) in vec2 _vs2fs_location0; layout(location = 0) out vec4 _fs2p_location0; void main() { @@ -26,4 +22,3 @@ void main() { return; } - diff --git a/third_party/rust/naga/tests/out/quad-Vertex.glsl.snap b/third_party/rust/naga/tests/out/quad.Vertex.glsl similarity index 52% rename from third_party/rust/naga/tests/out/quad-Vertex.glsl.snap rename to third_party/rust/naga/tests/out/quad.Vertex.glsl index 99ff87ef1a22..751d8c592551 100644 --- a/third_party/rust/naga/tests/out/quad-Vertex.glsl.snap +++ b/third_party/rust/naga/tests/out/quad.Vertex.glsl @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- #version 310 es precision highp float; @@ -13,17 +9,13 @@ struct VertexOutput { layout(location = 0) in vec2 _p2vs_location0; layout(location = 1) in vec2 _p2vs_location1; -layout(location = 0) out vec2 _vs2fs_location0; +smooth layout(location = 0) out vec2 _vs2fs_location0; void main() { vec2 pos = _p2vs_location0; vec2 uv1 = _p2vs_location1; - VertexOutput out1; - out1.uv = uv1; - out1.position = vec4((1.2 * pos), 0.0, 1.0); - _vs2fs_location0 = out1.uv; - gl_Position = out1.position; + _vs2fs_location0 = VertexOutput(uv1, vec4((1.2 * pos), 0.0, 1.0)).uv; + gl_Position = VertexOutput(uv1, vec4((1.2 * pos), 0.0, 1.0)).position; return; } - diff --git a/third_party/rust/naga/tests/out/quad.dot.snap b/third_party/rust/naga/tests/out/quad.dot similarity index 63% rename from third_party/rust/naga/tests/out/quad.dot.snap rename to third_party/rust/naga/tests/out/quad.dot index b839e856d697..60587fc8b17d 100644 --- a/third_party/rust/naga/tests/out/quad.dot.snap +++ b/third_party/rust/naga/tests/out/quad.dot @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- digraph Module { subgraph cluster_globals { label="Globals" @@ -11,50 +7,29 @@ digraph Module { subgraph cluster_ep0 { label="Vertex/'main'" node [ style=filled ] - ep0_l0 [ shape=hexagon label="[1] 'out'" ] ep0_e0 [ fillcolor="#ffffb3" label="[1] Constant" ] ep0_e1 [ color="#8dd3c7" label="[2] Argument[0]" ] ep0_e2 [ color="#8dd3c7" label="[3] Argument[1]" ] - ep0_e3 [ color="#8dd3c7" label="[4] Local" ] - ep0_l0 -> ep0_e3 - ep0_e4 [ color="#8dd3c7" label="[5] AccessIndex[0]" ] - ep0_e3 -> ep0_e4 [ label="base" ] - ep0_e5 [ color="#8dd3c7" label="[6] AccessIndex[1]" ] - ep0_e3 -> ep0_e5 [ label="base" ] - ep0_e6 [ color="#fdb462" label="[7] Multiply" ] - ep0_e1 -> ep0_e6 [ label="right" ] - ep0_e0 -> ep0_e6 [ label="left" ] - ep0_e7 [ fillcolor="#ffffb3" label="[8] Constant" ] - ep0_e8 [ fillcolor="#ffffb3" label="[9] Constant" ] - ep0_e9 [ color="#bebada" label="[10] Compose" ] - { ep0_e6 ep0_e7 ep0_e8 } -> ep0_e9 - ep0_e10 [ color="#fb8072" label="[11] Load" ] - ep0_e3 -> ep0_e10 [ label="pointer" ] + ep0_e3 [ color="#fdb462" label="[4] Multiply" ] + ep0_e1 -> ep0_e3 [ label="right" ] + ep0_e0 -> ep0_e3 [ label="left" ] + ep0_e4 [ fillcolor="#ffffb3" label="[5] Constant" ] + ep0_e5 [ fillcolor="#ffffb3" label="[6] Constant" ] + ep0_e6 [ color="#bebada" label="[7] Compose" ] + { ep0_e3 ep0_e4 ep0_e5 } -> ep0_e6 + ep0_e7 [ color="#bebada" label="[8] Compose" ] + { ep0_e2 ep0_e6 } -> ep0_e7 ep0_s0 [ shape=square label="Root" ] ep0_s1 [ shape=square label="Emit" ] - ep0_s2 [ shape=square label="Store" ] - ep0_s3 [ shape=square label="Emit" ] - ep0_s4 [ shape=square label="Emit" ] - ep0_s5 [ shape=square label="Store" ] - ep0_s6 [ shape=square label="Emit" ] - ep0_s7 [ shape=square label="Return" ] + ep0_s2 [ shape=square label="Emit" ] + ep0_s3 [ shape=square label="Return" ] ep0_s0 -> ep0_s1 [ arrowhead=tee label="" ] ep0_s1 -> ep0_s2 [ arrowhead=tee label="" ] ep0_s2 -> ep0_s3 [ arrowhead=tee label="" ] - ep0_s3 -> ep0_s4 [ arrowhead=tee label="" ] - ep0_s4 -> ep0_s5 [ arrowhead=tee label="" ] - ep0_s5 -> ep0_s6 [ arrowhead=tee label="" ] - ep0_s6 -> ep0_s7 [ arrowhead=tee label="" ] - ep0_e2 -> ep0_s2 [ label="value" ] - ep0_e9 -> ep0_s5 [ label="value" ] - ep0_e10 -> ep0_s7 [ label="value" ] - ep0_s1 -> ep0_e4 [ style=dotted ] - ep0_s2 -> ep0_e4 [ style=dotted ] - ep0_s3 -> ep0_e5 [ style=dotted ] - ep0_s3 -> ep0_e6 [ style=dotted ] - ep0_s4 -> ep0_e9 [ style=dotted ] - ep0_s5 -> ep0_e5 [ style=dotted ] - ep0_s6 -> ep0_e10 [ style=dotted ] + ep0_e7 -> ep0_s3 [ label="value" ] + ep0_s1 -> ep0_e3 [ style=dotted ] + ep0_s2 -> ep0_e6 [ style=dotted ] + ep0_s2 -> ep0_e7 [ style=dotted ] } subgraph cluster_ep1 { label="Fragment/'main'" @@ -108,4 +83,3 @@ digraph Module { ep1_s8 -> ep1_e9 [ style=dotted ] } } - diff --git a/third_party/rust/naga/tests/out/quad.msl b/third_party/rust/naga/tests/out/quad.msl new file mode 100644 index 000000000000..b3fd9acaa3b9 --- /dev/null +++ b/third_party/rust/naga/tests/out/quad.msl @@ -0,0 +1,45 @@ +#include +#include + +constexpr constant float c_scale = 1.2; +struct VertexOutput { + metal::float2 uv; + metal::float4 position; +}; + +struct main1Input { + metal::float2 pos [[attribute(0)]]; + metal::float2 uv1 [[attribute(1)]]; +}; +struct main1Output { + metal::float2 uv [[user(loc0), center_perspective]]; + metal::float4 position [[position]]; +}; +vertex main1Output main1( + main1Input varyings [[stage_in]] +) { + const auto pos = varyings.pos; + const auto uv1 = varyings.uv1; + const auto _tmp = VertexOutput {uv1, metal::float4(c_scale * pos, 0.0, 1.0)}; + return main1Output { _tmp.uv, _tmp.position }; +} + + +struct main2Input { + metal::float2 uv2 [[user(loc0), center_perspective]]; +}; +struct main2Output { + metal::float4 member1 [[color(0)]]; +}; +fragment main2Output main2( + main2Input varyings1 [[stage_in]] +, metal::texture2d u_texture [[user(fake0), center_perspective]] +, metal::sampler u_sampler [[user(fake0), center_perspective]] +) { + const auto uv2 = varyings1.uv2; + metal::float4 _e4 = u_texture.sample(u_sampler, uv2); + if (_e4.w == 0.0) { + metal::discard_fragment(); + } + return main2Output { _e4.w * _e4 }; +} diff --git a/third_party/rust/naga/tests/out/quad.msl.snap b/third_party/rust/naga/tests/out/quad.msl.snap deleted file mode 100644 index 084d7fb87be5..000000000000 --- a/third_party/rust/naga/tests/out/quad.msl.snap +++ /dev/null @@ -1,58 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant float c_scale = 1.2; -constexpr constant float const_0f = 0.0; -constexpr constant float const_1f = 1.0; -typedef float type; -typedef metal::float2 type1; -typedef metal::float4 type2; -struct VertexOutput { - type1 uv; - type2 position; -}; -typedef metal::texture2d type3; -typedef metal::sampler type4; -struct main1Input { - type1 pos [[attribute(0)]]; - type1 uv1 [[attribute(1)]]; -}; -struct main1Output { - type1 uv [[user(loc0)]]; - type2 position [[position]]; -}; -vertex main1Output main1( - main1Input varyings [[stage_in]] -) { - const auto pos = varyings.pos; - const auto uv1 = varyings.uv1; - VertexOutput out; - out.uv = uv1; - out.position = metal::float4(c_scale * pos, const_0f, const_1f); - const auto _tmp = out; - return main1Output { _tmp.uv, _tmp.position }; -} - -struct main2Input { - type1 uv2 [[user(loc0)]]; -}; -struct main2Output { - type2 member1 [[color(0)]]; -}; -fragment main2Output main2( - main2Input varyings1 [[stage_in]] -, type3 u_texture [[texture(0)]] -, type4 u_sampler [[sampler(0)]] -) { - const auto uv2 = varyings1.uv2; - metal::float4 _expr4 = u_texture.sample(u_sampler, uv2); - if (_expr4.w == const_0f) { - metal::discard_fragment(); - } - return main2Output { _expr4.w * _expr4 }; -} - diff --git a/third_party/rust/naga/tests/out/quad.spvasm b/third_party/rust/naga/tests/out/quad.spvasm new file mode 100644 index 000000000000..d15def3de2bd --- /dev/null +++ b/third_party/rust/naga/tests/out/quad.spvasm @@ -0,0 +1,105 @@ +; SPIR-V +; Version: 1.0 +; Generator: rspirv +; Bound: 58 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %26 "main" %17 %20 %22 %24 +OpEntryPoint Fragment %44 "main" %41 %43 +OpExecutionMode %44 OriginUpperLeft +OpSource GLSL 450 +OpName %3 "c_scale" +OpName %9 "VertexOutput" +OpMemberName %9 0 "uv" +OpMemberName %9 1 "position" +OpName %12 "u_texture" +OpName %14 "u_sampler" +OpName %17 "pos" +OpName %20 "uv" +OpName %22 "uv" +OpName %24 "position" +OpName %26 "main" +OpName %41 "uv" +OpName %44 "main" +OpMemberDecorate %9 0 Offset 0 +OpMemberDecorate %9 1 Offset 16 +OpDecorate %12 DescriptorSet 0 +OpDecorate %12 Binding 0 +OpDecorate %14 DescriptorSet 0 +OpDecorate %14 Binding 1 +OpDecorate %17 Location 0 +OpDecorate %20 Location 1 +OpDecorate %22 Location 0 +OpDecorate %24 BuiltIn Position +OpDecorate %41 Location 0 +OpDecorate %43 Location 0 +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%3 = OpConstant %4 1.2 +%5 = OpConstant %4 0.0 +%6 = OpConstant %4 1.0 +%7 = OpTypeVector %4 2 +%8 = OpTypeVector %4 4 +%9 = OpTypeStruct %7 %8 +%10 = OpTypeImage %4 2D 0 0 0 1 Unknown +%11 = OpTypeSampler +%13 = OpTypePointer UniformConstant %10 +%12 = OpVariable %13 UniformConstant +%15 = OpTypePointer UniformConstant %11 +%14 = OpVariable %15 UniformConstant +%18 = OpTypePointer Input %7 +%17 = OpVariable %18 Input +%20 = OpVariable %18 Input +%23 = OpTypePointer Output %7 +%22 = OpVariable %23 Output +%25 = OpTypePointer Output %8 +%24 = OpVariable %25 Output +%27 = OpTypeFunction %2 +%35 = OpTypePointer Output %4 +%36 = OpTypeInt 32 1 +%37 = OpConstant %36 1 +%41 = OpVariable %18 Input +%43 = OpVariable %25 Output +%48 = OpTypeSampledImage %10 +%52 = OpTypeBool +%26 = OpFunction %2 None %27 +%16 = OpLabel +%19 = OpLoad %7 %17 +%21 = OpLoad %7 %20 +OpBranch %28 +%28 = OpLabel +%29 = OpVectorTimesScalar %7 %19 %3 +%30 = OpCompositeConstruct %8 %29 %5 %6 +%31 = OpCompositeConstruct %9 %21 %30 +%32 = OpCompositeExtract %7 %31 0 +OpStore %22 %32 +%33 = OpCompositeExtract %8 %31 1 +OpStore %24 %33 +%34 = OpAccessChain %35 %24 %37 +%38 = OpLoad %4 %34 +%39 = OpFNegate %4 %38 +OpStore %34 %39 +OpReturn +OpFunctionEnd +%44 = OpFunction %2 None %27 +%40 = OpLabel +%42 = OpLoad %7 %41 +%45 = OpLoad %10 %12 +%46 = OpLoad %11 %14 +OpBranch %47 +%47 = OpLabel +%49 = OpSampledImage %48 %45 %46 +%50 = OpImageSampleImplicitLod %8 %49 %42 +%51 = OpCompositeExtract %4 %50 3 +%53 = OpFOrdEqual %52 %51 %5 +OpSelectionMerge %54 None +OpBranchConditional %53 %55 %54 +%55 = OpLabel +OpKill +%54 = OpLabel +%56 = OpCompositeExtract %4 %50 3 +%57 = OpVectorTimesScalar %8 %50 %56 +OpStore %43 %57 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/quad.spvasm.snap b/third_party/rust/naga/tests/out/quad.spvasm.snap deleted file mode 100644 index 800c4f612fdc..000000000000 --- a/third_party/rust/naga/tests/out/quad.spvasm.snap +++ /dev/null @@ -1,121 +0,0 @@ ---- -source: tests/snapshots.rs -expression: dis ---- -; SPIR-V -; Version: 1.0 -; Generator: rspirv -; Bound: 65 -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %28 "main" %19 %22 %24 %26 -OpEntryPoint Fragment %51 "main" %48 %50 -OpExecutionMode %51 OriginUpperLeft -OpSource GLSL 450 -OpName %3 "c_scale" -OpName %9 "VertexOutput" -OpMemberName %9 0 "uv" -OpMemberName %9 1 "position" -OpName %12 "u_texture" -OpName %14 "u_sampler" -OpName %16 "out" -OpName %19 "pos" -OpName %22 "uv" -OpName %24 "uv" -OpName %26 "position" -OpName %28 "main" -OpName %28 "main" -OpName %48 "uv" -OpName %51 "main" -OpName %51 "main" -OpMemberDecorate %9 0 Offset 0 -OpMemberDecorate %9 1 Offset 16 -OpDecorate %12 DescriptorSet 0 -OpDecorate %12 Binding 0 -OpDecorate %14 DescriptorSet 0 -OpDecorate %14 Binding 1 -OpDecorate %19 Location 0 -OpDecorate %22 Location 1 -OpDecorate %24 Location 0 -OpDecorate %26 BuiltIn Position -OpDecorate %48 Location 0 -OpDecorate %50 Location 0 -%2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpConstant %4 1.2 -%5 = OpConstant %4 0.0 -%6 = OpConstant %4 1.0 -%7 = OpTypeVector %4 2 -%8 = OpTypeVector %4 4 -%9 = OpTypeStruct %7 %8 -%10 = OpTypeImage %4 2D 0 0 0 1 Unknown -%11 = OpTypeSampler -%13 = OpTypePointer UniformConstant %10 -%12 = OpVariable %13 UniformConstant -%15 = OpTypePointer UniformConstant %11 -%14 = OpVariable %15 UniformConstant -%17 = OpTypePointer Function %9 -%20 = OpTypePointer Input %7 -%19 = OpVariable %20 Input -%22 = OpVariable %20 Input -%25 = OpTypePointer Output %7 -%24 = OpVariable %25 Output -%27 = OpTypePointer Output %8 -%26 = OpVariable %27 Output -%29 = OpTypeFunction %2 -%31 = OpTypePointer Function %7 -%32 = OpTypeInt 32 1 -%33 = OpConstant %32 0 -%35 = OpTypePointer Function %8 -%38 = OpConstant %32 1 -%44 = OpTypePointer Output %4 -%48 = OpVariable %20 Input -%50 = OpVariable %27 Output -%55 = OpTypeSampledImage %10 -%59 = OpTypeBool -%28 = OpFunction %2 None %29 -%18 = OpLabel -%16 = OpVariable %17 Function -%21 = OpLoad %7 %19 -%23 = OpLoad %7 %22 -OpBranch %30 -%30 = OpLabel -%34 = OpAccessChain %31 %16 %33 -OpStore %34 %23 -%36 = OpVectorTimesScalar %7 %21 %3 -%37 = OpCompositeConstruct %8 %36 %5 %6 -%39 = OpAccessChain %35 %16 %38 -OpStore %39 %37 -%40 = OpLoad %9 %16 -%41 = OpCompositeExtract %7 %40 0 -OpStore %24 %41 -%42 = OpCompositeExtract %8 %40 1 -OpStore %26 %42 -%43 = OpAccessChain %44 %26 %38 -%45 = OpLoad %4 %43 -%46 = OpFNegate %4 %45 -OpStore %43 %46 -OpReturn -OpFunctionEnd -%51 = OpFunction %2 None %29 -%47 = OpLabel -%49 = OpLoad %7 %48 -%52 = OpLoad %10 %12 -%53 = OpLoad %11 %14 -OpBranch %54 -%54 = OpLabel -%56 = OpSampledImage %55 %52 %53 -%57 = OpImageSampleImplicitLod %8 %56 %49 -%58 = OpCompositeExtract %4 %57 3 -%60 = OpFOrdEqual %59 %58 %5 -OpSelectionMerge %61 None -OpBranchConditional %60 %62 %61 -%62 = OpLabel -OpKill -%61 = OpLabel -%63 = OpCompositeExtract %4 %57 3 -%64 = OpVectorTimesScalar %8 %57 %63 -OpStore %50 %64 -OpReturn -OpFunctionEnd diff --git a/third_party/rust/naga/tests/out/shadow-Fragment.glsl.snap b/third_party/rust/naga/tests/out/shadow.Fragment.glsl similarity index 81% rename from third_party/rust/naga/tests/out/shadow-Fragment.glsl.snap rename to third_party/rust/naga/tests/out/shadow.Fragment.glsl index 14501be8d27a..b045c725085b 100644 --- a/third_party/rust/naga/tests/out/shadow-Fragment.glsl.snap +++ b/third_party/rust/naga/tests/out/shadow.Fragment.glsl @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- #version 310 es precision highp float; @@ -22,16 +18,15 @@ readonly buffer Lights_block_1 { uniform highp sampler2DArrayShadow _group_0_binding_2; -layout(location = 0) in vec3 _vs2fs_location0; -layout(location = 1) in vec4 _vs2fs_location1; +smooth layout(location = 0) in vec3 _vs2fs_location0; +smooth layout(location = 1) in vec4 _vs2fs_location1; layout(location = 0) out vec4 _fs2p_location0; float fetch_shadow(uint light_id, vec4 homogeneous_coords) { if((homogeneous_coords[3] <= 0.0)) { return 1.0; } - float _expr15 = (1.0 / homogeneous_coords[3]); - float _expr28 = textureGrad(_group_0_binding_2, vec4((((vec2(homogeneous_coords[0], homogeneous_coords[1]) * vec2(0.5, -0.5)) * _expr15) + vec2(0.5, 0.5)), int(light_id), (homogeneous_coords[2] * _expr15)), vec2(0, 0), vec2(0,0)); + float _expr28 = textureGrad(_group_0_binding_2, vec4((((vec2(homogeneous_coords[0], homogeneous_coords[1]) * vec2(0.5, -0.5)) / vec2(homogeneous_coords[3])) + vec2(0.5, 0.5)), int(light_id), (homogeneous_coords[2] / homogeneous_coords[3])), vec2(0, 0), vec2(0,0)); return _expr28; } @@ -53,4 +48,3 @@ void main() { return; } - diff --git a/third_party/rust/naga/tests/out/shadow.info.ron.snap b/third_party/rust/naga/tests/out/shadow.info.ron similarity index 94% rename from third_party/rust/naga/tests/out/shadow.info.ron.snap rename to third_party/rust/naga/tests/out/shadow.info.ron index 9280830557bb..d1491f6c8cfa 100644 --- a/third_party/rust/naga/tests/out/shadow.info.ron.snap +++ b/third_party/rust/naga/tests/out/shadow.info.ron @@ -1,12 +1,8 @@ ---- -source: tests/snapshots.rs -expression: output ---- ( functions: [ ( flags: ( - bits: 15, + bits: 31, ), available_stages: ( bits: 7, @@ -217,7 +213,7 @@ expression: output bits: 0, ), ), - ref_count: 3, + ref_count: 2, assignable_global: None, ty: Value(Scalar( kind: Float, @@ -842,7 +838,11 @@ expression: output ), ref_count: 1, assignable_global: None, - ty: Handle(9), + ty: Value(Vector( + size: Bi, + kind: Float, + width: 4, + )), ), ( uniformity: ( @@ -1063,7 +1063,7 @@ expression: output ), ( flags: ( - bits: 15, + bits: 31, ), available_stages: ( bits: 7, @@ -2753,7 +2753,7 @@ expression: output entry_points: [ ( flags: ( - bits: 15, + bits: 31, ), available_stages: ( bits: 7, @@ -2873,236 +2873,4 @@ expression: output ], ), ], - layouter: ( - layouts: [ - ( - size: 4, - alignment: 4, - ), - ( - size: 12, - alignment: 16, - ), - ( - size: 4, - alignment: 4, - ), - ( - size: 16, - alignment: 16, - ), - ( - size: 1, - alignment: 1, - ), - ( - size: 8, - alignment: 8, - ), - ( - size: 0, - alignment: 1, - ), - ( - size: 0, - alignment: 1, - ), - ( - size: 8, - alignment: 8, - ), - ( - size: 4, - alignment: 4, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 16, - alignment: 16, - ), - ( - size: 16, - alignment: 16, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 64, - alignment: 16, - ), - ( - size: 96, - alignment: 16, - ), - ( - size: 96, - alignment: 96, - ), - ( - size: 128, - alignment: 96, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 4, - alignment: 1, - ), - ( - size: 0, - alignment: 1, - ), - ( - size: 0, - alignment: 1, - ), - ], - ), -) +) \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/shadow.msl b/third_party/rust/naga/tests/out/shadow.msl new file mode 100644 index 000000000000..68f2b8bfa663 --- /dev/null +++ b/third_party/rust/naga/tests/out/shadow.msl @@ -0,0 +1,64 @@ +#include +#include + +constexpr constant unsigned c_max_lights = 10u; +struct Globals { + metal::uint4 num_lights; +}; +struct Light { + metal::float4x4 proj; + metal::float4 pos; + metal::float4 color; +}; +typedef Light type3[1]; +struct Lights { + type3 data; +}; +constant metal::float3 c_ambient = {0.05, 0.05, 0.05}; + +float fetch_shadow( + metal::uint light_id, + metal::float4 homogeneous_coords, + metal::depth2d_array t_shadow, + metal::sampler sampler_shadow +) { + if (homogeneous_coords.w <= 0.0) { + return 1.0; + } + float _e28 = t_shadow.sample_compare(sampler_shadow, ((metal::float2(homogeneous_coords.x, homogeneous_coords.y) * metal::float2(0.5, -0.5)) / homogeneous_coords.w) + metal::float2(0.5, 0.5), static_cast(light_id), homogeneous_coords.z / homogeneous_coords.w); + return _e28; +} + +struct fs_mainInput { + metal::float3 raw_normal [[user(loc0), center_perspective]]; + metal::float4 position [[user(loc1), center_perspective]]; +}; +struct fs_mainOutput { + metal::float4 member [[color(0)]]; +}; +fragment fs_mainOutput fs_main( + fs_mainInput varyings [[stage_in]] +, constant Globals& u_globals [[user(fake0), center_perspective]] +, constant Lights& s_lights [[user(fake0), center_perspective]] +, metal::depth2d_array t_shadow [[user(fake0), center_perspective]] +, metal::sampler sampler_shadow [[user(fake0), center_perspective]] +) { + const auto raw_normal = varyings.raw_normal; + const auto position = varyings.position; + metal::float3 color1 = c_ambient; + metal::uint i = 0u; + bool loop_init = true; + while(true) { + if (!loop_init) { + i = i + 1u; + } + loop_init = false; + if (i >= metal::min(u_globals.num_lights.x, c_max_lights)) { + break; + } + Light _e21 = s_lights.data[i]; + float _e25 = fetch_shadow(i, _e21.proj * position, t_shadow, sampler_shadow); + color1 = color1 + ((_e25 * metal::max(0.0, metal::dot(metal::normalize(raw_normal), metal::normalize(metal::float3(_e21.pos.x, _e21.pos.y, _e21.pos.z) - metal::float3(position.x, position.y, position.z))))) * metal::float3(_e21.color.x, _e21.color.y, _e21.color.z)); + } + return fs_mainOutput { metal::float4(color1, 1.0) }; +} diff --git a/third_party/rust/naga/tests/out/shadow.msl.snap b/third_party/rust/naga/tests/out/shadow.msl.snap deleted file mode 100644 index e2a9c1c86671..000000000000 --- a/third_party/rust/naga/tests/out/shadow.msl.snap +++ /dev/null @@ -1,85 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant float const_0f = 0.0; -constexpr constant float const_1f = 1.0; -constexpr constant float const_0_50f = 0.5; -constexpr constant float const_n0_50f = -0.5; -constexpr constant float const_0_05f = 0.05; -constexpr constant unsigned c_max_lights = 10u; -constexpr constant unsigned const_0u = 0u; -constexpr constant unsigned const_1u = 1u; -typedef metal::uint4 type; -struct Globals { - type num_lights; -}; -typedef metal::float4x4 type1; -typedef metal::float4 type2; -struct Light { - type1 proj; - type2 pos; - type2 color; -}; -typedef Light type3[1]; -struct Lights { - type3 data; -}; -typedef metal::depth2d_array type4; -typedef metal::sampler type5; -typedef metal::uint type6; -typedef float type7; -typedef metal::float2 type8; -typedef metal::float3 type9; -constexpr constant type9 c_ambient = {const_0_05f, const_0_05f, const_0_05f}; -type7 fetch_shadow( - type6 light_id, - type2 homogeneous_coords, - type4 t_shadow, - type5 sampler_shadow -) { - if (homogeneous_coords.w <= const_0f) { - return const_1f; - } - float _expr15 = const_1f / homogeneous_coords.w; - float _expr28 = t_shadow.sample_compare(sampler_shadow, ((metal::float2(homogeneous_coords.x, homogeneous_coords.y) * metal::float2(const_0_50f, const_n0_50f)) * _expr15) + metal::float2(const_0_50f, const_0_50f), static_cast(light_id), homogeneous_coords.z * _expr15); - return _expr28; -} - -struct fs_mainInput { - type9 raw_normal [[user(loc0)]]; - type2 position [[user(loc1)]]; -}; -struct fs_mainOutput { - type2 member [[color(0)]]; -}; -fragment fs_mainOutput fs_main( - fs_mainInput varyings [[stage_in]] -, constant Globals& u_globals [[buffer(0)]] -, constant Lights& s_lights [[buffer(1)]] -, type4 t_shadow [[texture(0)]] -, type5 sampler_shadow [[sampler(0)]] -) { - const auto raw_normal = varyings.raw_normal; - const auto position = varyings.position; - type9 color1 = c_ambient; - type6 i = const_0u; - bool loop_init = true; - while(true) { - if (!loop_init) { - i = i + const_1u; - } - loop_init = false; - if (i >= metal::min(u_globals.num_lights.x, c_max_lights)) { - break; - } - Light _expr21 = s_lights.data[i]; - type7 _expr25 = fetch_shadow(i, _expr21.proj * position, t_shadow, sampler_shadow); - color1 = color1 + ((_expr25 * metal::max(const_0f, metal::dot(metal::normalize(raw_normal), metal::normalize(metal::float3(_expr21.pos.x, _expr21.pos.y, _expr21.pos.z) - metal::float3(position.x, position.y, position.z))))) * metal::float3(_expr21.color.x, _expr21.color.y, _expr21.color.z)); - } - return fs_mainOutput { metal::float4(color1, const_1f) }; -} - diff --git a/third_party/rust/naga/tests/out/shadow.ron.snap b/third_party/rust/naga/tests/out/shadow.ron similarity index 97% rename from third_party/rust/naga/tests/out/shadow.ron.snap rename to third_party/rust/naga/tests/out/shadow.ron index cb7c0d81e6fd..e99b3c01218e 100644 --- a/third_party/rust/naga/tests/out/shadow.ron.snap +++ b/third_party/rust/naga/tests/out/shadow.ron @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: output ---- ( types: [ ( @@ -106,16 +102,16 @@ expression: output ( name: Some("Globals"), inner: Struct( - block: true, + level: Root, members: [ ( name: Some("num_lights"), ty: 13, binding: None, - size: None, - align: None, + offset: 0, ), ], + span: 16, ), ), ( @@ -150,30 +146,30 @@ expression: output ( name: Some("Light"), inner: Struct( - block: false, + level: Normal( + alignment: 16, + ), members: [ ( name: Some("proj"), ty: 18, binding: None, - size: None, - align: None, + offset: 0, ), ( name: Some("pos"), ty: 4, binding: None, - size: None, - align: None, + offset: 64, ), ( name: Some("color"), ty: 4, binding: None, - size: None, - align: None, + offset: 80, ), ], + span: 96, ), ), ( @@ -181,22 +177,22 @@ expression: output inner: Array( base: 19, size: Dynamic, - stride: Some(96), + stride: 96, ), ), ( name: Some("Lights"), inner: Struct( - block: true, + level: Root, members: [ ( name: Some("data"), ty: 20, binding: None, - size: None, - align: None, + offset: 0, ), ], + span: 96, ), ), ( @@ -973,12 +969,9 @@ expression: output left: 55, right: 57, ), - Compose( - ty: 9, - components: [ - 13, - 13, - ], + Splat( + size: Bi, + value: 13, ), Binary( op: Add, @@ -1524,17 +1517,29 @@ expression: output ( name: Some("in_normal_fs"), ty: 2, - binding: Some(Location(0, Some(Perspective))), + binding: Some(Location( + location: 0, + interpolation: Some(Perspective), + sampling: Some(Center), + )), ), ( name: Some("in_position_fs"), ty: 4, - binding: Some(Location(1, Some(Perspective))), + binding: Some(Location( + location: 1, + interpolation: Some(Perspective), + sampling: Some(Center), + )), ), ], result: Some(( ty: 4, - binding: Some(Location(0, None)), + binding: Some(Location( + location: 0, + interpolation: None, + sampling: None, + )), )), local_variables: [], expressions: [ @@ -1572,4 +1577,4 @@ expression: output ), ), ], -) +) \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/shadow.spvasm b/third_party/rust/naga/tests/out/shadow.spvasm new file mode 100644 index 000000000000..1016e20605f6 --- /dev/null +++ b/third_party/rust/naga/tests/out/shadow.spvasm @@ -0,0 +1,208 @@ +; SPIR-V +; Version: 1.2 +; Generator: rspirv +; Bound: 137 +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %82 "fs_main" %74 %77 %80 +OpExecutionMode %82 OriginUpperLeft +OpSource GLSL 450 +OpName %9 "c_max_lights" +OpName %14 "Globals" +OpMemberName %14 0 "num_lights" +OpName %17 "Light" +OpMemberName %17 0 "proj" +OpMemberName %17 1 "pos" +OpMemberName %17 2 "color" +OpName %19 "Lights" +OpMemberName %19 0 "data" +OpName %24 "c_ambient" +OpName %25 "u_globals" +OpName %27 "s_lights" +OpName %29 "t_shadow" +OpName %31 "sampler_shadow" +OpName %36 "fetch_shadow" +OpName %69 "color" +OpName %71 "i" +OpName %74 "raw_normal" +OpName %77 "position" +OpName %82 "fs_main" +OpDecorate %14 Block +OpMemberDecorate %14 0 Offset 0 +OpMemberDecorate %17 0 Offset 0 +OpMemberDecorate %17 0 ColMajor +OpMemberDecorate %17 0 MatrixStride 16 +OpMemberDecorate %17 1 Offset 64 +OpMemberDecorate %17 2 Offset 80 +OpDecorate %18 ArrayStride 96 +OpDecorate %19 Block +OpMemberDecorate %19 0 Offset 0 +OpDecorate %25 DescriptorSet 0 +OpDecorate %25 Binding 0 +OpDecorate %27 NonWritable +OpDecorate %27 DescriptorSet 0 +OpDecorate %27 Binding 1 +OpDecorate %29 DescriptorSet 0 +OpDecorate %29 Binding 2 +OpDecorate %31 DescriptorSet 0 +OpDecorate %31 Binding 3 +OpDecorate %74 Location 0 +OpDecorate %77 Location 1 +OpDecorate %80 Location 0 +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%3 = OpConstant %4 0.0 +%5 = OpConstant %4 1.0 +%6 = OpConstant %4 0.5 +%7 = OpConstant %4 -0.5 +%8 = OpConstant %4 0.05 +%10 = OpTypeInt 32 0 +%9 = OpConstant %10 10 +%11 = OpConstant %10 0 +%12 = OpConstant %10 1 +%13 = OpTypeVector %10 4 +%14 = OpTypeStruct %13 +%16 = OpTypeVector %4 4 +%15 = OpTypeMatrix %16 4 +%17 = OpTypeStruct %15 %16 %16 +%18 = OpTypeRuntimeArray %17 +%19 = OpTypeStruct %18 +%20 = OpTypeImage %4 2D 1 1 0 1 Unknown +%21 = OpTypeSampler +%22 = OpTypeVector %4 2 +%23 = OpTypeVector %4 3 +%24 = OpConstantComposite %23 %8 %8 %8 +%26 = OpTypePointer Uniform %14 +%25 = OpVariable %26 Uniform +%28 = OpTypePointer StorageBuffer %19 +%27 = OpVariable %28 StorageBuffer +%30 = OpTypePointer UniformConstant %20 +%29 = OpVariable %30 UniformConstant +%32 = OpTypePointer UniformConstant %21 +%31 = OpVariable %32 UniformConstant +%37 = OpTypeFunction %4 %10 %16 +%42 = OpTypeBool +%56 = OpTypeInt 32 1 +%61 = OpTypeSampledImage %20 +%68 = OpConstant %4 0.0 +%70 = OpTypePointer Function %23 +%72 = OpTypePointer Function %10 +%75 = OpTypePointer Input %23 +%74 = OpVariable %75 Input +%78 = OpTypePointer Input %16 +%77 = OpVariable %78 Input +%81 = OpTypePointer Output %16 +%80 = OpVariable %81 Output +%83 = OpTypeFunction %2 +%93 = OpTypePointer Uniform %13 +%94 = OpConstant %56 0 +%102 = OpTypePointer StorageBuffer %18 +%104 = OpTypePointer StorageBuffer %17 +%36 = OpFunction %4 None %37 +%34 = OpFunctionParameter %10 +%35 = OpFunctionParameter %16 +%33 = OpLabel +%38 = OpLoad %20 %29 +%39 = OpLoad %21 %31 +OpBranch %40 +%40 = OpLabel +%41 = OpCompositeExtract %4 %35 3 +%43 = OpFOrdLessThanEqual %42 %41 %3 +OpSelectionMerge %44 None +OpBranchConditional %43 %45 %44 +%45 = OpLabel +OpReturnValue %5 +%44 = OpLabel +%46 = OpCompositeConstruct %22 %6 %7 +%47 = OpCompositeExtract %4 %35 0 +%48 = OpCompositeExtract %4 %35 1 +%49 = OpCompositeConstruct %22 %47 %48 +%50 = OpFMul %22 %49 %46 +%51 = OpCompositeExtract %4 %35 3 +%52 = OpCompositeConstruct %22 %51 %51 +%53 = OpFDiv %22 %50 %52 +%54 = OpCompositeConstruct %22 %6 %6 +%55 = OpFAdd %22 %53 %54 +%57 = OpBitcast %56 %34 +%58 = OpCompositeExtract %4 %35 2 +%59 = OpCompositeExtract %4 %35 3 +%60 = OpFDiv %4 %58 %59 +%62 = OpCompositeExtract %4 %55 0 +%63 = OpCompositeExtract %4 %55 1 +%64 = OpConvertUToF %4 %57 +%65 = OpCompositeConstruct %23 %62 %63 %64 +%66 = OpSampledImage %61 %38 %39 +%67 = OpImageSampleDrefExplicitLod %4 %66 %65 %60 Lod %68 +OpReturnValue %67 +OpFunctionEnd +%82 = OpFunction %2 None %83 +%73 = OpLabel +%69 = OpVariable %70 Function %24 +%71 = OpVariable %72 Function %11 +%76 = OpLoad %23 %74 +%79 = OpLoad %16 %77 +%84 = OpLoad %20 %29 +%85 = OpLoad %21 %31 +OpBranch %86 +%86 = OpLabel +%87 = OpExtInst %23 %1 Normalize %76 +OpBranch %88 +%88 = OpLabel +OpLoopMerge %89 %91 None +OpBranch %90 +%90 = OpLabel +%92 = OpLoad %10 %71 +%95 = OpAccessChain %93 %25 %94 +%96 = OpLoad %13 %95 +%97 = OpCompositeExtract %10 %96 0 +%98 = OpExtInst %10 %1 UMin %97 %9 +%99 = OpUGreaterThanEqual %42 %92 %98 +OpSelectionMerge %100 None +OpBranchConditional %99 %101 %100 +%101 = OpLabel +OpBranch %89 +%100 = OpLabel +%103 = OpLoad %10 %71 +%105 = OpAccessChain %104 %27 %94 %103 +%106 = OpLoad %17 %105 +%107 = OpLoad %10 %71 +%108 = OpCompositeExtract %15 %106 0 +%109 = OpMatrixTimesVector %16 %108 %79 +%110 = OpFunctionCall %4 %36 %107 %109 +%111 = OpCompositeExtract %16 %106 1 +%112 = OpCompositeExtract %4 %111 0 +%113 = OpCompositeExtract %4 %111 1 +%114 = OpCompositeExtract %4 %111 2 +%115 = OpCompositeConstruct %23 %112 %113 %114 +%116 = OpCompositeExtract %4 %79 0 +%117 = OpCompositeExtract %4 %79 1 +%118 = OpCompositeExtract %4 %79 2 +%119 = OpCompositeConstruct %23 %116 %117 %118 +%120 = OpFSub %23 %115 %119 +%121 = OpExtInst %23 %1 Normalize %120 +%122 = OpDot %4 %87 %121 +%123 = OpExtInst %4 %1 FMax %3 %122 +%124 = OpLoad %23 %69 +%125 = OpFMul %4 %110 %123 +%126 = OpCompositeExtract %16 %106 2 +%127 = OpCompositeExtract %4 %126 0 +%128 = OpCompositeExtract %4 %126 1 +%129 = OpCompositeExtract %4 %126 2 +%130 = OpCompositeConstruct %23 %127 %128 %129 +%131 = OpVectorTimesScalar %23 %130 %125 +%132 = OpFAdd %23 %124 %131 +OpStore %69 %132 +OpBranch %91 +%91 = OpLabel +%133 = OpLoad %10 %71 +%134 = OpIAdd %10 %133 %12 +OpStore %71 %134 +OpBranch %88 +%89 = OpLabel +%135 = OpLoad %23 %69 +%136 = OpCompositeConstruct %16 %135 %5 +OpStore %80 %136 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/shadow.spvasm.snap b/third_party/rust/naga/tests/out/shadow.spvasm.snap deleted file mode 100644 index e478f288e7e9..000000000000 --- a/third_party/rust/naga/tests/out/shadow.spvasm.snap +++ /dev/null @@ -1,212 +0,0 @@ ---- -source: tests/snapshots.rs -expression: dis ---- -; SPIR-V -; Version: 1.2 -; Generator: rspirv -; Bound: 136 -OpCapability Shader -OpExtension "SPV_KHR_storage_buffer_storage_class" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %81 "fs_main" %73 %76 %79 -OpExecutionMode %81 OriginUpperLeft -OpSource GLSL 450 -OpName %9 "c_max_lights" -OpName %14 "Globals" -OpMemberName %14 0 "num_lights" -OpName %17 "Light" -OpMemberName %17 0 "proj" -OpMemberName %17 1 "pos" -OpMemberName %17 2 "color" -OpName %19 "Lights" -OpMemberName %19 0 "data" -OpName %24 "c_ambient" -OpName %25 "u_globals" -OpName %27 "s_lights" -OpName %29 "t_shadow" -OpName %31 "sampler_shadow" -OpName %36 "fetch_shadow" -OpName %68 "color" -OpName %70 "i" -OpName %73 "raw_normal" -OpName %76 "position" -OpName %81 "fs_main" -OpName %81 "fs_main" -OpDecorate %14 Block -OpMemberDecorate %14 0 Offset 0 -OpMemberDecorate %17 0 Offset 0 -OpMemberDecorate %17 0 ColMajor -OpMemberDecorate %17 0 MatrixStride 16 -OpMemberDecorate %17 1 Offset 64 -OpMemberDecorate %17 2 Offset 80 -OpDecorate %18 ArrayStride 96 -OpDecorate %19 Block -OpMemberDecorate %19 0 Offset 0 -OpDecorate %25 DescriptorSet 0 -OpDecorate %25 Binding 0 -OpDecorate %27 NonWritable -OpDecorate %27 DescriptorSet 0 -OpDecorate %27 Binding 1 -OpDecorate %29 DescriptorSet 0 -OpDecorate %29 Binding 2 -OpDecorate %31 DescriptorSet 0 -OpDecorate %31 Binding 3 -OpDecorate %73 Location 0 -OpDecorate %76 Location 1 -OpDecorate %79 Location 0 -%2 = OpTypeVoid -%4 = OpTypeFloat 32 -%3 = OpConstant %4 0.0 -%5 = OpConstant %4 1.0 -%6 = OpConstant %4 0.5 -%7 = OpConstant %4 -0.5 -%8 = OpConstant %4 0.05 -%10 = OpTypeInt 32 0 -%9 = OpConstant %10 10 -%11 = OpConstant %10 0 -%12 = OpConstant %10 1 -%13 = OpTypeVector %10 4 -%14 = OpTypeStruct %13 -%16 = OpTypeVector %4 4 -%15 = OpTypeMatrix %16 4 -%17 = OpTypeStruct %15 %16 %16 -%18 = OpTypeRuntimeArray %17 -%19 = OpTypeStruct %18 -%20 = OpTypeImage %4 2D 1 1 0 1 Unknown -%21 = OpTypeSampler -%22 = OpTypeVector %4 2 -%23 = OpTypeVector %4 3 -%24 = OpConstantComposite %23 %8 %8 %8 -%26 = OpTypePointer Uniform %14 -%25 = OpVariable %26 Uniform -%28 = OpTypePointer StorageBuffer %19 -%27 = OpVariable %28 StorageBuffer -%30 = OpTypePointer UniformConstant %20 -%29 = OpVariable %30 UniformConstant -%32 = OpTypePointer UniformConstant %21 -%31 = OpVariable %32 UniformConstant -%37 = OpTypeFunction %4 %10 %16 -%42 = OpTypeBool -%56 = OpTypeInt 32 1 -%60 = OpTypeSampledImage %20 -%67 = OpConstant %4 0.0 -%69 = OpTypePointer Function %23 -%71 = OpTypePointer Function %10 -%74 = OpTypePointer Input %23 -%73 = OpVariable %74 Input -%77 = OpTypePointer Input %16 -%76 = OpVariable %77 Input -%80 = OpTypePointer Output %16 -%79 = OpVariable %80 Output -%82 = OpTypeFunction %2 -%92 = OpTypePointer Uniform %13 -%93 = OpConstant %56 0 -%101 = OpTypePointer StorageBuffer %18 -%103 = OpTypePointer StorageBuffer %17 -%36 = OpFunction %4 None %37 -%34 = OpFunctionParameter %10 -%35 = OpFunctionParameter %16 -%33 = OpLabel -%38 = OpLoad %20 %29 -%39 = OpLoad %21 %31 -OpBranch %40 -%40 = OpLabel -%41 = OpCompositeExtract %4 %35 3 -%43 = OpFOrdLessThanEqual %42 %41 %3 -OpSelectionMerge %44 None -OpBranchConditional %43 %45 %44 -%45 = OpLabel -OpReturnValue %5 -%44 = OpLabel -%46 = OpCompositeConstruct %22 %6 %7 -%47 = OpCompositeExtract %4 %35 3 -%48 = OpFDiv %4 %5 %47 -%49 = OpCompositeExtract %4 %35 0 -%50 = OpCompositeExtract %4 %35 1 -%51 = OpCompositeConstruct %22 %49 %50 -%52 = OpFMul %22 %51 %46 -%53 = OpVectorTimesScalar %22 %52 %48 -%54 = OpCompositeConstruct %22 %6 %6 -%55 = OpFAdd %22 %53 %54 -%57 = OpBitcast %56 %34 -%58 = OpCompositeExtract %4 %35 2 -%59 = OpFMul %4 %58 %48 -%61 = OpCompositeExtract %4 %55 0 -%62 = OpCompositeExtract %4 %55 1 -%63 = OpConvertUToF %4 %57 -%64 = OpCompositeConstruct %23 %61 %62 %63 -%65 = OpSampledImage %60 %38 %39 -%66 = OpImageSampleDrefExplicitLod %4 %65 %64 %59 Lod %67 -OpReturnValue %66 -OpFunctionEnd -%81 = OpFunction %2 None %82 -%72 = OpLabel -%68 = OpVariable %69 Function %24 -%70 = OpVariable %71 Function %11 -%75 = OpLoad %23 %73 -%78 = OpLoad %16 %76 -%83 = OpLoad %20 %29 -%84 = OpLoad %21 %31 -OpBranch %85 -%85 = OpLabel -%86 = OpExtInst %23 %1 Normalize %75 -OpBranch %87 -%87 = OpLabel -OpLoopMerge %88 %90 None -OpBranch %89 -%89 = OpLabel -%91 = OpLoad %10 %70 -%94 = OpAccessChain %92 %25 %93 -%95 = OpLoad %13 %94 -%96 = OpCompositeExtract %10 %95 0 -%97 = OpExtInst %10 %1 UMin %96 %9 -%98 = OpUGreaterThanEqual %42 %91 %97 -OpSelectionMerge %99 None -OpBranchConditional %98 %100 %99 -%100 = OpLabel -OpBranch %88 -%99 = OpLabel -%102 = OpLoad %10 %70 -%104 = OpAccessChain %103 %27 %93 %102 -%105 = OpLoad %17 %104 -%106 = OpLoad %10 %70 -%107 = OpCompositeExtract %15 %105 0 -%108 = OpMatrixTimesVector %16 %107 %78 -%109 = OpFunctionCall %4 %36 %106 %108 -%110 = OpCompositeExtract %16 %105 1 -%111 = OpCompositeExtract %4 %110 0 -%112 = OpCompositeExtract %4 %110 1 -%113 = OpCompositeExtract %4 %110 2 -%114 = OpCompositeConstruct %23 %111 %112 %113 -%115 = OpCompositeExtract %4 %78 0 -%116 = OpCompositeExtract %4 %78 1 -%117 = OpCompositeExtract %4 %78 2 -%118 = OpCompositeConstruct %23 %115 %116 %117 -%119 = OpFSub %23 %114 %118 -%120 = OpExtInst %23 %1 Normalize %119 -%121 = OpDot %4 %86 %120 -%122 = OpExtInst %4 %1 FMax %3 %121 -%123 = OpLoad %23 %68 -%124 = OpFMul %4 %109 %122 -%125 = OpCompositeExtract %16 %105 2 -%126 = OpCompositeExtract %4 %125 0 -%127 = OpCompositeExtract %4 %125 1 -%128 = OpCompositeExtract %4 %125 2 -%129 = OpCompositeConstruct %23 %126 %127 %128 -%130 = OpVectorTimesScalar %23 %129 %124 -%131 = OpFAdd %23 %123 %130 -OpStore %68 %131 -OpBranch %90 -%90 = OpLabel -%132 = OpLoad %10 %70 -%133 = OpIAdd %10 %132 %12 -OpStore %70 %133 -OpBranch %87 -%88 = OpLabel -%134 = OpLoad %23 %68 -%135 = OpCompositeConstruct %16 %134 %5 -OpStore %79 %135 -OpReturn -OpFunctionEnd diff --git a/third_party/rust/naga/tests/out/skybox-Vertex.glsl.snap b/third_party/rust/naga/tests/out/skybox-Vertex.glsl.snap deleted file mode 100644 index 8c27eed330fa..000000000000 --- a/third_party/rust/naga/tests/out/skybox-Vertex.glsl.snap +++ /dev/null @@ -1,37 +0,0 @@ ---- -source: tests/snapshots.rs -expression: string ---- -#version 310 es - -precision highp float; - -struct VertexOutput { - vec4 position; - vec3 uv; -}; - -uniform Data_block_0 { - mat4x4 proj_inv; - mat4x4 view; -} _group_0_binding_0; - -layout(location = 0) out vec3 _vs2fs_location0; - -void main() { - uint vertex_index = uint(gl_VertexID); - int tmp1_; - int tmp2_; - VertexOutput out1; - tmp1_ = (int(vertex_index) / 2); - tmp2_ = (int(vertex_index) & 1); - vec4 _expr24 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0); - vec4 _expr50 = (_group_0_binding_0.proj_inv * _expr24); - out1.uv = (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr50[0], _expr50[1], _expr50[2])); - out1.position = _expr24; - gl_Position = out1.position; - _vs2fs_location0 = out1.uv; - return; -} - - diff --git a/third_party/rust/naga/tests/out/skybox-Fragment.glsl.snap b/third_party/rust/naga/tests/out/skybox.Fragment.glsl similarity index 78% rename from third_party/rust/naga/tests/out/skybox-Fragment.glsl.snap rename to third_party/rust/naga/tests/out/skybox.Fragment.glsl index 2975a920b971..c8a25b4488c1 100644 --- a/third_party/rust/naga/tests/out/skybox-Fragment.glsl.snap +++ b/third_party/rust/naga/tests/out/skybox.Fragment.glsl @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: string ---- #version 310 es precision highp float; @@ -13,7 +9,7 @@ struct VertexOutput { uniform highp samplerCube _group_0_binding_1; -layout(location = 0) in vec3 _vs2fs_location0; +smooth layout(location = 0) in vec3 _vs2fs_location0; layout(location = 0) out vec4 _fs2p_location0; void main() { @@ -23,4 +19,3 @@ void main() { return; } - diff --git a/third_party/rust/naga/tests/out/skybox.Vertex.glsl b/third_party/rust/naga/tests/out/skybox.Vertex.glsl new file mode 100644 index 000000000000..e76121da33cd --- /dev/null +++ b/third_party/rust/naga/tests/out/skybox.Vertex.glsl @@ -0,0 +1,29 @@ +#version 310 es + +precision highp float; + +struct VertexOutput { + vec4 position; + vec3 uv; +}; + +uniform Data_block_0 { + mat4x4 proj_inv; + mat4x4 view; +} _group_0_binding_0; + +smooth layout(location = 0) out vec3 _vs2fs_location0; + +void main() { + uint vertex_index = uint(gl_VertexID); + int tmp1_; + int tmp2_; + tmp1_ = (int(vertex_index) / 2); + tmp2_ = (int(vertex_index) & 1); + vec4 _expr24 = vec4(((float(tmp1_) * 4.0) - 1.0), ((float(tmp2_) * 4.0) - 1.0), 0.0, 1.0); + vec4 _expr50 = (_group_0_binding_0.proj_inv * _expr24); + gl_Position = VertexOutput(_expr24, (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr50[0], _expr50[1], _expr50[2]))).position; + _vs2fs_location0 = VertexOutput(_expr24, (transpose(mat3x3(vec3(_group_0_binding_0.view[0][0], _group_0_binding_0.view[0][1], _group_0_binding_0.view[0][2]), vec3(_group_0_binding_0.view[1][0], _group_0_binding_0.view[1][1], _group_0_binding_0.view[1][2]), vec3(_group_0_binding_0.view[2][0], _group_0_binding_0.view[2][1], _group_0_binding_0.view[2][2]))) * vec3(_expr50[0], _expr50[1], _expr50[2]))).uv; + return; +} + diff --git a/third_party/rust/naga/tests/out/skybox.msl b/third_party/rust/naga/tests/out/skybox.msl new file mode 100644 index 000000000000..bd3763713f02 --- /dev/null +++ b/third_party/rust/naga/tests/out/skybox.msl @@ -0,0 +1,56 @@ +#include +#include + +struct VertexOutput { + metal::float4 position; + metal::float3 uv; +}; +struct Data { + metal::float4x4 proj_inv; + metal::float4x4 view; +}; + +struct vs_mainInput { +}; +struct vs_mainOutput { + metal::float4 position [[position]]; + metal::float3 uv [[user(loc0), center_perspective]]; +}; +vertex vs_mainOutput vs_main( + metal::uint vertex_index [[vertex_id]] +, constant Data& r_data [[buffer(0)]] +) { + int tmp1_; + int tmp2_; + tmp1_ = static_cast(vertex_index) / 2; + tmp2_ = static_cast(vertex_index) & 1; + metal::float4 _e24 = metal::float4((static_cast(tmp1_) * 4.0) - 1.0, (static_cast(tmp2_) * 4.0) - 1.0, 0.0, 1.0); + metal::float4 _e50 = r_data.proj_inv * _e24; + const auto _tmp = VertexOutput {_e24, metal::transpose(metal::float3x3(metal::float3(r_data.view[0].x, r_data.view[0].y, r_data.view[0].z), metal::float3(r_data.view[1].x, r_data.view[1].y, r_data.view[1].z), metal::float3(r_data.view[2].x, r_data.view[2].y, r_data.view[2].z))) * metal::float3(_e50.x, _e50.y, _e50.z)}; + return vs_mainOutput { _tmp.position, _tmp.uv }; +} + + +struct fs_mainInput { + metal::float3 uv [[user(loc0), center_perspective]]; +}; +struct fs_mainOutput { + metal::float4 member1 [[color(0)]]; +}; +fragment fs_mainOutput fs_main( + fs_mainInput varyings1 [[stage_in]] +, metal::float4 position [[position]] +, metal::texturecube r_texture [[texture(0)]] +) { + constexpr metal::sampler r_sampler( + metal::s_address::clamp_to_edge, + metal::t_address::clamp_to_edge, + metal::r_address::clamp_to_edge, + metal::mag_filter::linear, + metal::min_filter::linear, + metal::coord::normalized + ); + const VertexOutput in = { position, varyings1.uv }; + metal::float4 _e5 = r_texture.sample(r_sampler, in.uv); + return fs_mainOutput { _e5 }; +} diff --git a/third_party/rust/naga/tests/out/skybox.msl.snap b/third_party/rust/naga/tests/out/skybox.msl.snap deleted file mode 100644 index 1fbf706d97f3..000000000000 --- a/third_party/rust/naga/tests/out/skybox.msl.snap +++ /dev/null @@ -1,68 +0,0 @@ ---- -source: tests/snapshots.rs -expression: msl ---- -#include -#include - -constexpr constant int const_2i = 2; -constexpr constant int const_1i = 1; -constexpr constant float const_4f = 4.0; -constexpr constant float const_1f = 1.0; -constexpr constant float const_0f = 0.0; -typedef metal::float4 type; -typedef metal::float3 type1; -struct VertexOutput { - type position; - type1 uv; -}; -typedef metal::float4x4 type2; -struct Data { - type2 proj_inv; - type2 view; -}; -typedef metal::uint type3; -typedef int type4; -typedef metal::float3x3 type5; -typedef metal::texturecube type6; -typedef metal::sampler type7; -struct vs_mainInput { -}; -struct vs_mainOutput { - type position [[position]]; - type1 uv [[user(loc0)]]; -}; -vertex vs_mainOutput vs_main( - type3 vertex_index [[vertex_id]] -, constant Data& r_data [[buffer(0)]] -) { - type4 tmp1_; - type4 tmp2_; - VertexOutput out; - tmp1_ = static_cast(vertex_index) / const_2i; - tmp2_ = static_cast(vertex_index) & const_1i; - type _expr24 = metal::float4((static_cast(tmp1_) * const_4f) - const_1f, (static_cast(tmp2_) * const_4f) - const_1f, const_0f, const_1f); - metal::float4 _expr50 = r_data.proj_inv * _expr24; - out.uv = metal::transpose(metal::float3x3(metal::float3(r_data.view[0].x, r_data.view[0].y, r_data.view[0].z), metal::float3(r_data.view[1].x, r_data.view[1].y, r_data.view[1].z), metal::float3(r_data.view[2].x, r_data.view[2].y, r_data.view[2].z))) * metal::float3(_expr50.x, _expr50.y, _expr50.z); - out.position = _expr24; - const auto _tmp = out; - return vs_mainOutput { _tmp.position, _tmp.uv }; -} - -struct fs_mainInput { - type1 uv [[user(loc0)]]; -}; -struct fs_mainOutput { - type member1 [[color(0)]]; -}; -fragment fs_mainOutput fs_main( - fs_mainInput varyings1 [[stage_in]] -, type position [[position]] -, type6 r_texture [[texture(0)]] -, type7 r_sampler [[sampler(1)]] -) { - const VertexOutput in = { position, varyings1.uv }; - metal::float4 _expr5 = r_texture.sample(r_sampler, in.uv); - return fs_mainOutput { _expr5 }; -} - diff --git a/third_party/rust/naga/tests/out/skybox.spvasm b/third_party/rust/naga/tests/out/skybox.spvasm new file mode 100644 index 000000000000..c51900db33c7 --- /dev/null +++ b/third_party/rust/naga/tests/out/skybox.spvasm @@ -0,0 +1,145 @@ +; SPIR-V +; Version: 1.0 +; Generator: rspirv +; Bound: 105 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %36 "vs_main" %29 %32 %34 +OpEntryPoint Fragment %97 "fs_main" %90 %93 %96 +OpExecutionMode %97 OriginUpperLeft +OpMemberDecorate %12 0 Offset 0 +OpMemberDecorate %12 1 Offset 16 +OpDecorate %14 Block +OpMemberDecorate %14 0 Offset 0 +OpMemberDecorate %14 0 ColMajor +OpMemberDecorate %14 0 MatrixStride 16 +OpMemberDecorate %14 1 Offset 64 +OpMemberDecorate %14 1 ColMajor +OpMemberDecorate %14 1 MatrixStride 16 +OpDecorate %19 DescriptorSet 0 +OpDecorate %19 Binding 0 +OpDecorate %21 DescriptorSet 0 +OpDecorate %21 Binding 1 +OpDecorate %23 DescriptorSet 0 +OpDecorate %23 Binding 2 +OpDecorate %29 BuiltIn VertexIndex +OpDecorate %32 BuiltIn Position +OpDecorate %34 Location 0 +OpDecorate %90 BuiltIn FragCoord +OpDecorate %93 Location 0 +OpDecorate %96 Location 0 +%2 = OpTypeVoid +%4 = OpTypeInt 32 1 +%3 = OpConstant %4 2 +%5 = OpConstant %4 1 +%7 = OpTypeFloat 32 +%6 = OpConstant %7 4.0 +%8 = OpConstant %7 1.0 +%9 = OpConstant %7 0.0 +%10 = OpTypeVector %7 4 +%11 = OpTypeVector %7 3 +%12 = OpTypeStruct %10 %11 +%13 = OpTypeMatrix %10 4 +%14 = OpTypeStruct %13 %13 +%15 = OpTypeInt 32 0 +%16 = OpTypeMatrix %11 3 +%17 = OpTypeImage %7 Cube 0 0 0 1 Unknown +%18 = OpTypeSampler +%20 = OpTypePointer Uniform %14 +%19 = OpVariable %20 Uniform +%22 = OpTypePointer UniformConstant %17 +%21 = OpVariable %22 UniformConstant +%24 = OpTypePointer UniformConstant %18 +%23 = OpVariable %24 UniformConstant +%26 = OpTypePointer Function %4 +%30 = OpTypePointer Input %15 +%29 = OpVariable %30 Input +%33 = OpTypePointer Output %10 +%32 = OpVariable %33 Output +%35 = OpTypePointer Output %11 +%34 = OpVariable %35 Output +%37 = OpTypeFunction %2 +%52 = OpTypePointer Uniform %13 +%76 = OpConstant %4 0 +%91 = OpTypePointer Input %10 +%90 = OpVariable %91 Input +%94 = OpTypePointer Input %11 +%93 = OpVariable %94 Input +%96 = OpVariable %33 Output +%102 = OpTypeSampledImage %17 +%36 = OpFunction %2 None %37 +%28 = OpLabel +%25 = OpVariable %26 Function +%27 = OpVariable %26 Function +%31 = OpLoad %15 %29 +OpBranch %38 +%38 = OpLabel +%39 = OpBitcast %4 %31 +%40 = OpSDiv %4 %39 %3 +OpStore %25 %40 +%41 = OpBitcast %4 %31 +%42 = OpBitwiseAnd %4 %41 %5 +OpStore %27 %42 +%43 = OpLoad %4 %25 +%44 = OpConvertSToF %7 %43 +%45 = OpFMul %7 %44 %6 +%46 = OpFSub %7 %45 %8 +%47 = OpLoad %4 %27 +%48 = OpConvertSToF %7 %47 +%49 = OpFMul %7 %48 %6 +%50 = OpFSub %7 %49 %8 +%51 = OpCompositeConstruct %10 %46 %50 %9 %8 +%53 = OpAccessChain %52 %19 %5 +%54 = OpLoad %13 %53 +%55 = OpCompositeExtract %10 %54 0 +%56 = OpCompositeExtract %7 %55 0 +%57 = OpCompositeExtract %7 %55 1 +%58 = OpCompositeExtract %7 %55 2 +%59 = OpCompositeConstruct %11 %56 %57 %58 +%60 = OpAccessChain %52 %19 %5 +%61 = OpLoad %13 %60 +%62 = OpCompositeExtract %10 %61 1 +%63 = OpCompositeExtract %7 %62 0 +%64 = OpCompositeExtract %7 %62 1 +%65 = OpCompositeExtract %7 %62 2 +%66 = OpCompositeConstruct %11 %63 %64 %65 +%67 = OpAccessChain %52 %19 %5 +%68 = OpLoad %13 %67 +%69 = OpCompositeExtract %10 %68 2 +%70 = OpCompositeExtract %7 %69 0 +%71 = OpCompositeExtract %7 %69 1 +%72 = OpCompositeExtract %7 %69 2 +%73 = OpCompositeConstruct %11 %70 %71 %72 +%74 = OpCompositeConstruct %16 %59 %66 %73 +%75 = OpTranspose %16 %74 +%77 = OpAccessChain %52 %19 %76 +%78 = OpLoad %13 %77 +%79 = OpMatrixTimesVector %10 %78 %51 +%80 = OpCompositeExtract %7 %79 0 +%81 = OpCompositeExtract %7 %79 1 +%82 = OpCompositeExtract %7 %79 2 +%83 = OpCompositeConstruct %11 %80 %81 %82 +%84 = OpMatrixTimesVector %11 %75 %83 +%85 = OpCompositeConstruct %12 %51 %84 +%86 = OpCompositeExtract %10 %85 0 +OpStore %32 %86 +%87 = OpCompositeExtract %11 %85 1 +OpStore %34 %87 +OpReturn +OpFunctionEnd +%97 = OpFunction %2 None %37 +%88 = OpLabel +%92 = OpLoad %10 %90 +%95 = OpLoad %11 %93 +%89 = OpCompositeConstruct %12 %92 %95 +%98 = OpLoad %17 %21 +%99 = OpLoad %18 %23 +OpBranch %100 +%100 = OpLabel +%101 = OpCompositeExtract %11 %89 1 +%103 = OpSampledImage %102 %98 %99 +%104 = OpImageSampleImplicitLod %10 %103 %101 +OpStore %96 %104 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/out/skybox.spvasm.snap b/third_party/rust/naga/tests/out/skybox.spvasm.snap deleted file mode 100644 index d41aa067b24f..000000000000 --- a/third_party/rust/naga/tests/out/skybox.spvasm.snap +++ /dev/null @@ -1,157 +0,0 @@ ---- -source: tests/snapshots.rs -expression: dis ---- -; SPIR-V -; Version: 1.0 -; Generator: rspirv -; Bound: 111 -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %38 "vs_main" %31 %34 %36 -OpEntryPoint Fragment %103 "fs_main" %96 %99 %102 -OpExecutionMode %103 OriginUpperLeft -OpMemberDecorate %12 0 Offset 0 -OpMemberDecorate %12 1 Offset 16 -OpDecorate %14 Block -OpMemberDecorate %14 0 Offset 0 -OpMemberDecorate %14 0 ColMajor -OpMemberDecorate %14 0 MatrixStride 16 -OpMemberDecorate %14 1 Offset 64 -OpMemberDecorate %14 1 ColMajor -OpMemberDecorate %14 1 MatrixStride 16 -OpDecorate %19 DescriptorSet 0 -OpDecorate %19 Binding 0 -OpDecorate %21 DescriptorSet 0 -OpDecorate %21 Binding 1 -OpDecorate %23 DescriptorSet 0 -OpDecorate %23 Binding 2 -OpDecorate %31 BuiltIn VertexIndex -OpDecorate %34 BuiltIn Position -OpDecorate %36 Location 0 -OpDecorate %96 BuiltIn FragCoord -OpDecorate %99 Location 0 -OpDecorate %102 Location 0 -%2 = OpTypeVoid -%4 = OpTypeInt 32 1 -%3 = OpConstant %4 2 -%5 = OpConstant %4 1 -%7 = OpTypeFloat 32 -%6 = OpConstant %7 4.0 -%8 = OpConstant %7 1.0 -%9 = OpConstant %7 0.0 -%10 = OpTypeVector %7 4 -%11 = OpTypeVector %7 3 -%12 = OpTypeStruct %10 %11 -%13 = OpTypeMatrix %10 4 -%14 = OpTypeStruct %13 %13 -%15 = OpTypeInt 32 0 -%16 = OpTypeMatrix %11 3 -%17 = OpTypeImage %7 Cube 0 0 0 1 Unknown -%18 = OpTypeSampler -%20 = OpTypePointer Uniform %14 -%19 = OpVariable %20 Uniform -%22 = OpTypePointer UniformConstant %17 -%21 = OpVariable %22 UniformConstant -%24 = OpTypePointer UniformConstant %18 -%23 = OpVariable %24 UniformConstant -%26 = OpTypePointer Function %4 -%29 = OpTypePointer Function %12 -%32 = OpTypePointer Input %15 -%31 = OpVariable %32 Input -%35 = OpTypePointer Output %10 -%34 = OpVariable %35 Output -%37 = OpTypePointer Output %11 -%36 = OpVariable %37 Output -%39 = OpTypeFunction %2 -%54 = OpTypePointer Uniform %13 -%78 = OpConstant %4 0 -%82 = OpTypePointer Function %11 -%89 = OpTypePointer Function %10 -%97 = OpTypePointer Input %10 -%96 = OpVariable %97 Input -%100 = OpTypePointer Input %11 -%99 = OpVariable %100 Input -%102 = OpVariable %35 Output -%108 = OpTypeSampledImage %17 -%38 = OpFunction %2 None %39 -%30 = OpLabel -%25 = OpVariable %26 Function -%27 = OpVariable %26 Function -%28 = OpVariable %29 Function -%33 = OpLoad %15 %31 -OpBranch %40 -%40 = OpLabel -%41 = OpBitcast %4 %33 -%42 = OpSDiv %4 %41 %3 -OpStore %25 %42 -%43 = OpBitcast %4 %33 -%44 = OpBitwiseAnd %4 %43 %5 -OpStore %27 %44 -%45 = OpLoad %4 %25 -%46 = OpConvertSToF %7 %45 -%47 = OpFMul %7 %46 %6 -%48 = OpFSub %7 %47 %8 -%49 = OpLoad %4 %27 -%50 = OpConvertSToF %7 %49 -%51 = OpFMul %7 %50 %6 -%52 = OpFSub %7 %51 %8 -%53 = OpCompositeConstruct %10 %48 %52 %9 %8 -%55 = OpAccessChain %54 %19 %5 -%56 = OpLoad %13 %55 -%57 = OpCompositeExtract %10 %56 0 -%58 = OpCompositeExtract %7 %57 0 -%59 = OpCompositeExtract %7 %57 1 -%60 = OpCompositeExtract %7 %57 2 -%61 = OpCompositeConstruct %11 %58 %59 %60 -%62 = OpAccessChain %54 %19 %5 -%63 = OpLoad %13 %62 -%64 = OpCompositeExtract %10 %63 1 -%65 = OpCompositeExtract %7 %64 0 -%66 = OpCompositeExtract %7 %64 1 -%67 = OpCompositeExtract %7 %64 2 -%68 = OpCompositeConstruct %11 %65 %66 %67 -%69 = OpAccessChain %54 %19 %5 -%70 = OpLoad %13 %69 -%71 = OpCompositeExtract %10 %70 2 -%72 = OpCompositeExtract %7 %71 0 -%73 = OpCompositeExtract %7 %71 1 -%74 = OpCompositeExtract %7 %71 2 -%75 = OpCompositeConstruct %11 %72 %73 %74 -%76 = OpCompositeConstruct %16 %61 %68 %75 -%77 = OpTranspose %16 %76 -%79 = OpAccessChain %54 %19 %78 -%80 = OpLoad %13 %79 -%81 = OpMatrixTimesVector %10 %80 %53 -%83 = OpCompositeExtract %7 %81 0 -%84 = OpCompositeExtract %7 %81 1 -%85 = OpCompositeExtract %7 %81 2 -%86 = OpCompositeConstruct %11 %83 %84 %85 -%87 = OpMatrixTimesVector %11 %77 %86 -%88 = OpAccessChain %82 %28 %5 -OpStore %88 %87 -%90 = OpAccessChain %89 %28 %78 -OpStore %90 %53 -%91 = OpLoad %12 %28 -%92 = OpCompositeExtract %10 %91 0 -OpStore %34 %92 -%93 = OpCompositeExtract %11 %91 1 -OpStore %36 %93 -OpReturn -OpFunctionEnd -%103 = OpFunction %2 None %39 -%94 = OpLabel -%98 = OpLoad %10 %96 -%101 = OpLoad %11 %99 -%95 = OpCompositeConstruct %12 %98 %101 -%104 = OpLoad %17 %21 -%105 = OpLoad %18 %23 -OpBranch %106 -%106 = OpLabel -%107 = OpCompositeExtract %11 %95 1 -%109 = OpSampledImage %108 %104 %105 -%110 = OpImageSampleImplicitLod %10 %109 %107 -OpStore %102 %110 -OpReturn -OpFunctionEnd diff --git a/third_party/rust/naga/tests/out/texture-array.msl b/third_party/rust/naga/tests/out/texture-array.msl new file mode 100644 index 000000000000..98f5d22d046f --- /dev/null +++ b/third_party/rust/naga/tests/out/texture-array.msl @@ -0,0 +1,29 @@ +#include +#include + +struct PushConstants { + metal::uint index; +}; + +struct main1Input { + metal::float2 tex_coord [[user(loc0), center_perspective]]; +}; +struct main1Output { + metal::float4 member [[color(1)]]; +}; +fragment main1Output main1( + main1Input varyings [[stage_in]] +, metal::texture2d texture0_ [[user(fake0), center_perspective]] +, metal::texture2d texture1_ [[user(fake0), center_perspective]] +, metal::sampler sampler [[user(fake0), center_perspective]] +, constant PushConstants& pc [[user(fake0), center_perspective]] +) { + const auto tex_coord = varyings.tex_coord; + if (pc.index == 0u) { + metal::float4 _e9 = texture0_.sample(sampler, tex_coord); + return main1Output { _e9 }; + } else { + metal::float4 _e10 = texture1_.sample(sampler, tex_coord); + return main1Output { _e10 }; + } +} diff --git a/third_party/rust/naga/tests/out/texture-array.spvasm.snap b/third_party/rust/naga/tests/out/texture-array.spvasm similarity index 95% rename from third_party/rust/naga/tests/out/texture-array.spvasm.snap rename to third_party/rust/naga/tests/out/texture-array.spvasm index 2a5b56ef9903..1f4ba03f465c 100644 --- a/third_party/rust/naga/tests/out/texture-array.spvasm.snap +++ b/third_party/rust/naga/tests/out/texture-array.spvasm @@ -1,7 +1,3 @@ ---- -source: tests/snapshots.rs -expression: dis ---- ; SPIR-V ; Version: 1.5 ; Generator: rspirv @@ -20,7 +16,6 @@ OpName %14 "sampler" OpName %16 "pc" OpName %19 "tex_coord" OpName %24 "main" -OpName %24 "main" OpDecorate %8 Block OpMemberDecorate %8 0 Offset 0 OpDecorate %11 DescriptorSet 0 @@ -82,4 +77,4 @@ OpStore %22 %44 OpReturn %37 = OpLabel OpBranch %29 -OpFunctionEnd +OpFunctionEnd \ No newline at end of file diff --git a/third_party/rust/naga/tests/snapshots.rs b/third_party/rust/naga/tests/snapshots.rs index e978a00510ba..a52b8b6f5ed4 100644 --- a/third_party/rust/naga/tests/snapshots.rs +++ b/third_party/rust/naga/tests/snapshots.rs @@ -1,3 +1,11 @@ +//TODO: move this to a binary target once Rust supports +// binary-specific dependencies. + +use std::{fs, path::PathBuf}; + +const DIR_IN: &str = "tests/in"; +const DIR_OUT: &str = "tests/out"; + bitflags::bitflags! { struct Targets: u32 { const IR = 0x1; @@ -6,39 +14,11 @@ bitflags::bitflags! { const METAL = 0x8; const GLSL = 0x10; const DOT = 0x20; + const HLSL = 0x40; + const WGSL = 0x80; } } -#[derive(Hash, PartialEq, Eq, serde::Deserialize)] -enum Stage { - Vertex, - Fragment, - Compute, -} - -#[derive(Hash, PartialEq, Eq, serde::Deserialize)] -struct BindSource { - stage: Stage, - group: u32, - binding: u32, -} - -#[derive(serde::Deserialize)] -struct BindTarget { - #[cfg_attr(not(feature = "msl-out"), allow(dead_code))] - #[serde(default)] - buffer: Option, - #[cfg_attr(not(feature = "msl-out"), allow(dead_code))] - #[serde(default)] - texture: Option, - #[cfg_attr(not(feature = "msl-out"), allow(dead_code))] - #[serde(default)] - sampler: Option, - #[cfg_attr(not(feature = "msl-out"), allow(dead_code))] - #[serde(default)] - mutable: bool, -} - #[derive(Default, serde::Deserialize)] struct Parameters { #[cfg_attr(not(feature = "spv-out"), allow(dead_code))] @@ -49,21 +29,20 @@ struct Parameters { spv_debug: bool, #[cfg_attr(not(feature = "spv-out"), allow(dead_code))] spv_adjust_coordinate_space: bool, - #[cfg_attr(not(feature = "msl-out"), allow(dead_code))] - mtl_bindings: naga::FastHashMap, -} - -#[allow(dead_code)] -fn with_snapshot_settings ()>(snapshot_assertion: F) { - let mut settings = insta::Settings::new(); - settings.set_snapshot_path("out"); - settings.set_prepend_module_to_snapshot(false); - settings.bind(|| snapshot_assertion()); + #[cfg(all(feature = "deserialize", feature = "msl-out"))] + #[serde(default)] + msl: naga::back::msl::Options, + #[cfg(all(not(feature = "deserialize"), feature = "msl-out"))] + msl_custom: bool, + #[cfg_attr(not(feature = "glsl-out"), allow(dead_code))] + #[serde(default)] + glsl_desktop_version: Option, } #[allow(dead_code, unused_variables)] fn check_targets(module: &naga::Module, name: &str, targets: Targets) { - let params = match std::fs::read_to_string(format!("tests/in/{}{}", name, ".param.ron")) { + let root = env!("CARGO_MANIFEST_DIR"); + let params = match fs::read_to_string(format!("{}/{}/{}.param.ron", root, DIR_IN, name)) { Ok(string) => ron::de::from_str(&string).expect("Couldn't find param file"), Err(_) => Parameters::default(), }; @@ -71,41 +50,39 @@ fn check_targets(module: &naga::Module, name: &str, targets: Targets) { .validate(module) .unwrap(); + let dest = PathBuf::from(root).join(DIR_OUT).join(name); + #[cfg(feature = "serialize")] { if targets.contains(Targets::IR) { let config = ron::ser::PrettyConfig::default().with_new_line("\n".to_string()); - let output = ron::ser::to_string_pretty(module, config).unwrap(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}.ron", name), output); - }); + let string = ron::ser::to_string_pretty(module, config).unwrap(); + fs::write(dest.with_extension("ron"), string).unwrap(); } if targets.contains(Targets::ANALYSIS) { let config = ron::ser::PrettyConfig::default().with_new_line("\n".to_string()); - let output = ron::ser::to_string_pretty(&info, config).unwrap(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}.info.ron", name), output); - }); + let string = ron::ser::to_string_pretty(&info, config).unwrap(); + fs::write(dest.with_extension("info.ron"), string).unwrap(); } } #[cfg(feature = "spv-out")] { if targets.contains(Targets::SPIRV) { - check_output_spv(module, &info, name, ¶ms); + check_output_spv(module, &info, &dest, ¶ms); } } #[cfg(feature = "msl-out")] { if targets.contains(Targets::METAL) { - check_output_msl(module, &info, name, ¶ms); + check_output_msl(module, &info, &dest, ¶ms); } } #[cfg(feature = "glsl-out")] { if targets.contains(Targets::GLSL) { for ep in module.entry_points.iter() { - check_output_glsl(module, &info, name, ep.stage, &ep.name); + check_output_glsl(module, &info, &dest, ep.stage, &ep.name, ¶ms); } } } @@ -113,9 +90,19 @@ fn check_targets(module: &naga::Module, name: &str, targets: Targets) { { if targets.contains(Targets::DOT) { let string = naga::back::dot::write(module, Some(&info)).unwrap(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}.dot", name), string); - }); + fs::write(dest.with_extension("dot"), string).unwrap(); + } + } + #[cfg(feature = "hlsl-out")] + { + if targets.contains(Targets::HLSL) { + check_output_hlsl(module, &dest); + } + } + #[cfg(feature = "wgsl-out")] + { + if targets.contains(Targets::WGSL) { + check_output_wgsl(module, &dest); } } } @@ -124,7 +111,7 @@ fn check_targets(module: &naga::Module, name: &str, targets: Targets) { fn check_output_spv( module: &naga::Module, info: &naga::valid::ModuleInfo, - name: &str, + destination: &PathBuf, params: &Parameters, ) { use naga::back::spv; @@ -148,67 +135,56 @@ fn check_output_spv( let dis = rspirv::dr::load_words(spv) .expect("Produced invalid SPIR-V") .disassemble(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}.spvasm", name), dis); - }); + + fs::write(destination.with_extension("spvasm"), dis).unwrap(); } #[cfg(feature = "msl-out")] fn check_output_msl( module: &naga::Module, info: &naga::valid::ModuleInfo, - name: &str, + destination: &PathBuf, params: &Parameters, ) { use naga::back::msl; - let mut binding_map = msl::BindingMap::default(); - for (key, value) in params.mtl_bindings.iter() { - binding_map.insert( - msl::BindSource { - stage: match key.stage { - Stage::Vertex => naga::ShaderStage::Vertex, - Stage::Fragment => naga::ShaderStage::Fragment, - Stage::Compute => naga::ShaderStage::Compute, - }, - group: key.group, - binding: key.binding, - }, - msl::BindTarget { - buffer: value.buffer, - texture: value.texture, - sampler: value.sampler, - mutable: value.mutable, - }, - ); - } - let options = msl::Options { - lang_version: (1, 0), - binding_map, - spirv_cross_compatibility: false, - fake_missing_bindings: false, + #[cfg_attr(feature = "deserialize", allow(unused_variables))] + let default_options = msl::Options::default(); + #[cfg(feature = "deserialize")] + let options = ¶ms.msl; + #[cfg(not(feature = "deserialize"))] + let options = if params.msl_custom { + println!("Skipping {}", destination); + return; + } else { + &default_options + }; + + let pipeline_options = msl::PipelineOptions { allow_point_size: true, }; - let (msl, _) = msl::write_string(module, info, &options).unwrap(); + let (string, _) = msl::write_string(module, info, options, &pipeline_options).unwrap(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}.msl", name), msl); - }); + fs::write(destination.with_extension("msl"), string).unwrap(); } #[cfg(feature = "glsl-out")] fn check_output_glsl( module: &naga::Module, info: &naga::valid::ModuleInfo, - name: &str, + destination: &PathBuf, stage: naga::ShaderStage, ep_name: &str, + params: &Parameters, ) { use naga::back::glsl; let options = glsl::Options { - version: glsl::Version::Embedded(310), + version: match params.glsl_desktop_version { + Some(v) => glsl::Version::Desktop(v), + None => glsl::Version::Embedded(310), + }, shader_stage: stage, entry_point: ep_name.to_string(), }; @@ -219,80 +195,75 @@ fn check_output_glsl( let string = String::from_utf8(buffer).unwrap(); - with_snapshot_settings(|| { - insta::assert_snapshot!(format!("{}-{:?}.glsl", name, stage), string); - }); + let ext = format!("{:?}.glsl", stage); + fs::write(destination.with_extension(&ext), string).unwrap(); } -#[cfg(feature = "wgsl-in")] -fn convert_wgsl(name: &str, targets: Targets) { - let module = naga::front::wgsl::parse_str( - &std::fs::read_to_string(format!("tests/in/{}{}", name, ".wgsl")) - .expect("Couldn't find wgsl file"), - ) - .unwrap(); - check_targets(&module, name, targets); +#[cfg(feature = "hlsl-out")] +fn check_output_hlsl(module: &naga::Module, destination: &PathBuf) { + use naga::back::hlsl; + + let string = hlsl::write_string(module).unwrap(); + + fs::write(destination.with_extension("hlsl"), string).unwrap(); +} + +#[cfg(feature = "wgsl-out")] +fn check_output_wgsl(module: &naga::Module, destination: &PathBuf) { + use naga::back::wgsl; + + let string = wgsl::write_string(module).unwrap(); + + fs::write(destination.with_extension("wgsl"), string).unwrap(); } #[cfg(feature = "wgsl-in")] #[test] -fn convert_wgsl_quad() { - convert_wgsl( - "quad", - Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::DOT, - ); -} +fn convert_wgsl() { + let root = env!("CARGO_MANIFEST_DIR"); + let inputs = [ + ( + "empty", + Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL, + ), + ( + "quad", + Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::DOT, + ), + ("boids", Targets::SPIRV | Targets::METAL), + ("skybox", Targets::SPIRV | Targets::METAL | Targets::GLSL), + ( + "collatz", + Targets::SPIRV | Targets::METAL | Targets::IR | Targets::ANALYSIS, + ), + ("shadow", Targets::SPIRV | Targets::METAL | Targets::GLSL), + //SPIR-V is blocked by https://github.com/gfx-rs/naga/issues/646 + ("image-copy", Targets::METAL), + ("texture-array", Targets::SPIRV | Targets::METAL), + ("operators", Targets::SPIRV | Targets::METAL | Targets::GLSL), + ( + "interpolate", + Targets::SPIRV | Targets::METAL | Targets::GLSL, + ), + ("access", Targets::SPIRV | Targets::METAL), + ]; -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_empty() { - convert_wgsl("empty", Targets::SPIRV | Targets::METAL | Targets::GLSL); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_boids() { - convert_wgsl("boids", Targets::SPIRV | Targets::METAL); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_skybox() { - convert_wgsl("skybox", Targets::SPIRV | Targets::METAL | Targets::GLSL); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_collatz() { - convert_wgsl( - "collatz", - Targets::SPIRV | Targets::METAL | Targets::IR | Targets::ANALYSIS, - ); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_shadow() { - convert_wgsl("shadow", Targets::SPIRV | Targets::METAL | Targets::GLSL); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_image_copy() { - //SPIR-V is blocked by https://github.com/gfx-rs/naga/issues/646 - convert_wgsl("image-copy", Targets::METAL); -} - -#[cfg(feature = "wgsl-in")] -#[test] -fn convert_wgsl_texture_array() { - convert_wgsl("texture-array", Targets::SPIRV); + for &(name, targets) in inputs.iter() { + println!("Processing '{}'", name); + let file = fs::read_to_string(format!("{}/{}/{}.wgsl", root, DIR_IN, name)) + .expect("Couldn't find wgsl file"); + match naga::front::wgsl::parse_str(&file) { + Ok(module) => check_targets(&module, name, targets), + Err(e) => panic!("{}", e), + } + } } #[cfg(feature = "spv-in")] fn convert_spv(name: &str, adjust_coordinate_space: bool, targets: Targets) { + let root = env!("CARGO_MANIFEST_DIR"); let module = naga::front::spv::parse_u8_slice( - &std::fs::read(format!("tests/in/{}{}", name, ".spv")).expect("Couldn't find spv file"), + &fs::read(format!("{}/{}/{}.spv", root, DIR_IN, name)).expect("Couldn't find spv file"), &naga::front::spv::Options { adjust_coordinate_space, flow_graph_dump_prefix: None, @@ -323,8 +294,9 @@ fn convert_glsl( entry_points: naga::FastHashMap, _targets: Targets, ) { + let root = env!("CARGO_MANIFEST_DIR"); let _module = naga::front::glsl::parse_str( - &std::fs::read_to_string(format!("tests/in/{}{}", name, ".glsl")) + &fs::read_to_string(format!("{}/{}/{}.glsl", root, DIR_IN, name)) .expect("Couldn't find glsl file"), &naga::front::glsl::Options { entry_points, diff --git a/third_party/rust/neqo-transport/TODO b/third_party/rust/neqo-transport/TODO old mode 100644 new mode 100755 diff --git a/third_party/rust/num-bigint/ci/rustup.sh b/third_party/rust/num-bigint/ci/rustup.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/num-bigint/ci/test_full.sh b/third_party/rust/num-bigint/ci/test_full.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/num-rational/ci/rustup.sh b/third_party/rust/num-rational/ci/rustup.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/num-rational/ci/test_full.sh b/third_party/rust/num-rational/ci/test_full.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/all.sh b/third_party/rust/packed_simd/ci/all.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/benchmark.sh b/third_party/rust/packed_simd/ci/benchmark.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/dox.sh b/third_party/rust/packed_simd/ci/dox.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/max_line_width.sh b/third_party/rust/packed_simd/ci/max_line_width.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/run-docker.sh b/third_party/rust/packed_simd/ci/run-docker.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/run.sh b/third_party/rust/packed_simd/ci/run.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/setup_benchmarks.sh b/third_party/rust/packed_simd/ci/setup_benchmarks.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/packed_simd/ci/test-runner-linux b/third_party/rust/packed_simd/ci/test-runner-linux old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/LICENSE b/third_party/rust/plane-split/LICENSE old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/README.md b/third_party/rust/plane-split/README.md old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/benches/split.rs b/third_party/rust/plane-split/benches/split.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/rustfmt.toml b/third_party/rust/plane-split/rustfmt.toml old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/src/bsp.rs b/third_party/rust/plane-split/src/bsp.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/src/clip.rs b/third_party/rust/plane-split/src/clip.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/src/lib.rs b/third_party/rust/plane-split/src/lib.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/src/polygon.rs b/third_party/rust/plane-split/src/polygon.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/tests/clip.rs b/third_party/rust/plane-split/tests/clip.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/tests/main.rs b/third_party/rust/plane-split/tests/main.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/plane-split/tests/split.rs b/third_party/rust/plane-split/tests/split.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/png/fuzzit.sh b/third_party/rust/png/fuzzit.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/profiling/examples/puffin/shaders/compile_shaders.sh b/third_party/rust/profiling/examples/puffin/shaders/compile_shaders.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/prost/prepare-release.sh b/third_party/rust/prost/prepare-release.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/prost/publish-release.sh b/third_party/rust/prost/publish-release.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/redox_syscall/src/scheme/generate.sh b/third_party/rust/redox_syscall/src/scheme/generate.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/regex-syntax/test b/third_party/rust/regex-syntax/test old mode 100644 new mode 100755 diff --git a/third_party/rust/regex/test b/third_party/rust/regex/test old mode 100644 new mode 100755 diff --git a/third_party/rust/rkv/run-all-examples.sh b/third_party/rust/rkv/run-all-examples.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/rusqlite/publish-ghp-docs.sh b/third_party/rust/rusqlite/publish-ghp-docs.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/spirv-cross-internal/src/vendor/SPIRV-Cross/.clang-format b/third_party/rust/spirv-cross-internal/src/vendor/SPIRV-Cross/.clang-format old mode 100644 new mode 100755 diff --git a/third_party/rust/strsim/dev b/third_party/rust/strsim/dev old mode 100644 new mode 100755 diff --git a/third_party/rust/target-lexicon/scripts/rust-targets.sh b/third_party/rust/target-lexicon/scripts/rust-targets.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/type-map/README.md b/third_party/rust/type-map/README.md old mode 100644 new mode 100755 diff --git a/third_party/rust/type-map/src/lib.rs b/third_party/rust/type-map/src/lib.rs old mode 100644 new mode 100755 diff --git a/third_party/rust/unicode-normalization/scripts/unicode.py b/third_party/rust/unicode-normalization/scripts/unicode.py old mode 100644 new mode 100755 diff --git a/third_party/rust/unicode-normalization/scripts/unicode_gen_normtests.py b/third_party/rust/unicode-normalization/scripts/unicode_gen_normtests.py old mode 100644 new mode 100755 diff --git a/third_party/rust/unicode-segmentation/scripts/unicode.py b/third_party/rust/unicode-segmentation/scripts/unicode.py old mode 100644 new mode 100755 diff --git a/third_party/rust/unicode-segmentation/scripts/unicode_gen_breaktests.py b/third_party/rust/unicode-segmentation/scripts/unicode_gen_breaktests.py old mode 100644 new mode 100755 diff --git a/third_party/rust/unicode-width/scripts/unicode.py b/third_party/rust/unicode-width/scripts/unicode.py old mode 100644 new mode 100755 diff --git a/third_party/rust/wasmparser/compare-with-main.sh b/third_party/rust/wasmparser/compare-with-main.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/webrtc-sdp/examples/sdps/extract.sh b/third_party/rust/webrtc-sdp/examples/sdps/extract.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/winapi-util/ci/script.sh b/third_party/rust/winapi-util/ci/script.sh old mode 100644 new mode 100755 diff --git a/third_party/rust/yaml-rust/tests/specs/cpp2rust.rb b/third_party/rust/yaml-rust/tests/specs/cpp2rust.rb old mode 100644 new mode 100755