/// <summary> /// Creates a compute shader from the given <see cref="ShaderDescription"/> containing SPIR-V bytecode or GLSL source /// code. /// </summary> /// <param name="factory">The <see cref="ResourceFactory"/> used to compile the translated shader code.</param> /// <param name="computeShaderDescription">The compute shader's description. /// <see cref="ShaderDescription.ShaderBytes"/> should contain SPIR-V bytecode or Vulkan-style GLSL source code which /// can be compiled to SPIR-V.</param> /// <param name="options">The <see cref="CrossCompileOptions"/> which will control the parameters used to translate the /// shaders from SPIR-V to the target language.</param> /// <returns>The compiled compute <see cref="Shader"/>.</returns> public static Shader CreateFromSpirv( this ResourceFactory factory, ShaderDescription computeShaderDescription, CrossCompileOptions options) { GraphicsBackend backend = factory.BackendType; if (backend == GraphicsBackend.Vulkan) { computeShaderDescription.ShaderBytes = EnsureSpirv(computeShaderDescription); return(factory.CreateShader(ref computeShaderDescription)); } CrossCompileTarget target = GetCompilationTarget(factory.BackendType); ComputeCompilationResult compilationResult = SpirvCompilation.CompileCompute( computeShaderDescription.ShaderBytes, target, options); string computeEntryPoint = (backend == GraphicsBackend.Metal && computeShaderDescription.EntryPoint == "main") ? "main0" : computeShaderDescription.EntryPoint; byte[] computeBytes = GetBytes(backend, compilationResult.ComputeShader); return(factory.CreateShader(new ShaderDescription( computeShaderDescription.Stage, computeBytes, computeEntryPoint))); }
public void ComputeSucceeds(string cs, CrossCompileTarget target) { byte[] csBytes = TestUtil.LoadBytes(cs); ComputeCompilationResult result = SpirvCompilation.CompileCompute(csBytes, target); Assert.NotNull(result.ComputeShader); }
public void CompilationFails(string vs, string fs, CrossCompileTarget target) { byte[] vsBytes = TestUtil.LoadBytes(vs); byte[] fsBytes = TestUtil.LoadBytes(fs); Assert.Throws <SpirvCompilationException>(() => SpirvCompilation.CompileVertexFragment( vsBytes, fsBytes, target, new CrossCompileOptions(false, false))); }
/// <summary> /// Creates a vertex and fragment shader pair from the given <see cref="ShaderDescription"/> pair containing SPIR-V /// bytecode or GLSL source code. /// </summary> /// <param name="factory">The <see cref="ResourceFactory"/> used to compile the translated shader code.</param> /// <param name="vertexShaderDescription">The vertex shader's description. <see cref="ShaderDescription.ShaderBytes"/> /// should contain SPIR-V bytecode or Vulkan-style GLSL source code which can be compiled to SPIR-V.</param> /// <param name="fragmentShaderDescription">The fragment shader's description. /// <see cref="ShaderDescription.ShaderBytes"/> should contain SPIR-V bytecode or Vulkan-style GLSL source code which /// can be compiled to SPIR-V.</param> /// <param name="options">The <see cref="CrossCompileOptions"/> which will control the parameters used to translate the /// shaders from SPIR-V to the target language.</param> /// <returns>A two-element array, containing the vertex shader (element 0) and the fragment shader (element 1).</returns> public static Shader[] CreateFromSpirv( this ResourceFactory factory, ShaderDescription vertexShaderDescription, ShaderDescription fragmentShaderDescription, CrossCompileOptions options) { GraphicsBackend backend = factory.BackendType; if (backend == GraphicsBackend.Vulkan) { vertexShaderDescription.ShaderBytes = EnsureSpirv(vertexShaderDescription); fragmentShaderDescription.ShaderBytes = EnsureSpirv(fragmentShaderDescription); return(new Shader[] { factory.CreateShader(ref vertexShaderDescription), factory.CreateShader(ref fragmentShaderDescription) }); } CrossCompileTarget target = GetCompilationTarget(factory.BackendType); VertexFragmentCompilationResult compilationResult = SpirvCompilation.CompileVertexFragment( vertexShaderDescription.ShaderBytes, fragmentShaderDescription.ShaderBytes, target, options); string vertexEntryPoint = (backend == GraphicsBackend.Metal && vertexShaderDescription.EntryPoint == "main") ? "main0" : vertexShaderDescription.EntryPoint; byte[] vertexBytes = GetBytes(backend, compilationResult.VertexShader); Shader vertexShader = factory.CreateShader(new ShaderDescription( vertexShaderDescription.Stage, vertexBytes, vertexEntryPoint)); string fragmentEntryPoint = (backend == GraphicsBackend.Metal && fragmentShaderDescription.EntryPoint == "main") ? "main0" : fragmentShaderDescription.EntryPoint; byte[] fragmentBytes = GetBytes(backend, compilationResult.FragmentShader); Shader fragmentShader = factory.CreateShader(new ShaderDescription( fragmentShaderDescription.Stage, fragmentBytes, fragmentEntryPoint)); return(new Shader[] { vertexShader, fragmentShader }); }
public void VertexFragmentSucceeds(string vs, string fs, CrossCompileTarget target) { byte[] vsBytes = TestUtil.LoadBytes(vs); byte[] fsBytes = TestUtil.LoadBytes(fs); SpecializationConstant[] specializations = { new SpecializationConstant(100, 125u), new SpecializationConstant(101, true), new SpecializationConstant(102, 0.75f), }; VertexFragmentCompilationResult result = SpirvCompilation.CompileVertexFragment( vsBytes, fsBytes, target, new CrossCompileOptions(false, false, specializations)); Assert.NotNull(result.VertexShader); Assert.NotNull(result.FragmentShader); }
private string GetExtension(CrossCompileTarget target) { switch (target) { case CrossCompileTarget.HLSL: return("hlsl"); case CrossCompileTarget.GLSL: return("glsl"); case CrossCompileTarget.ESSL: return("essl"); case CrossCompileTarget.MSL: return("metal"); default: throw new SpirvCompilationException($"Invalid CrossCompileTarget: {target}"); } }
/// <summary> /// Cross-compiles the given vertex-fragment pair into some target language. /// </summary> /// <param name="vsBytes">The vertex shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="fsBytes">The fragment shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="target">The target language.</param> /// <param name="options">The options for shader translation.</param> /// <returns>A <see cref="VertexFragmentCompilationResult"/> containing the compiled output.</returns> public static unsafe VertexFragmentCompilationResult CompileVertexFragment( byte[] vsBytes, byte[] fsBytes, CrossCompileTarget target, CrossCompileOptions options) { int size1 = sizeof(CrossCompileInfo); int size2 = sizeof(InteropArray); byte[] vsSpirvBytes; byte[] fsSpirvBytes; if (Util.HasSpirvHeader(vsBytes)) { vsSpirvBytes = vsBytes; } else { fixed(byte *sourceTextPtr = vsBytes) { SpirvCompilationResult vsCompileResult = CompileGlslToSpirv( (uint)vsBytes.Length, sourceTextPtr, string.Empty, ShaderStages.Vertex, target == CrossCompileTarget.GLSL || target == CrossCompileTarget.ESSL, 0, null); vsSpirvBytes = vsCompileResult.SpirvBytes; } } if (Util.HasSpirvHeader(fsBytes)) { fsSpirvBytes = fsBytes; } else { fixed(byte *sourceTextPtr = fsBytes) { SpirvCompilationResult fsCompileResult = CompileGlslToSpirv( (uint)fsBytes.Length, sourceTextPtr, string.Empty, ShaderStages.Fragment, target == CrossCompileTarget.GLSL || target == CrossCompileTarget.ESSL, 0, null); fsSpirvBytes = fsCompileResult.SpirvBytes; } } int specConstantsCount = options.Specializations.Length; NativeSpecializationConstant *nativeSpecConstants = stackalloc NativeSpecializationConstant[specConstantsCount]; for (int i = 0; i < specConstantsCount; i++) { nativeSpecConstants[i].ID = options.Specializations[i].ID; nativeSpecConstants[i].Constant = options.Specializations[i].Data; } CrossCompileInfo info; info.Target = target; info.FixClipSpaceZ = options.FixClipSpaceZ; info.InvertY = options.InvertVertexOutputY; info.NormalizeResourceNames = options.NormalizeResourceNames; fixed(byte *vsBytesPtr = vsSpirvBytes) fixed(byte *fsBytesPtr = fsSpirvBytes) { info.VertexShader = new InteropArray((uint)vsSpirvBytes.Length / 4, vsBytesPtr); info.FragmentShader = new InteropArray((uint)fsSpirvBytes.Length / 4, fsBytesPtr); info.Specializations = new InteropArray((uint)specConstantsCount, nativeSpecConstants); CompilationResult *result = null; try { result = VeldridSpirvNative.CrossCompile(&info); if (!result->Succeeded) { throw new SpirvCompilationException( "Compilation failed: " + Util.GetString((byte *)result->GetData(0), result->GetLength(0))); } string vsCode = Util.GetString((byte *)result->GetData(0), result->GetLength(0)); string fsCode = Util.GetString((byte *)result->GetData(1), result->GetLength(1)); ReflectionInfo *reflInfo = &result->ReflectionInfo; VertexElementDescription[] vertexElements = new VertexElementDescription[reflInfo->VertexElements.Count]; for (uint i = 0; i < reflInfo->VertexElements.Count; i++) { ref NativeVertexElementDescription nativeDesc = ref reflInfo->VertexElements.Ref <NativeVertexElementDescription>(i); vertexElements[i] = new VertexElementDescription( Util.GetString((byte *)nativeDesc.Name.Data, nativeDesc.Name.Count), nativeDesc.Semantic, nativeDesc.Format, nativeDesc.Offset); } ResourceLayoutDescription[] layouts = new ResourceLayoutDescription[reflInfo->ResourceLayouts.Count]; for (uint i = 0; i < reflInfo->ResourceLayouts.Count; i++) { ref NativeResourceLayoutDescription nativeDesc = ref reflInfo->ResourceLayouts.Ref <NativeResourceLayoutDescription>(i); layouts[i].Elements = new ResourceLayoutElementDescription[nativeDesc.ResourceElements.Count]; for (uint j = 0; j < nativeDesc.ResourceElements.Count; j++) { ref NativeResourceElementDescription elemDesc = ref nativeDesc.ResourceElements.Ref <NativeResourceElementDescription>(j); layouts[i].Elements[j] = new ResourceLayoutElementDescription( Util.GetString((byte *)elemDesc.Name.Data, elemDesc.Name.Count), elemDesc.Kind, elemDesc.Stages, elemDesc.Options); } }
/// <summary> /// Cross-compiles the given vertex-fragment pair into some target language. /// </summary> /// <param name="vsBytes">The vertex shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="fsBytes">The fragment shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="target">The target language.</param> /// <returns>A <see cref="VertexFragmentCompilationResult"/> containing the compiled output.</returns> public static unsafe VertexFragmentCompilationResult CompileVertexFragment( byte[] vsBytes, byte[] fsBytes, CrossCompileTarget target) => CompileVertexFragment(vsBytes, fsBytes, target, new CrossCompileOptions());
/// <summary> /// Cross-compiles the given vertex-fragment pair into some target language. /// </summary> /// <param name="vsBytes">The vertex shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="fsBytes">The fragment shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="target">The target language.</param> /// <param name="options">The options for shader translation.</param> /// <returns>A <see cref="VertexFragmentCompilationResult"/> containing the compiled output.</returns> public static unsafe VertexFragmentCompilationResult CompileVertexFragment( byte[] vsBytes, byte[] fsBytes, CrossCompileTarget target, CrossCompileOptions options) { int size1 = sizeof(CrossCompileInfo); int size2 = sizeof(InteropArray); byte[] vsSpirvBytes; byte[] fsSpirvBytes; if (Util.HasSpirvHeader(vsBytes)) { vsSpirvBytes = vsBytes; } else { fixed(byte *sourceTextPtr = vsBytes) { SpirvCompilationResult vsCompileResult = CompileGlslToSpirv( (uint)vsBytes.Length, sourceTextPtr, string.Empty, ShaderStages.Vertex, target == CrossCompileTarget.GLSL || target == CrossCompileTarget.ESSL, 0, null); vsSpirvBytes = vsCompileResult.SpirvBytes; } } if (Util.HasSpirvHeader(fsBytes)) { fsSpirvBytes = fsBytes; } else { fixed(byte *sourceTextPtr = fsBytes) { SpirvCompilationResult fsCompileResult = CompileGlslToSpirv( (uint)fsBytes.Length, sourceTextPtr, string.Empty, ShaderStages.Fragment, target == CrossCompileTarget.GLSL || target == CrossCompileTarget.ESSL, 0, null); fsSpirvBytes = fsCompileResult.SpirvBytes; } } int specConstantsCount = options.Specializations.Length; NativeSpecializationConstant *nativeSpecConstants = stackalloc NativeSpecializationConstant[specConstantsCount]; for (int i = 0; i < specConstantsCount; i++) { nativeSpecConstants[i].ID = options.Specializations[i].ID; nativeSpecConstants[i].Constant = options.Specializations[i].Data; } CrossCompileInfo info; info.Target = target; info.FixClipSpaceZ = options.FixClipSpaceZ; info.InvertY = options.InvertVertexOutputY; fixed(byte *vsBytesPtr = vsSpirvBytes) fixed(byte *fsBytesPtr = fsSpirvBytes) { info.VertexShader = new InteropArray((uint)vsSpirvBytes.Length / 4, vsBytesPtr); info.FragmentShader = new InteropArray((uint)fsSpirvBytes.Length / 4, fsBytesPtr); info.Specializations = new InteropArray((uint)specConstantsCount, nativeSpecConstants); CompilationResult *result = null; try { result = VeldridSpirvNative.CrossCompile(&info); if (!result->Succeeded) { throw new SpirvCompilationException( "Compilation failed: " + Util.GetString((byte *)result->GetData(0), result->GetLength(0))); } string vsCode = Util.GetString((byte *)result->GetData(0), result->GetLength(0)); string fsCode = Util.GetString((byte *)result->GetData(1), result->GetLength(1)); return(new VertexFragmentCompilationResult(vsCode, fsCode)); } finally { if (result != null) { VeldridSpirvNative.FreeResult(result); } } } }
/// <summary> /// Cross-compiles the given vertex-fragment pair into some target language. /// </summary> /// <param name="csBytes">The compute shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="target">The target language.</param> /// <param name="options">The options for shader translation.</param> /// <returns>A <see cref="ComputeCompilationResult"/> containing the compiled output.</returns> public static unsafe ComputeCompilationResult CompileCompute( byte[] csBytes, CrossCompileTarget target, CrossCompileOptions options) { byte[] csSpirvBytes; if (Util.HasSpirvHeader(csBytes)) { csSpirvBytes = csBytes; } else { fixed(byte *sourceTextPtr = csBytes) { SpirvCompilationResult vsCompileResult = CompileGlslToSpirv( (uint)csBytes.Length, sourceTextPtr, string.Empty, ShaderStages.Compute, target == CrossCompileTarget.GLSL || target == CrossCompileTarget.ESSL, 0, null); csSpirvBytes = vsCompileResult.SpirvBytes; } } CrossCompileInfo info; info.Target = target; info.FixClipSpaceZ = options.FixClipSpaceZ; info.InvertY = options.InvertVertexOutputY; fixed(byte *csBytesPtr = csSpirvBytes) fixed(SpecializationConstant * specConstants = options.Specializations) { info.ComputeShader = new InteropArray((uint)csSpirvBytes.Length / 4, csBytesPtr); info.Specializations = new InteropArray((uint)options.Specializations.Length, specConstants); CompilationResult *result = null; try { result = VeldridSpirvNative.CrossCompile(&info); if (!result->Succeeded) { throw new SpirvCompilationException( "Compilation failed: " + Util.GetString((byte *)result->GetData(0), result->GetLength(0))); } string csCode = Util.GetString((byte *)result->GetData(0), result->GetLength(0)); return(new ComputeCompilationResult(csCode)); } finally { if (result != null) { VeldridSpirvNative.FreeResult(result); } } } }
/// <summary> /// Cross-compiles the given vertex-fragment pair into some target language. /// </summary> /// <param name="csBytes">The compute shader's SPIR-V bytecode or ASCII-encoded GLSL source code.</param> /// <param name="target">The target language.</param> /// <returns>A <see cref="ComputeCompilationResult"/> containing the compiled output.</returns> public static unsafe ComputeCompilationResult CompileCompute( byte[] csBytes, CrossCompileTarget target) => CompileCompute(csBytes, target, new CrossCompileOptions());
public static VertexFragmentCompilationResult DecompileBytecode(byte[] vertexShader, byte[] fragmentShader, CrossCompileTarget target = CrossCompileTarget.GLSL) { return(SpirvCompilation.CompileVertexFragment(vertexShader, fragmentShader, target)); }