/// <summary> /// Extracts the output buffer info for the current shader. /// </summary> /// <param name="structDeclarationSymbol">The input <see cref="INamedTypeSymbol"/> instance to process.</param> /// <param name="bufferPrecision">The output buffer precision for the shader.</param> /// <param name="channelDepth">The output buffer channel depth for the shader.</param> public static void GetInfo( INamedTypeSymbol structDeclarationSymbol, out D2D1BufferPrecision bufferPrecision, out D2D1ChannelDepth channelDepth) { // Try to get the [D2DOutputBuffer] attribute if (!structDeclarationSymbol.TryGetAttributeWithFullMetadataName("ComputeSharp.D2D1.D2DOutputBufferAttribute", out AttributeData? attributeData)) { bufferPrecision = D2D1BufferPrecision.Unknown; channelDepth = D2D1ChannelDepth.Default; return; } // Extract the buffer precision and channel depth, if available if (attributeData !.ConstructorArguments.Length == 1) { if (attributeData.AttributeConstructor is IMethodSymbol { Parameters.Length : 1 } constructorSymbol&& constructorSymbol.Parameters[0].Type.HasFullyQualifiedName("ComputeSharp.D2D1.D2D1BufferPrecision")) { bufferPrecision = (D2D1BufferPrecision)attributeData.ConstructorArguments[0].Value !; channelDepth = D2D1ChannelDepth.Default; }
/// <summary> /// The factory method for <see cref="ID2D1Factory1.RegisterEffectFromString"/>. /// </summary> /// <param name="shaderId">The <see cref="Guid"/> for the shader.</param> /// <param name="inputCount">The number of inputs for the shader.</param> /// <param name="inputTypes">The buffer with the types of inputs for the shader.</param> /// <param name="inputDescriptionCount">The number of available input descriptions.</param> /// <param name="inputDescriptions">The buffer with the available input descriptions for the shader.</param> /// <param name="pixelOptions">The pixel options for the shader.</param> /// <param name="bytecode">The shader bytecode.</param> /// <param name="bytecodeSize">The size of <paramref name="bytecode"/>.</param> /// <param name="bufferPrecision">The buffer precision for the resulting output buffer.</param> /// <param name="channelDepth">The channel depth for the resulting output buffer.</param> /// <param name="d2D1TransformMapper">The <see cref="D2D1TransformMapper"/> instance to use for the effect.</param> /// <param name="effectImpl">The resulting effect instance.</param> /// <returns>This always returns <c>0</c>.</returns> private static int Factory( Guid shaderId, int inputCount, D2D1PixelShaderInputType *inputTypes, int inputDescriptionCount, D2D1InputDescription *inputDescriptions, D2D1PixelOptions pixelOptions, byte *bytecode, int bytecodeSize, D2D1BufferPrecision bufferPrecision, D2D1ChannelDepth channelDepth, D2D1TransformMapper?d2D1TransformMapper, IUnknown **effectImpl) { PixelShaderEffect * @this; try { @this = (PixelShaderEffect *)NativeMemory.Alloc((nuint)sizeof(PixelShaderEffect)); } catch (OutOfMemoryException) { *effectImpl = null; return(E.E_OUTOFMEMORY); } *@this = default; @this->lpVtblForID2D1EffectImpl = VtblForID2D1EffectImpl; @this->lpVtblForID2D1DrawTransform = VtblForID2D1DrawTransform; @this->referenceCount = 1; @this->shaderId = shaderId; @this->inputCount = inputCount; @this->inputTypes = inputTypes; @this->inputDescriptionCount = inputDescriptionCount; @this->inputDescriptions = inputDescriptions; @this->pixelOptions = pixelOptions; @this->bytecode = bytecode; @this->bytecodeSize = bytecodeSize; @this->bufferPrecision = bufferPrecision; @this->channelDepth = channelDepth; @this->d2D1TransformMapperHandle = GCHandle.Alloc(d2D1TransformMapper); *effectImpl = (IUnknown *)@this; return(S.S_OK); }
/// <summary> /// Creates a new instance of the <see cref="D2DOutputBufferAttribute"/> type with the specified arguments. /// </summary> /// <param name="channelDepth">The channel depth for the resulting output buffer.</param> public D2DOutputBufferAttribute(D2D1ChannelDepth channelDepth) { ChannelDepth = channelDepth; }
/// <summary> /// Creates a new instance of the <see cref="D2DOutputBufferAttribute"/> type with the specified arguments. /// </summary> /// <param name="bufferPrecision">The buffer precision for the resulting output buffer.</param> /// <param name="channelDepth">The channel depth for the resulting output buffer.</param> public D2DOutputBufferAttribute(D2D1BufferPrecision bufferPrecision, D2D1ChannelDepth channelDepth) { BufferPrecision = bufferPrecision; ChannelDepth = channelDepth; }
/// <summary> /// Initializes the <see cref="For{T}"/> shared state. /// </summary> /// <param name="d2D1DrawTransformMapperFactory">The factory of <see cref="ID2D1TransformMapper{T}"/> instances to use for each created effect.</param> /// <exception cref="InvalidOperationException">Thrown if initialization is attempted with a mismatched transform factory.</exception> public static void Initialize(Func <ID2D1TransformMapper <T> >?d2D1DrawTransformMapperFactory) { // This conceptually acts as a static constructor, and this type is // internal, so in this very specific case locking on the type is fine. lock (typeof(For <T>)) { if (isInitialized) { // If the factory is already initialized, ensure the draw transform mapper is the same if (For <T> .d2D1DrawTransformMapperFactory != d2D1DrawTransformMapperFactory) { ThrowHelper.ThrowInvalidOperationException( "Cannot initialize an ID2D1Effect factory for the same shader type with two different transform mappings. " + "Make sure to only ever register a pixel shader effect with either no transform, or the same transform type."); } } else { // Load all shader properties Guid shaderId = typeof(T).GUID; ReadOnlyMemory <byte> bytecodeInfo = D2D1PixelShader.LoadBytecode <T>(); int bytecodeSize = bytecodeInfo.Length; byte *bytecode = (byte *)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(For <T>), bytecodeSize); D2D1BufferPrecision bufferPrecision = D2D1PixelShader.GetOutputBufferPrecision <T>(); D2D1ChannelDepth channelDepth = D2D1PixelShader.GetOutputBufferChannelDepth <T>(); D2D1PixelOptions pixelOptions = D2D1PixelShader.GetPixelOptions <T>(); // Prepare the inputs info int inputCount = D2D1PixelShader.GetInputCount <T>(); D2D1PixelShaderInputType *inputTypes = (D2D1PixelShaderInputType *)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(For <T>), sizeof(D2D1PixelShaderInputType) * inputCount); for (int i = 0; i < inputCount; i++) { inputTypes[i] = D2D1PixelShader.GetInputType <T>(i); } // Prepare the input descriptions ReadOnlyMemory <D2D1InputDescription> inputDescriptionsInfo = D2D1PixelShader.GetInputDescriptions <T>(); int inputDescriptionCount = inputDescriptionsInfo.Length; D2D1InputDescription *inputDescriptions = (D2D1InputDescription *)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(For <T>), sizeof(D2D1InputDescription) * inputDescriptionCount); inputDescriptionsInfo.Span.CopyTo(new Span <D2D1InputDescription>(inputDescriptions, inputDescriptionCount)); // Copy the bytecode to the target buffer bytecodeInfo.Span.CopyTo(new Span <byte>(bytecode, bytecodeSize)); // Set the shared state and mark the type as initialized For <T> .shaderId = shaderId; For <T> .inputCount = inputCount; For <T> .inputTypes = inputTypes; For <T> .inputDescriptionCount = inputDescriptionCount; For <T> .inputDescriptions = inputDescriptions; For <T> .pixelOptions = pixelOptions; For <T> .bytecode = bytecode; For <T> .bytecodeSize = bytecodeSize; For <T> .bufferPrecision = bufferPrecision; For <T> .channelDepth = channelDepth; For <T> .d2D1DrawTransformMapperFactory = d2D1DrawTransformMapperFactory; isInitialized = true; } } }