public static int MapInvalidRect(PixelShaderEffect * @this, uint inputIndex, RECT invalidInputRect, RECT *invalidOutputRect) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Rectangle invalidInput = invalidInputRect.ToRectangle(); Rectangle invalidOutput; // Handle exceptions once again try { d2D1TransformMapper.MapInvalidOutput((int)inputIndex, invalidInput, out invalidOutput); } catch (Exception e) { return(e.HResult); } *invalidOutputRect = invalidOutput.ToRECT(); } else { // Default mapping *invalidOutputRect = @this->inputRect; } return(S.S_OK); }
/// <summary> /// The factory method for <see cref="ID2D1Factory1.RegisterEffectFromString"/>. /// </summary> /// <param name="shaderId">The <see cref="Guid"/> for the shader.</param> /// <param name="numberOfInputs">The number of inputs for the shader.</param> /// <param name="bytecode">The shader bytecode.</param> /// <param name="bytecodeSize">The size of <paramref name="bytecode"/>.</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 numberOfInputs, byte *bytecode, int bytecodeSize, D2D1TransformMapper?d2D1TransformMapper, IUnknown **effectImpl) { PixelShaderEffect * @this = (PixelShaderEffect *)NativeMemory.Alloc((nuint)sizeof(PixelShaderEffect)); *@this = default; @this->lpVtblForID2D1EffectImpl = VtblForID2D1EffectImpl; @this->lpVtblForID2D1DrawTransform = VtblForID2D1DrawTransform; @this->referenceCount = 1; @this->shaderId = shaderId; @this->numberOfInputs = numberOfInputs; @this->bytecode = bytecode; @this->bytecodeSize = bytecodeSize; @this->d2D1TransformMapperHandle = GCHandle.Alloc(d2D1TransformMapper); *effectImpl = (IUnknown *)@this; return(S.S_OK); }
public static int SetDrawInfo(PixelShaderEffect * @this, ID2D1DrawInfo *drawInfo) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; @this->d2D1DrawInfo = drawInfo; return(drawInfo->SetPixelShader(&@this->shaderId)); }
public static int PrepareForRender(PixelShaderEffect * @this, D2D1_CHANGE_TYPE changeType) { if (@this->constantBuffer is not null) { return(@this->d2D1DrawInfo->SetPixelShaderConstantBuffer( buffer: @this->constantBuffer, bufferCount: (uint)@this->constantBufferSize)); } return(S.S_OK); }
public static int Initialize(PixelShaderEffect * @this, ID2D1EffectContext *effectContext, ID2D1TransformGraph *transformGraph) { int hresult = effectContext->LoadPixelShader( shaderId: &@this->shaderId, shaderBuffer: @this->bytecode, shaderBufferCount: (uint)@this->bytecodeSize); if (Windows.SUCCEEDED(hresult)) { hresult = transformGraph->SetSingleTransformNode((ID2D1TransformNode *)&@this->lpVtblForID2D1DrawTransform); } return(hresult); }
public static int Initialize(PixelShaderEffect * @this, ID2D1EffectContext *effectContext, ID2D1TransformGraph *transformGraph) { int hresult = effectContext->LoadPixelShader( shaderId: &@this->shaderId, shaderBuffer: @this->bytecode, shaderBufferCount: (uint)@this->bytecodeSize); // If E_INVALIDARG was returned, try to check whether double precision support was requested when not available. This // is only done to provide a more helpful error message to callers. If no error was returned, the behavior is the same. if (hresult == E.E_INVALIDARG) { D2D1_FEATURE_DATA_DOUBLES d2D1FeatureDataDoubles = default; // If the call failed, just do nothing and return the previous result if (!Windows.SUCCEEDED(effectContext->CheckFeatureSupport(D2D1_FEATURE.D2D1_FEATURE_DOUBLES, &d2D1FeatureDataDoubles, (uint)sizeof(D2D1_FEATURE_DATA_DOUBLES)))) { return(E.E_INVALIDARG); } // If the context does not support double precision values, check whether the shader requested them if (d2D1FeatureDataDoubles.doublePrecisionFloatShaderOps == 0) { using ComPtr <ID3D11ShaderReflection> d3D11ShaderReflection = default; // Create the reflection instance, and in case of error just return the previous error like above if (!Windows.SUCCEEDED(DirectX.D3DReflect( pSrcData: @this->bytecode, SrcDataSize: (uint)@this->bytecodeSize, pInterface: Windows.__uuidof <ID3D11ShaderReflection>(), ppReflector: d3D11ShaderReflection.GetVoidAddressOf()))) { return(E.E_INVALIDARG); } // If the shader requires double precision support, return a more descriptive error if ((d3D11ShaderReflection.Get()->GetRequiresFlags() & (D3D.D3D_SHADER_REQUIRES_DOUBLES | D3D.D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS)) != 0) { return(D2DERR.D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES); } } } if (Windows.SUCCEEDED(hresult)) { hresult = transformGraph->SetSingleTransformNode((ID2D1TransformNode *)&@this->lpVtblForID2D1DrawTransform); } return(hresult); }
public static int MapInvalidRect(PixelShaderEffect * @this, uint inputIndex, RECT invalidInputRect, RECT *invalidOutputRect) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (inputIndex >= (uint)@this->inputCount) { return(E.E_INVALIDARG); } if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Rectangle invalidInput = invalidInputRect.ToRectangle(); Rectangle invalidOutput; // Handle exceptions once again try { d2D1TransformMapper.MapInvalidOutput((int)inputIndex, invalidInput, out invalidOutput); } catch (Exception e) { return(e.HResult); } *invalidOutputRect = invalidOutput.ToRECT(); } else { // The default mapping in this scenario just needs to set the invalid output rect for simple inputs to // be the invalid input rect, and to set the invalid output rect for complex inputs to an infinite rect. switch (@this->inputTypes[inputIndex]) { case D2D1PixelShaderInputType.Simple: *invalidOutputRect = invalidInputRect; break; case D2D1PixelShaderInputType.Complex: invalidOutputRect->MakeD2D1Infinite(); break; default: return(E.E_FAIL); } } return(S.S_OK); }
public static int MapOutputRectToInputRects(PixelShaderEffect * @this, RECT *outputRect, RECT *inputRects, uint inputRectsCount) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (inputRectsCount != @this->numberOfInputs) { return(E.E_INVALIDARG); } if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Rectangle output = outputRect->ToRectangle(); Span <Rectangle> inputs = stackalloc Rectangle[8].Slice(0, (int)inputRectsCount); for (int i = 0; i < (int)inputRectsCount; i++) { inputs[i] = inputRects[i].ToRectangle(); } // Invoke MapOutputToInputs and handle exceptions so they don't cross the ABI boundary try { d2D1TransformMapper.MapOutputToInputs(in output, inputs); } catch (Exception e) { return(e.HResult); } for (int i = 0; i < (int)inputRectsCount; i++) { inputRects[i] = inputs[i].ToRECT(); } } else { // Default mapping for (int i = 0; i < (int)inputRectsCount; i++) { inputRects[i] = *outputRect; } } return(S.S_OK); }
public static int SetConstantBuffer(IUnknown *effect, byte *data, uint dataSize) { PixelShaderEffect * @this = (PixelShaderEffect *)effect; if (@this->constantBuffer is not null) { NativeMemory.Free(@this->constantBuffer); } void *buffer = NativeMemory.Alloc(dataSize); Buffer.MemoryCopy(data, buffer, dataSize, dataSize); @this->constantBuffer = (byte *)buffer; @this->constantBufferSize = (int)dataSize; return(S.S_OK); }
public static int GetConstantBuffer(IUnknown *effect, byte *data, uint dataSize, uint *actualSize) { PixelShaderEffect * @this = (PixelShaderEffect *)effect; if (@this->constantBufferSize == 0) { *actualSize = 0; } else { int bytesToCopy = Math.Min((int)dataSize, @this->constantBufferSize); Buffer.MemoryCopy(@this->constantBuffer, data, dataSize, bytesToCopy); *actualSize = (uint)bytesToCopy; } return(S.S_OK); }
public static int SetDrawInfo(PixelShaderEffect * @this, ID2D1DrawInfo *drawInfo) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; // Free the previous ID2D1DrawInfo object, if present if (@this->d2D1DrawInfo is not null) { _ = @this->d2D1DrawInfo->Release(); } // Store the new ID2D1DrawInfo object _ = drawInfo->AddRef(); @this->d2D1DrawInfo = drawInfo; // Set the pixel shader for the effect HRESULT hresult = drawInfo->SetPixelShader(&@this->shaderId, (D2D1_PIXEL_OPTIONS)@this->pixelOptions); if (hresult != S.S_OK) { return(hresult); } // If any input descriptions are present, set them if (@this->inputDescriptionCount > 0) { for (int i = 0; i < @this->inputDescriptionCount; i++) { ref D2D1InputDescription inputDescription = ref @this->inputDescriptions[i]; D2D1_INPUT_DESCRIPTION d2D1InputDescription; d2D1InputDescription.filter = (D2D1_FILTER)inputDescription.Filter; d2D1InputDescription.levelOfDetailCount = (uint)inputDescription.LevelOfDetailCount; hresult = drawInfo->SetInputDescription((uint)inputDescription.Index, d2D1InputDescription); if (hresult != S.S_OK) { return(hresult); } } }
public static uint Release(PixelShaderEffect * @this) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; return(@this->Release()); }
public static int MapInputRectsToOutputRect(PixelShaderEffect * @this, RECT *inputRects, RECT *inputOpaqueSubRects, uint inputRectCount, RECT *outputRect, RECT *outputOpaqueSubRect) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (inputRectCount != @this->inputCount) { return(E.E_INVALIDARG); } if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Span <Rectangle> inputs = stackalloc Rectangle[8].Slice(0, (int)inputRectCount); Span <Rectangle> opaqueInputs = stackalloc Rectangle[8].Slice(0, (int)inputRectCount); for (int i = 0; i < (int)inputRectCount; i++) { inputs[i] = inputRects[i].ToRectangle(); opaqueInputs[i] = inputOpaqueSubRects[i].ToRectangle(); } ReadOnlySpan <byte> buffer = new(@this->constantBuffer, @this->constantBufferSize); Rectangle output; Rectangle opaqueOutput; // Handle exceptions, as mentioned above try { d2D1TransformMapper.MapInputsToOutput(buffer, inputs, opaqueInputs, out output, out opaqueOutput); } catch (Exception e) { return(e.HResult); } *outputRect = output.ToRECT(); *outputOpaqueSubRect = opaqueOutput.ToRECT(); } else if (inputRectCount == 0) { // If there are no inputs, make the output rectangle infinite. This is useful // to make output-only effects work fine by default, without needing a custom // transform. In this case, the target area will be the output node anyway. outputRect->MakeD2D1Infinite(); *outputOpaqueSubRect = default; } else { // If at least one input is present and no custom mapper is available, apply the default // mapping. In this case, the output rect should be the union of the input rects for all // the simple shader inputs, or infinite if there are no simple inputs. The input rects // for complex inputs, if present, are not needed in this scenario, so they're ignored. RECT unionOfSimpleRects = default; bool isUnionOfSimpleRectsEmpty = true; for (uint i = 0; i < inputRectCount; i++) { if (@this->inputTypes[i] == D2D1PixelShaderInputType.Simple) { if (isUnionOfSimpleRectsEmpty) { unionOfSimpleRects = inputRects[i]; isUnionOfSimpleRectsEmpty = false; } else { unionOfSimpleRects = unionOfSimpleRects.Union(inputRects[i]); } } } if (isUnionOfSimpleRectsEmpty) { outputRect->MakeD2D1Infinite(); } else { *outputRect = unionOfSimpleRects; } *outputOpaqueSubRect = default; } return(S.S_OK); }
public static uint AddRef(PixelShaderEffect * @this) { return(@this->AddRef()); }
public static uint Release(PixelShaderEffect * @this) { return(@this->Release()); }
public static int QueryInterface(PixelShaderEffect * @this, Guid *riid, void **ppvObject) { return(@this->QueryInterface(riid, ppvObject)); }
public static int SetGraph(PixelShaderEffect * @this, ID2D1TransformGraph *transformGraph) { return(E.E_NOTIMPL); }
public static uint GetInputCount(PixelShaderEffect * @this) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; return((uint)@this->numberOfInputs); }
public static uint AddRef(PixelShaderEffect * @this) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; return(@this->AddRef()); }
public static int MapInputRectsToOutputRect(PixelShaderEffect * @this, RECT *inputRects, RECT *inputOpaqueSubRects, uint inputRectCount, RECT *outputRect, RECT *outputOpaqueSubRect) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (inputRectCount != @this->numberOfInputs) { return(E.E_INVALIDARG); } if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Span <Rectangle> inputs = stackalloc Rectangle[8].Slice(0, (int)inputRectCount); Span <Rectangle> opaqueInputs = stackalloc Rectangle[8].Slice(0, (int)inputRectCount); for (int i = 0; i < (int)inputRectCount; i++) { inputs[i] = inputRects[i].ToRectangle(); opaqueInputs[i] = inputOpaqueSubRects[i].ToRectangle(); } ReadOnlySpan <byte> buffer = new(@this->constantBuffer, @this->constantBufferSize); Rectangle output; Rectangle opaqueOutput; // Handle exceptions, as mentioned above try { d2D1TransformMapper.MapInputsToOutput(buffer, inputs, opaqueInputs, out output, out opaqueOutput); } catch (Exception e) { return(e.HResult); } *outputRect = output.ToRECT(); *outputOpaqueSubRect = opaqueOutput.ToRECT(); } else if (inputRectCount == 0) { // If there are no inputs, make the output rectangle infinite. This is useful // to make output-only effects work fine by default, without needing a custom // transform. In this case, the target area will be the output node anyway. outputRect->MakeD2D1Infinite(); @this->inputRect = default; *outputOpaqueSubRect = default; } else { // Default mapping *outputRect = inputRects[0]; @this->inputRect = inputRects[0]; *outputOpaqueSubRect = default; } return(S.S_OK); }
public static int QueryInterface(PixelShaderEffect * @this, Guid *riid, void **ppvObject) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; return(@this->QueryInterface(riid, ppvObject)); }
public static int MapOutputRectToInputRects(PixelShaderEffect * @this, RECT *outputRect, RECT *inputRects, uint inputRectsCount) { @this = (PixelShaderEffect *)&((void **)@this)[-1]; if (inputRectsCount != @this->inputCount) { return(E.E_INVALIDARG); } if (@this->d2D1TransformMapperHandle.Target is D2D1TransformMapper d2D1TransformMapper) { Rectangle output = outputRect->ToRectangle(); Span <Rectangle> inputs = stackalloc Rectangle[8].Slice(0, (int)inputRectsCount); for (int i = 0; i < (int)inputRectsCount; i++) { inputs[i] = inputRects[i].ToRectangle(); } // Invoke MapOutputToInputs and handle exceptions so they don't cross the ABI boundary try { d2D1TransformMapper.MapOutputToInputs(in output, inputs); } catch (Exception e) { return(e.HResult); } for (int i = 0; i < (int)inputRectsCount; i++) { inputRects[i] = inputs[i].ToRECT(); } } else { // If no custom transform is used, apply the default mapping. In this case, the loop will // automatically handle cases where no inputs are defined. If inputs are present instead, // the default mapping will set the input rect for a simple input to be the same as the // output rect, and the input rect for a complex rect to be infinite. In both cases, D2D // will handle clipping the inputs to the actual output rect area, if needed. for (uint i = 0; i < inputRectsCount; i++) { switch (@this->inputTypes[i]) { case D2D1PixelShaderInputType.Simple: inputRects[i] = *outputRect; break; case D2D1PixelShaderInputType.Complex: inputRects[i].MakeD2D1Infinite(); break; default: return(E.E_FAIL); } } } return(S.S_OK); }