Repository navigation
Releases: recursive-ai-oss/oneshader-csharp
Releases · recursive-ai-oss/oneshader-csharp
Release list
v1.4.0
- Bindless resources. Unbounded resource arrays (
Texture2D Tex[] : register(t0, space1); also samplers, structured, byte-address, constant buffers and read-write textures) and the Shader Model 6.6 heapsResourceDescriptorHeap[i]/SamplerDescriptorHeap[i]compile on SPIR-V and Metal; before, unbounded arrays were error OSH0350. SPIR-V: runtime descriptor arrays withRuntimeDescriptorArrayandSPV_EXT_descriptor_indexing,NonUniformdecorations on the index, the access chain, the loaded descriptor and the data loaded through it, and DXC's default heap mapping (each resource type read from a heap is an unbounded array; the resource heap takes the first unused binding of set 0, the sampler heap the next;CompileOptions.ResourceHeapBinding/SamplerHeapBindingand the CLI's-fvk-bind-resource-heap/-fvk-bind-sampler-heapchoose them). A heap element becomes a resource where it is assigned to a resource variable, cast, or passed to a function; misuse is OSH0336. Metal: each unbounded array or heap is one argument buffer of 8-byte descriptors (a texture's or sampler'sgpuResourceID, a buffer'sgpuAddress) at one buffer index, read throughconstant T_entry*; needs argument buffers tier 2 and Metal 3. WGSL: an error at the declaration or first use (OSH5202), only when WGSL is a selected target. Non-bindless output on every target is unchanged. - Reflection:
ResourceInfo.IsUnbounded(Count0),Heap(DescriptorHeaps) andHeapKinds;EntryPointInfo.DescriptorHeaps;DeviceFeatures.RuntimeDescriptorArray,NonUniformIndexingandMutableDescriptorType(also inEntryLayout/PipelineLayout/PipelineLayoutInfo.RequiredFeatures). The serialized form gets optionalheap/heapkindsattributes and aheapschild; the tool's JSON getsunbounded,heap,heapKinds,descriptorHeapsandrequiredFeatures. OneShader.Layouts:ResourceLayout.IsUnbounded,Heap,HeapKinds.ToVulkangives an unbounded binding a maximum descriptor count (VulkanLayoutOptions.UnboundedMaxCount, default 4096, per bindingUnboundedCounts),PartiallyBoundand, on the highest binding of a set,VariableDescriptorCount(optionsPartiallyBound,VariableDescriptorCount,UpdateAfterBind;DescriptorSetLayoutBindingInfo.BindingFlags,DescriptorSetLayoutInfo.CreateFlags), and a heap read as several kinds aMutabledescriptor withMutableTypes.DescriptorSetLayoutInfo.HasVariableCounttells which sets need the variable-count allocation info.TryToMetalreportsMetalArgument.IsArgumentBuffer,DescriptorStride8,ElementKinds,Encoding.TryToWebGpureturns aLayoutError.- Generated bindings:
Bindings.<Name>.IsUnbounded(andHeapfor a heap),ResourceBinding.IsUnbounded; the generatedLayoutcarries the heap data; variants work. - The corpus gains
bindless_textures,bindless_buffersandbindless_heap; the parity harness creates partially bound, update-after-bind, variable-count and mutable descriptor bindings, and the Metal runner executes argument-buffer cases. PipelineLayout.ToBindingsdescribes unbounded arrays and heaps:BindingDescription.Countis 0 withIsUnbounded,HeapandHeapKindsfor a descriptor heap,PartiallyBound(true for every unbounded binding) andHasVariableCount(the highest binding of its set). Union layouts merge equal unbounded slots and refuse an unbounded slot against a sized one.- A scalar texel offset on a 2D or 3D texture (
Sample(s, uv, 1)) applies to every axis, as in DXC; before, it produced invalid SPIR-V.
v1.3.0
- Pipeline layout helpers, additions only.
UnionOptionsforPipelineLayout.TryCreateUnion(entries, options, ...):IgnoreTextureDimensionlets a 2D and a cube texture share a slot,MergeStorageAccessmerges read-only and read-write buffers of one family to read-write.WebGpuLayoutOptions.TextureDimensionspicks theviewDimensionof such a slot (without a pickTryToWebGpureports it as unsupported, and it refuses a merged read-only/read-write buffer unlessReadOnlyStorageBuffersnames it).PipelineLayout.ToBindings(BindingOptions?)returns target-neutralBindingDescriptions (BindingType,TextureDimension,TextureSampleKind, comparison flag, count, stages, dynamic flag, Metal index).VertexLayout.TrySplit(streams, ..., overrides)spreads a vertex input over several buffers with per-vertex or per-instance step (VertexStream,VertexStreamLayout.ToVulkan/ToMetal/ToWebGpu); overlapping attributes, a too-small stride and a location in no stream areLayoutErrors. - Source-level debug information.
CompileOptions.DebugInfo(DebugInfoLevel.Noneby default;Lines,Full) andDebugSourceRoot. SPIR-V:LineswritesOpSource(with the text of the main and each included file) andOpLine/OpNoLine, as DXC's-Zi;FullwritesNonSemantic.Shader.DebugInfo.100(compilation unit, oneDebugSourceper file, functions, lexical blocks, inlined-at records, local variables withDebugDeclare/DebugValue, global variables, types, lines, entry point), as DXC's-fspv-debug=vulkan-with-source, for RenderDoc and Nsight. MSL:#linedirectives for Metal's-gline-tables-only -frecord-sourcesand Xcode. WGSL is unchanged. Paths in the output are relative toDebugSourceRootand never absolute. Off by default, and then every blob is byte-identical to before. The optimizer keeps running with debug information on and keeps positions through every pass;Optimize = falsegives one step per statement with every local visible. Command line:-Zi,-fspv-debug=vulkan-with-source(alsovulkan,file,source,line,tool),--debug-root. Build package:OneShaderDebugInfo(true/full/lines/false) andOneShaderOptimize, item metadataDebugInfoandOptimize. See docs/debugging.md.
v1.2.0
- 16-bit and 64-bit types. With
CompileOptions.Enable16BitTypes(DXC's-enable-16bit-types; MSBuildOneShaderEnable16BitTypes, item metadataEnable16BitTypes, CLI-enable-16bit-types)half,min16float,min10float,min16int,min16uintandfloat16_t/int16_t/uint16_t(vectors and matrices) are native 16-bit types, in arithmetic and in buffers with DXC's byte layout; without it the 16-bit names other thanhalf/min*are error OSH0360, and the min-precision types are 32-bit values marked RelaxedPrecision on SPIR-V, as DXC does.double,int64_tanduint64_twork on SPIR-V in arithmetic, buffers,asdouble,asuint(double, lo, hi)and 64-bitInterlocked*on structured buffers and group-shared memory. A double argument to a float-only intrinsic (floor,sqrt, ...) is narrowed to float as DXC does, with the new warning OSH0361. Unsuffixed float literals keep double precision until they meet a concrete type. Constant folding is exact at each width. - MSL: native
half,short,ushort,longandulong;double, 64-bit integer vectors in buffers and 64-bit atomics other than unsignedInterlockedMax/InterlockedMinwithout a used result (the only form Metal 2.4 has) are errors at the first use (OSH5102) that say what to change. WGSL:halfisf16withenable f16;(16-bit values in buffers are read and written as halves of 32-bit words; stores use atomic and/or on the word so neighbours written by other invocations are not disturbed); 16-bit integers,doubleand 64-bit integers are errors at the first use (OSH5202). A refusal is an error only when that target is selected. - Reflection:
EntryPointInfo.RequiredFeatures(DeviceFeatures:Float16,Int16,Float64,Int64,StorageBuffer16,UniformBuffer16,PushConstant16,InputOutput16,Int64Atomics; the serializedentryrecord gets an optionalfeatureschild).EntryLayout.RequiredFeaturesandPipelineLayout.RequiredFeatures;PipelineLayoutInfo.RequiredFeatures(the Vulkan device features to enable);WebGpuPipelineLayout.RequiredFeatureslistsshader-f16. Generated entry classes get aRequiredFeaturesconstant besideSubgroupOperations, and the generatedLayoutcarries it. - Default vertex formats for 16-bit inputs:
Float16x2/Float16x4,Sint16x2/Sint16x4,Uint16x2/Uint16x4. - Pipeline layout helpers (
OneShader.Layouts), additions only.PipelineLayout.TryCreateUnionbuilds one layout for any number of entry points, several per stage; resources at one slot that agree merge with united stages, disagreements are aLayoutErrornaming both entry points and the slot, and push-constant blocks merge into one covering range when their overlapping members agree (EntryLayout.PushConstantType,WithPushConstantType). Entry points compiled from different files that disagree on a Metal index or WebGPU push slot are reported byTryToMetal/TryToWebGpu.VulkanLayoutOptionsandWebGpuLayoutOptionsgain stage widening (WidenSets/WidenGroups,WidenBindings,WidenPushConstants) and dynamic offsets by slot (DynamicBindings; WebGPU alsoDynamicBuffers);ResourceLayout.DynamicOffset,DescriptorSetLayoutBindingInfo.IsDynamicandBindGroupLayoutEntryInfo.HasDynamicOffsetexpose the flag.EntryLayout.TryWithVertexOverrides/VertexLayout.TryWithOverridesapply the host's stride, and per-location format and offset, checked against the shader's input type (LayoutErrorKind.InvalidVertexInput); Vulkan, Metal and WebGPU vertex descriptions follow.TryToMetalalso reports two resources of one stage that take the same Metal index. - Specialization constants.
[[vk::constant_id(N)]] const <bool|int|uint|float> Name = <default>;becomes each target's pipeline-time constant, so one compiled shader serves many variants without recompiling. SPIR-V:OpSpecConstant/OpSpecConstantTrue/FalsewithSpecId N, the ids DXC writes for the same source. MSL:constant T Name [[function_constant(N)]], read throughis_function_constant_definedwith the default as the fallback. WGSL:@id(N) override Name: T = default;. Optimization never folds a specialization constant to its default; code derived from one (includingstatic constinitializers) is ordinary code that runs per pipeline. Mistakes are errors at the HLSL line: a duplicate id, a vector or struct type,static, a missing or non-constant default, a negative id (OSH0335); an array size,[numthreads]argument orcaselabel that uses one says why it is refused (OSH0310), as DXC refuses the same uses. - Reflection:
ShaderReflection.SpecConstants(SpecConstantInfo: name, id, scalar type, default bits and value, aSpecConstantSlotper target with the SPIR-VSpecId, the Metal function-constant index and variable, the WGSL@idand override name) andEntryPointInfo.UsedSpecConstants. The serialized form getsspecandspecuserecords, written only for shaders that have constants; the command-line tool's JSON getsspecConstantsandusedSpecConstantslikewise.InterfaceCompatibilityreports a removed constant or a changed id or type (InterfaceDifferenceKind.SpecConstant); new constants and changed defaults stay compatible. OneShader.Layouts:SpecializationValues(fromEntryLayout.SpecConstants; typedSet, plain data) converts to VulkanVkSpecializationInfocontents (Layouts.Vulkan.SpecializationInfo: map entries and the data block), Metal function-constant values (Layouts.Metal.FunctionConstantValue: index,MTLDataTypenumber, bits) and the WebGPUconstantsrecord keyed by decimal id.EntryLayoutgetsSpecConstants.- Generated code:
SpecializationConstants.<Name>.Id/Defaultconstants, a blittableSpecializationstruct (one 4-byte field per constant,Defaults,ToVulkan/ToMetal/ToWebGpu) andSpecConstantIdson every entry-point class that reads constants; the entry'sLayoutcarries them. In a variant file each variant class has its ownSpecializationConstantsandSpecialization(a constant may exist in only some variants), and the aggregate entry class hasSpecConstantIdsfor the variant it was looked up in. CompileOptions.SpecializationOverridesfixes chosen constants at compile time: they become plain constants, get folded, and leave reflection. A value that does not fit the type is error OSH0335; an unknown name is warning OSH0335.- Metal note: a function that declares function constants cannot build a pipeline state as it is, even when every default is wanted; create it with
makeFunction(name:constantValues:)(an emptyMTLFunctionConstantValuesselects the defaults). - Shader variants in the build package. A
OneShaderitem takesAxes="ALPHA_TEST;LIGHTING=NONE|LAMBERT|PBR"(flags and choices; the cartesian product is compiled), orOneShaderVariantitems name hand-picked define sets. One compile per variant per selected target, in parallel; only variants whose define set, shader, includes or options changed are recompiled. More than 64 variants is error OSH0905 (raise it withMaxVariants/OneShaderMaxVariants); malformed declarations are OSH0904 and OSH0906. An error that happens under some variants is reported once on the HLSL line with the define set ((variant ALPHA_TEST=1, LIGHTING=PBR)). - Generated code for a file with variants:
Key(one property per axis, enums for choices),Variants.Get(key)returning aVariantwith anEntryper entry point (SpirV,Msl,Wgsl,Layout, ...),BindingsandPipelineper variant, and a static class per variant shaped like a single file's class. Constant-buffer, push-constant and vertex structs are generated once when all variants agree on the layout, per variant when they differ. Files without variants generate exactly the same C# as before. Seedocs/generated-bindings.md. - A file listed explicitly as a
OneShaderitem (to give it metadata) is no longer added a second time by the default**/*.hlslglob. ShaderCompileCache(RecursiveAI.OneShader): thread-safe, bounded compile cache keyed by source, path, options and the content of the includes the compile read; concurrent calls for one key compile once;Clear()empties it.- The build task logs
OneShader: N compiled, M up to date.at low importance (-v:d).
v1.1.0
- New package
RecursiveAI.OneShader.Tool: theoneshadercommand-line compiler (a .NET tool, and a NativeAOT single-file binary withdotnet publish -r <rid>). It takes DXC's core flags (-T,-E,-D,-I,-Fo,-spirv,-O0..-O3,-Zpr/-Zpc,-HV 2021,-WX) plus--target spirv|msl|wgsl(repeatable),--all-entries,--reflect <file.json>and--depfile <file>. Diagnostics print asfile(line,col): error OSHnnnn: message; exit code 0, 1 for compile errors, 2 for command-line errors. - Pipeline layout helpers (
OneShader.Layouts): plain data, no graphics API behind it, that turns a shader into what a renderer creates.EntryLayout(from reflection withEntryLayout.TryCreate, or the generatedSprite.VSMain.Layout) andPipelineLayout.TryCreatemerge entry points into bind groups with combined stage visibility and push-constant blocks, returning conflicts as aLayoutErrorvalue.ToVulkan()gives descriptor set layouts, push-constant ranges and vertex input with numericVkDescriptorType/VkShaderStageFlagBits/VkFormatvalues;TryToMetal()gives per-stage buffer, texture and sampler indices, thesetBytesslot andMTLVertexDescriptordata;TryToWebGpu()gives bind group layout entries with the WebGPU enum strings, push constants as a uniform buffer at the reserved group and binding, and vertex buffer layouts. Generated classes gainLayouton every entry point andPipeline(vertex + pixel, or one compute entry point) on the file. - Wave (subgroup) and quad intrinsics on all three targets:
WaveGetLaneCount/Index,WaveIsFirstLane,WaveActiveAnyTrue/AllTrue/AllEqual/Ballot/Sum/Product/Min/Max/BitAnd/BitOr/BitXor/CountBits,WavePrefixSum/Product/CountBits,WaveReadLaneAt/FirstandQuadReadAcrossX/Y/Diagonal/QuadReadLaneAton 32-bit int, uint and float scalars and vectors. SPIR-V usesGroupNonUniform*as DXC does, MSLsimd_*/quad_*, WGSL thesubgroupsfeature (enable subgroups;; not in vertex shaders).WaveMatchandWaveMultiPrefix*are an error (OSH0350). Reflection gainsEntryPointInfo.SubgroupOperations(Vulkan'sVkSubgroupFeatureFlagBitsvalues),EntryPointInfo.UsesSubgroupsandShaderReflection.UsesSubgroups;EntryLayout/PipelineLayout/PipelineLayoutInfo/MetalPipelineLayoutcarrySubgroupOperations,WebGpuPipelineLayout.RequiredFeatureslistssubgroups, and generated entry classes get aSubgroupOperationsconstant.BuiltIngainsSubgroupLocalInvocationIdandSubgroupSize. - Reflection:
ResourceInfo.ImageFormatrecords the[[vk::image_format]]name of a storage texture (the serializedresourcerecord gets an optionalformatattribute, written only when set).
v1.0.0
First stable release. The public API (ShaderCompiler, CompileOptions, CompileResult, reflection, InterfaceCompatibility) and the generated C# shape are now covered by Semantic Versioning.
- Vertex, pixel and compute shaders in modern HLSL (HLSL 2021 templates included) compile to optimized SPIR-V for Vulkan 1.2, Metal Shading Language and WGSL, each with reflection; the build package compiles
*.hlslduringdotnet build, reports errors on the HLSL line, embeds the selected targets (OneShaderTargets) and generates C# structs and binding code. - Since 0.4: the packages are built with deterministic paths, embedded untracked sources and a symbol package (
.snupkg); package metadata links to the public repository; the four-platform CI (Windows x64, Linux x64 and arm64, macOS arm64) runs the compiler tests, the build-package tests and the NativeAOT smoke app, and runs the reference-tool tests (DXC,spirv-val, naga) wherever those tools are released. - Tested: the five fuzz targets (preprocessor, front end, IR and optimizer, every backend) ran clean for 600 s each, and the corpus is checked with
spirv-val, by running it on GPUs against DXC's output, with naga, with Apple'smetalcompiler and on WebGPU.