/// <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 }); }
private string[] CompileVertexFragment(ShaderVariantDescription variant) { List <string> generatedFiles = new List <string>(); List <Exception> compilationExceptions = new List <Exception>(); byte[] vsBytes = null; byte[] fsBytes = null; string vertexFileName = variant.Shaders.FirstOrDefault(vsd => vsd.Stage == ShaderStages.Vertex)?.FileName; if (vertexFileName != null) { try { vsBytes = CompileToSpirv(variant, vertexFileName, ShaderStages.Vertex); //string spvPath = Path.Combine(_outputPath, $"{variant.Name}_{ShaderStages.Vertex.ToString()}.spv"); string spvPath = Path.Combine(_outputPath, $"{variant.Name}.vert.spv"); File.WriteAllBytes(spvPath, vsBytes); generatedFiles.Add(spvPath); } catch (Exception e) { compilationExceptions.Add(e); } } string fragmentFileName = variant.Shaders.FirstOrDefault(vsd => vsd.Stage == ShaderStages.Fragment)?.FileName; if (fragmentFileName != null) { try { fsBytes = CompileToSpirv(variant, fragmentFileName, ShaderStages.Fragment); //string spvPath = Path.Combine(_outputPath, $"{variant.Name}_{ShaderStages.Fragment.ToString()}.spv"); string spvPath = Path.Combine(_outputPath, $"{variant.Name}.frag.spv"); File.WriteAllBytes(spvPath, fsBytes); generatedFiles.Add(spvPath); } catch (Exception e) { compilationExceptions.Add(e); } } if (compilationExceptions.Count > 0) { throw new AggregateException( $"Errors were encountered when compiling from GLSL to SPIR-V.", compilationExceptions); } foreach (CrossCompileTarget target in variant.Targets) { try { bool writeReflectionFile = true; VertexFragmentCompilationResult result = SpirvCompilation.CompileVertexFragment( vsBytes, fsBytes, target, variant.CrossCompileOptions); if (result.VertexShader != null) { string vsPath = Path.Combine(_outputPath, $"{variant.Name}_Vertex.{GetExtension(target)}"); File.WriteAllText(vsPath, result.VertexShader); generatedFiles.Add(vsPath); } if (result.FragmentShader != null) { string fsPath = Path.Combine(_outputPath, $"{variant.Name}_Fragment.{GetExtension(target)}"); File.WriteAllText(fsPath, result.FragmentShader); generatedFiles.Add(fsPath); } if (writeReflectionFile) { writeReflectionFile = false; string reflectionPath = Path.Combine(_outputPath, $"{variant.Name}_ReflectionInfo.json"); JsonSerializer serializer = new JsonSerializer(); serializer.Formatting = Formatting.Indented; StringEnumConverter enumConverter = new StringEnumConverter(); serializer.Converters.Add(enumConverter); using (StreamWriter sw = File.CreateText(reflectionPath)) using (JsonTextWriter jtw = new JsonTextWriter(sw)) { serializer.Serialize(jtw, result.Reflection); } generatedFiles.Add(reflectionPath); } } catch (Exception e) { compilationExceptions.Add(e); } } if (compilationExceptions.Count > 0) { throw new AggregateException($"Errors were encountered when compiling shader variant(s).", compilationExceptions); } return(generatedFiles.ToArray()); }