Skip to content

Commit

Permalink
Use throw helpers in pixel shader effect, add more checks
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Oct 7, 2023
1 parent 11d1ad9 commit b13322a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ public static void ThrowIfGreaterThan(this ArgumentOutOfRangeException? _, int v
}
}

/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is greater than or equal to <paramref name="other"/>.
/// </summary>
/// <param name="_">Dummy value to invoke the extension upon (always pass <see langword="null"/>.</param>
/// <param name="value">The argument to validate as less or equal than <paramref name="other"/>.</param>
/// <param name="other">The value to compare with <paramref name="value"/>.</param>
/// <param name="parameterName">The name of the parameter with which <paramref name="value"/> corresponds.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowIfGreaterThanOrEqual(this ArgumentOutOfRangeException? _, int value, int other, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
{
if (value > other)
{
Throw(parameterName, value);
}
}

/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is less than <paramref name="other"/>.
/// </summary>
Expand Down Expand Up @@ -118,6 +134,22 @@ public static void ThrowIfNotInRange(this ArgumentOutOfRangeException? _, int va
}
}

/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is not equal to a given other value.
/// </summary>
/// <param name="_">Dummy value to invoke the extension upon (always pass <see langword="null"/>.</param>
/// <param name="value">The argument to validate.</param>
/// <param name="other">The value to compare against.</param>
/// <param name="parameterName">The name of the parameter with which <paramref name="value"/> corresponds.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowIfNotEqual(this ArgumentOutOfRangeException? _, int value, int other, [CallerArgumentExpression(nameof(value))] string? parameterName = null)
{
if (value != other)
{
Throw(parameterName, value);
}
}

/// <summary>
/// Throws an <see cref="ArgumentOutOfRangeException"/> if <paramref name="value"/> is not in the specified range.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,14 @@ public static int MapOutputRectToInputRects(PixelShaderEffect* @this, RECT* outp

