/// <summary> /// Loads the bytecode from an input D2D1 pixel shader. /// </summary> /// <typeparam name="T">The type of D2D1 pixel shader to load the bytecode for.</typeparam> /// <param name="shaderProfile">The shader profile to use to get the shader bytecode.</param> /// <param name="options"> /// <para>The compile options to use to get the shader bytecode.</para> /// <para>For consistency with <see cref="D2DCompileOptionsAttribute"/>, <see cref="D2D1CompileOptions.PackMatrixRowMajor"/> will be automatically added.</para> /// </param> /// <returns>A <see cref="ReadOnlyMemory{T}"/> instance with the resulting shader bytecode.</returns> /// <exception cref="ArgumentException">Thrown if <see cref="D2D1CompileOptions.PackMatrixColumnMajor"/> is specified within <paramref name="options"/>.</exception> /// <remarks> /// If the input shader was precompiled, the returned <see cref="ReadOnlyMemory{T}"/> instance will wrap a pinned memory buffer (from the PE section). /// If the shader was compiled at runtime, the returned <see cref="ReadOnlyMemory{T}"/> instance will wrap a <see cref="byte"/> array with the bytecode. /// </remarks> public static ReadOnlyMemory <byte> LoadBytecode <T>(D2D1ShaderProfile shaderProfile, D2D1CompileOptions options) where T : unmanaged, ID2D1PixelShader { if ((options & D2D1CompileOptions.PackMatrixColumnMajor) != 0) { ThrowHelper.ThrowArgumentException(nameof(options), "The PackMatrixColumnMajor compile options is not compatible with ComputeSharp.D2D1 shaders."); } return(LoadOrCompileBytecode <T>(shaderProfile, options | D2D1CompileOptions.PackMatrixRowMajor)); }
/// <summary> /// Creates a new <see cref="D2DEmbeddedBytecodeAttribute"/> instance with the specified parameters. /// </summary> /// <param name="shaderProfile">The target shader profile to use to compile the shader.</param> public D2DEmbeddedBytecodeAttribute(D2D1ShaderProfile shaderProfile) { #if !SOURCE_GENERATOR ShaderProfile = shaderProfile switch { D2D1ShaderProfile.PixelShader40 or D2D1ShaderProfile.PixelShader40Level91 or D2D1ShaderProfile.PixelShader40Level93 or D2D1ShaderProfile.PixelShader41 or D2D1ShaderProfile.PixelShader50 => shaderProfile, _ => ThrowHelper.ThrowArgumentException <D2D1ShaderProfile>(nameof(shaderProfile), "Invalid shader profile value.") }; #endif }
/// <summary> /// Compiles a new HLSL shader from the input source code. /// </summary> /// <param name="source">The HLSL source code to compile.</param> /// <param name="shaderProfile">The shader profile to use to compile the shader.</param> /// <param name="enableLinkingSupport">Whether to enable linking support for the shader.</param> /// <returns>The bytecode for the compiled shader.</returns> public static ComPtr <ID3DBlob> Compile(ReadOnlySpan <char> source, D2D1ShaderProfile shaderProfile, bool enableLinkingSupport) { // Compile the standalone D2D1 full shader using ComPtr <ID3DBlob> d3DBlobFullShader = CompileD2DFullShader(source, shaderProfile); if (!enableLinkingSupport) { return(d3DBlobFullShader.Move()); } // Compile the export function and embed it as private data if requested using ComPtr <ID3DBlob> d3DBlobFunction = CompileD2DFunction(source, shaderProfile); using ComPtr <ID3DBlob> d3DBlobLinked = EmbedD2DFunctionPrivateData(d3DBlobFullShader.Get(), d3DBlobFunction.Get()); return(d3DBlobLinked.Move()); }
/// <summary> /// Loads the bytecode from an input D2D1 pixel shader. /// </summary> /// <typeparam name="T">The type of D2D1 pixel shader to load the bytecode for.</typeparam> /// <param name="shaderProfile">The shader profile to use to get the shader bytecode.</param> /// <returns>A <see cref="ReadOnlyMemory{T}"/> instance with the resulting shader bytecode.</returns> /// <remarks> /// If the input shader was precompiled, the returned <see cref="ReadOnlyMemory{T}"/> instance will wrap a pinned memory buffer (from the PE section). /// If the shader was compiled at runtime, the returned <see cref="ReadOnlyMemory{T}"/> instance will wrap a <see cref="byte"/> array with the bytecode. /// </remarks> public static ReadOnlyMemory <byte> LoadPixelShaderBytecode <T>(D2D1ShaderProfile shaderProfile) where T : unmanaged, ID2D1PixelShader { return(LoadOrCompilePixelShaderBytecode <T>(shaderProfile)); }
/// <summary> /// Compiles a D2D1 pixel shader with <c>D2D_FULL_SHADER</c>. /// </summary> /// <param name="source">The HLSL source code to compile.</param> /// <param name="shaderProfile">The shader profile to use to compile the shader.</param> /// <returns>The bytecode for the compiled shader.</returns> private static ComPtr <ID3DBlob> CompileD2DFullShader(ReadOnlySpan <char> source, D2D1ShaderProfile shaderProfile) { // Encode the HLSL source to ASCII int maxLength = Encoding.ASCII.GetMaxByteCount(source.Length); byte[] buffer = ArrayPool <byte> .Shared.Rent(maxLength); int writtenBytes = Encoding.ASCII.GetBytes(source, buffer); using ComPtr <ID3DBlob> d3DBlobBytecode = default; using ComPtr <ID3DBlob> d3DBlobErrors = default; int hResult; fixed(byte *bufferPtr = buffer) { // Prepare the macros for full shader compilation: // // -D D2D_FULL_SHADER // -D D2D_ENTRY=Execute D3D_SHADER_MACRO *macros = stackalloc D3D_SHADER_MACRO[] { new() { Name = (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.D2D_FULL_SHADER)), Definition = (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.NullTerminator)) }, new() { Name = (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.D2D_ENTRY)), Definition = (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.Execute)) }, new() }; // Compile the shader with -ps_5_0 -O3 -We -Zpr hResult = DirectX.D3DCompile( pSrcData: bufferPtr, SrcDataSize: (nuint)writtenBytes, pSourceName: null, pDefines: macros, pInclude: D3DIncludeForD2D1EffectHelpers, pEntrypoint: (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.Execute)), pTarget: (sbyte *)Unsafe.AsPointer(ref MemoryMarshal.GetReference(ASCII.GetPixelShaderProfile(shaderProfile))), Flags1: D3DCOMPILE.D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE.D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE.D3DCOMPILE_PACK_MATRIX_ROW_MAJOR, Flags2: 0, ppCode: d3DBlobBytecode.GetAddressOf(), ppErrorMsgs: d3DBlobErrors.GetAddressOf()); } ArrayPool <byte> .Shared.Return(buffer); // Throw if an error was retrieved, then also double check the HRESULT if (d3DBlobErrors.Get() is not null) { ThrowHslsCompilationException(d3DBlobErrors.Get()); } hResult.Assert(); return(d3DBlobBytecode.Move()); }
/// <summary> /// Creates a new <see cref="D2DEmbeddedBytecodeAttribute"/> instance with the specified parameters. /// </summary> /// <param name="shaderProfile">The target shader profile to use to compile the shader.</param> public D2DEmbeddedBytecodeAttribute(D2D1ShaderProfile shaderProfile) { ShaderProfile = shaderProfile; }