try
{
if (inputRectsCount != @this->GetGlobals().InputCount)
{
return E.E_INVALIDARG;
}
default(ArgumentNullException).ThrowIfNull(outputRect);
default(ArgumentNullException).ThrowIfNull(inputRects);
default(ArgumentOutOfRangeException).ThrowIfNotEqual((int)inputRectsCount, @this->GetGlobals().InputCount, nameof(inputRectsCount));

if (@this->d2D1TransformMapper is not null)
{
// Forward to the current ID2D1TransformMapper instance
HRESULT hresult = @this->d2D1TransformMapper->MapOutputRectToInputRects(outputRect, inputRects, inputRectsCount);

if (!Windows.SUCCEEDED(hresult))
{
return hresult;
}
@this->d2D1TransformMapper->MapOutputRectToInputRects(outputRect, inputRects, inputRectsCount).Assert();
}
else
{
Expand Down Expand Up @@ -186,29 +180,25 @@ public static int MapInputRectsToOutputRect(PixelShaderEffect* @this, RECT* inpu

try
{
if (inputRectCount != @this->GetGlobals().InputCount)
{
return E.E_INVALIDARG;
}
default(ArgumentNullException).ThrowIfNull(inputRects);
default(ArgumentNullException).ThrowIfNull(inputOpaqueSubRects);
default(ArgumentOutOfRangeException).ThrowIfNotEqual((int)inputRectCount, @this->GetGlobals().InputCount, nameof(inputRectCount));
default(ArgumentNullException).ThrowIfNull(outputRect);
default(ArgumentNullException).ThrowIfNull(outputOpaqueSubRect);

if (@this->d2D1TransformMapper is not null)
{
using ComPtr<D2D1DrawInfoUpdateContextImpl> d2D1DrawInfoUpdateContext = default;

// Create an ID2D1DrawInfoUpdateContext instance
HRESULT hresult = D2D1DrawInfoUpdateContextImpl.Factory(
D2D1DrawInfoUpdateContextImpl.Factory(
drawInfoUpdateContext: d2D1DrawInfoUpdateContext.GetAddressOf(),
constantBuffer: @this->constantBuffer,
constantBufferSize: @this->GetGlobals().ConstantBufferSize,
d2D1DrawInfo: @this->d2D1DrawInfo);

if (!Windows.SUCCEEDED(hresult))
{
return hresult;
}
d2D1DrawInfo: @this->d2D1DrawInfo).Assert();

// Forward the call to the input ID2D1TransformMapper instance
hresult = @this->d2D1TransformMapper->MapInputRectsToOutputRect(
HRESULT hresult = @this->d2D1TransformMapper->MapInputRectsToOutputRect(
updateContext: (ID2D1DrawInfoUpdateContext*)d2D1DrawInfoUpdateContext.Get(),
inputRects: inputRects,
inputOpaqueSubRects: inputOpaqueSubRects,
Expand All @@ -217,12 +207,10 @@ public static int MapInputRectsToOutputRect(PixelShaderEffect* @this, RECT* inpu
outputOpaqueSubRect: outputOpaqueSubRect);

// Regardless of the operation result, always invalidate the context
_ = d2D1DrawInfoUpdateContext.Get()->Close();
d2D1DrawInfoUpdateContext.Get()->Close().Assert();

if (!Windows.SUCCEEDED(hresult))
{
return hresult;
}
// Now we can validate that the call was in fact successful
hresult.Assert();
}
else if (inputRectCount == 0)
{
Expand Down Expand Up @@ -288,20 +276,13 @@ public static int MapInvalidRect(PixelShaderEffect* @this, uint inputIndex, RECT

try
{
if (inputIndex >= (uint)@this->GetGlobals().InputCount)
{
return E.E_INVALIDARG;
}
default(ArgumentOutOfRangeException).ThrowIfGreaterThanOrEqual((int)inputIndex, @this->GetGlobals().InputCount, nameof(inputIndex));
default(ArgumentNullException).ThrowIfNull(invalidOutputRect);

if (@this->d2D1TransformMapper is not null)
{
// Forward to the current ID2D1TransformMapper instance
HRESULT hresult = @this->d2D1TransformMapper->MapInvalidRect(inputIndex, invalidInputRect, invalidOutputRect);

if (!Windows.SUCCEEDED(hresult))
{
return hresult;
}
@this->d2D1TransformMapper->MapInvalidRect(inputIndex, invalidInputRect, invalidOutputRect).Assert();
}
else
{
Expand Down Expand Up @@ -336,6 +317,8 @@ public static int SetDrawInfo(PixelShaderEffect* @this, ID2D1DrawInfo* drawInfo)

try
{
default(ArgumentNullException).ThrowIfNull(drawInfo);

// Free the previous ID2D1DrawInfo object, if present
ComPtr<ID2D1DrawInfo>.Release(@this->d2D1DrawInfo);

Expand All @@ -348,12 +331,7 @@ public static int SetDrawInfo(PixelShaderEffect* @this, ID2D1DrawInfo* drawInfo)
D2D1PixelOptions pixelOptions = @this->GetGlobals().PixelOptions;

// Set the pixel shader for the effect
HRESULT hresult = drawInfo->SetPixelShader(&shaderId, (D2D1_PIXEL_OPTIONS)pixelOptions);

if (hresult != S.S_OK)
{
return hresult;
}
drawInfo->SetPixelShader(&shaderId, (D2D1_PIXEL_OPTIONS)pixelOptions).Assert();

// If any input descriptions are present, set them
foreach (ref readonly D2D1InputDescription inputDescription in @this->GetGlobals().InputDescriptions.Span)
Expand All @@ -362,12 +340,7 @@ public static int SetDrawInfo(PixelShaderEffect* @this, ID2D1DrawInfo* drawInfo)
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;
}
drawInfo->SetInputDescription((uint)inputDescription.Index, d2D1InputDescription).Assert();
}

D2D1BufferPrecision bufferPrecision = @this->GetGlobals().BufferPrecision;
Expand All @@ -377,14 +350,9 @@ public static int SetDrawInfo(PixelShaderEffect* @this, ID2D1DrawInfo* drawInfo)
if (bufferPrecision != D2D1BufferPrecision.Unknown ||
channelDepth != D2D1ChannelDepth.Default)
{
hresult = drawInfo->SetOutputBuffer(
drawInfo->SetOutputBuffer(
(D2D1_BUFFER_PRECISION)bufferPrecision,
(D2D1_CHANNEL_DEPTH)channelDepth);

if (hresult != S.S_OK)
{
return hresult;
}
(D2D1_CHANNEL_DEPTH)channelDepth).Assert();
}

return S.S_OK;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using ComputeSharp.D2D1.Extensions;
using ComputeSharp.D2D1.Shaders.Interop.Effects.ResourceManagers;
using ComputeSharp.D2D1.Shaders.Interop.Extensions;
using TerraFX.Interop.DirectX;
Expand Down Expand Up @@ -88,13 +89,15 @@ public static int Initialize(PixelShaderEffect* @this, ID2D1EffectContext* effec
{
try
{
default(ArgumentNullException).ThrowIfNull(effectContext);
default(ArgumentNullException).ThrowIfNull(transformGraph);

ReadOnlySpan<byte> bytecode = @this->GetGlobals().HlslBytecode.Span;
int hresult;

fixed (Guid* pShaderId = &@this->GetGlobals().EffectId)
fixed (byte* pBytecode = bytecode)
{
hresult = effectContext->LoadPixelShader(
HRESULT hresult = effectContext->LoadPixelShader(
shaderId: pShaderId,
shaderBuffer: pBytecode,
shaderBufferCount: (uint)bytecode.Length);
Expand All @@ -106,27 +109,23 @@ public static int Initialize(PixelShaderEffect* @this, ID2D1EffectContext* effec
{
hresult = D2DERR.D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES;
}

// Finally, assert that we did load the pixel shader correctly
hresult.Assert();
}

// If loading the bytecode succeeded, set the transform node
if (Windows.SUCCEEDED(hresult))
{
hresult = transformGraph->SetSingleTransformNode((ID2D1TransformNode*)&@this->lpVtblForID2D1DrawTransform);
}
transformGraph->SetSingleTransformNode((ID2D1TransformNode*)&@this->lpVtblForID2D1DrawTransform).Assert();

// If the transform node was set, also store the effect context
if (Windows.SUCCEEDED(hresult))
{
// Free the previous ID2D1EffectContext object, if present
ComPtr<ID2D1EffectContext>.Release(@this->d2D1EffectContext);
// Free the previous ID2D1EffectContext object, if present
ComPtr<ID2D1EffectContext>.Release(@this->d2D1EffectContext);

// Store the new ID2D1EffectContext object
_ = effectContext->AddRef();
// Store the new ID2D1EffectContext object
_ = effectContext->AddRef();

@this->d2D1EffectContext = effectContext;
}
@this->d2D1EffectContext = effectContext;

return hresult;
return S.S_OK;
}
catch (Exception e)
{
Expand All @@ -140,9 +139,10 @@ public static int PrepareForRender(PixelShaderEffect* @this, D2D1_CHANGE_TYPE ch
{
try
{
int hresult = S.S_OK;

// Validate the constant buffer
// Validate the constant buffer. We either must have a stateless shader, in which case
// the constant buffer might either be null or empty (both cases are allowed), or we
// must have a shader with some state and a constant buffer being set. In that case
// the code setting the constant buffer will have already validated its length.
if (@this->GetGlobals().ConstantBufferSize > 0 &&
@this->constantBuffer is null)
{
Expand All @@ -152,64 +152,44 @@ public static int PrepareForRender(PixelShaderEffect* @this, D2D1_CHANGE_TYPE ch
// First, set the constant buffer, if available
if (@this->constantBuffer is not null)
{
hresult = @this->d2D1DrawInfo->SetPixelShaderConstantBuffer(
@this->d2D1DrawInfo->SetPixelShaderConstantBuffer(
buffer: @this->constantBuffer,
bufferCount: (uint)@this->GetGlobals().ConstantBufferSize);
bufferCount: (uint)@this->GetGlobals().ConstantBufferSize).Assert();
}

if (Windows.SUCCEEDED(hresult))
ReadOnlySpan<D2D1ResourceTextureDescription> resourceTextureDescriptions = @this->GetGlobals().ResourceTextureDescriptions.Span;

for (int i = 0; i < resourceTextureDescriptions.Length; i++)
{
ReadOnlySpan<D2D1ResourceTextureDescription> resourceTextureDescriptions = @this->GetGlobals().ResourceTextureDescriptions.Span;
using ComPtr<ID2D1ResourceTextureManager> resourceTextureManager = @this->resourceTextureManagerBuffer[i];

for (int i = 0; i < resourceTextureDescriptions.Length; i++)
// If the current resource texture manager is not set, we cannot render, as there's an unbound resource texture
if (resourceTextureManager.Get() is null)
{
using ComPtr<ID2D1ResourceTextureManager> resourceTextureManager = @this->resourceTextureManagerBuffer[i];

// If the current resource texture manager is not set, we cannot render, as there's an unbound resource texture
if (resourceTextureManager.Get() is null)
{
hresult = E.E_NOT_VALID_STATE;

break;
}

using ComPtr<ID2D1ResourceTextureManagerInternal> resourceTextureManagerInternal = default;

// Get the ID2D1ResourceTextureManagerInternal object
hresult = resourceTextureManager.CopyTo(resourceTextureManagerInternal.GetAddressOf());

// This cast should always succeed, as when an input resource texture managers is set it's
// also checked for ID2D1ResourceTextureManagerInternal, but still validate for good measure.
if (!Windows.SUCCEEDED(hresult))
{
break;
}
return E.E_NOT_VALID_STATE;
}

using ComPtr<ID2D1ResourceTexture> d2D1ResourceTexture = default;
using ComPtr<ID2D1ResourceTextureManagerInternal> resourceTextureManagerInternal = default;

// Try to get the ID2D1ResourceTexture from the manager
hresult = resourceTextureManagerInternal.Get()->GetResourceTexture(d2D1ResourceTexture.GetAddressOf());
// Get the ID2D1ResourceTextureManagerInternal object. This cast should always succeed, as when
// an input resource texture managers is set it's also checked for ID2D1ResourceTextureManagerInternal,
// but still validate for good measure.
resourceTextureManager.CopyTo(resourceTextureManagerInternal.GetAddressOf()).Assert();

if (!Windows.SUCCEEDED(hresult))
{
break;
}
using ComPtr<ID2D1ResourceTexture> d2D1ResourceTexture = default;

ref readonly D2D1ResourceTextureDescription resourceTextureDescription = ref resourceTextureDescriptions[i];
// Try to get the ID2D1ResourceTexture from the manager
resourceTextureManagerInternal.Get()->GetResourceTexture(d2D1ResourceTexture.GetAddressOf()).Assert();

// Set the ID2D1ResourceTexture object to the current index in the ID2D1DrawInfo object in use
hresult = @this->d2D1DrawInfo->SetResourceTexture(
textureIndex: (uint)resourceTextureDescription.Index,
resourceTexture: d2D1ResourceTexture.Get());
ref readonly D2D1ResourceTextureDescription resourceTextureDescription = ref resourceTextureDescriptions[i];

if (!Windows.SUCCEEDED(hresult))
{
break;
}
}
// Set the ID2D1ResourceTexture object to the current index in the ID2D1DrawInfo object in use
@this->d2D1DrawInfo->SetResourceTexture(
textureIndex: (uint)resourceTextureDescription.Index,
resourceTexture: d2D1ResourceTexture.Get()).Assert();
}

return hresult;
return S.S_OK;
}
catch (Exception e)
{
Expand Down
Loading

0 comments on commit b13322a

Please sign in to comment.