Skip to content

Commit

Permalink
Minor code refactoring, share device context rent logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergio0694 committed Jan 22, 2023
1 parent cd7da44 commit c7e12d1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 48 deletions.
46 changes: 33 additions & 13 deletions src/ComputeSharp.D2D1.Uwp/Extensions/ICanvasDeviceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,43 @@ public static HRESULT GetD2DDevice(this ref ICanvasDevice canvasDevice, ID2D1Dev
}

/// <summary>
/// Gets a new <see cref="ID2D1DeviceContextLease"/> from an input <see cref="ICanvasDevice"/>.
/// Retrieves a usable <see cref="ID2D1DeviceContext"/> from an input <see cref="ICanvasDevice"/> if one is not available.
/// If a new one had to be rented from the pool, it also returns the owning <see cref="ID2D1DeviceContextLease"/> instance.
/// </summary>
/// <param name="canvasDevice">The input <see cref="ICanvasDevice"/> object.</param>
/// <param name="d2D1DeviceContextLease">The resulting <see cref="ID2D1DeviceContextLease"/> object.</param>
/// <returns>The <see cref="HRESULT"/> for the operation.</returns>
public static HRESULT GetD2DDeviceContextLease(this ref ICanvasDevice canvasDevice, ID2D1DeviceContextLease** d2D1DeviceContextLease)
/// <param name="d2D1DeviceContext">The current <see cref="ID2D1DeviceContext"/> object, if available.</param>
/// <param name="d2D1DeviceContextEffective">The resulting <see cref="ID2D1DeviceContext"/> instance to use.</param>
/// <param name="d2D1DeviceContextLease">The resulting <see cref="ID2D1DeviceContextLease"/> object, if used.</param>
/// <remarks>
/// When this method returns, <paramref name="d2D1DeviceContextEffective"/> is guaranteed to not be <see langword="null"/>.
/// </remarks>
public static void GetEffectiveD2DDeviceContextWithOptionalLease(
this ref ICanvasDevice canvasDevice,
ID2D1DeviceContext* d2D1DeviceContext,
ID2D1DeviceContext** d2D1DeviceContextEffective,
ID2D1DeviceContextLease** d2D1DeviceContextLease)
{
using ComPtr<ID2D1DeviceContextPool> d2D1DeviceContextPool = default;

// Get the ID2D1DeviceContextLease interface reference
canvasDevice.QueryInterface(
riid: Win32.__uuidof<ID2D1DeviceContextPool>(),
ppvObject: d2D1DeviceContextPool.GetVoidAddressOf()).Assert();
// If there is no input device context, just create a new one from the input canvas device
if (d2D1DeviceContext is null)
{
using (ComPtr<ID2D1DeviceContextPool> d2D1DeviceContextPool = default)
{
// Get the ID2D1DeviceContextPool interface reference
canvasDevice.QueryInterface(
riid: Win32.__uuidof<ID2D1DeviceContextPool>(),
ppvObject: d2D1DeviceContextPool.GetVoidAddressOf()).Assert();

// Create the new lease
HRESULT hresult = d2D1DeviceContextPool.Get()->GetDeviceContextLease(d2D1DeviceContextLease);
// Get a new ID2D1DeviceContextLease object from the retrieved pool
d2D1DeviceContextPool.Get()->GetDeviceContextLease(d2D1DeviceContextLease).Assert();
}

return hresult;
// Get the underlying device context from the lease (this is much faster than creating a new device context)
(*d2D1DeviceContextLease)->GetD2DDeviceContext(d2D1DeviceContextEffective).Assert();
}
else
{
// Otherwise, just use the input device context
*d2D1DeviceContextEffective = new ComPtr<ID2D1DeviceContext>(d2D1DeviceContext);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,24 +228,14 @@ private bool Realize(WIN2D_GET_D2D_IMAGE_FLAGS flags, float targetDpi, ID2D1Devi
{
Guid effectId = PixelShaderEffect.For<T>.Instance.Id;

using ComPtr<ID2D1DeviceContextLease> d2D1DeviceContextLease = default;
using ComPtr<ID2D1DeviceContext> d2D1DeviceContextEffective = default;
using ComPtr<ID2D1DeviceContextLease> d2D1DeviceContextLease = default;

// We need to realize the current effect (ComputeSharp.D2D1's ID2D1Effect), so a device context must
// be available. If there is no input device context, just create a new one from the realization device.
if (deviceContext is null)
{
// Get the ID2D1DeviceContextLease interface from the input device
this.canvasDevice.Get()->GetD2DDeviceContextLease(d2D1DeviceContextLease.GetAddressOf()).Assert();

// Rent a new device context from the lease (this is much faster than creating a new device context)
d2D1DeviceContextLease.Get()->GetD2DDeviceContext(d2D1DeviceContextEffective.GetAddressOf()).Assert();
}
else
{
// Otherwise, just use the input device context
*&d2D1DeviceContextEffective = new ComPtr<ID2D1DeviceContext>(deviceContext);
}
// We need to realize the current effect (ComputeSharp.D2D1's ID2D1Effect), which needs a device context
this.canvasDevice.Get()->GetEffectiveD2DDeviceContextWithOptionalLease(
d2D1DeviceContext: deviceContext,
d2D1DeviceContextEffective: d2D1DeviceContextEffective.GetAddressOf(),
d2D1DeviceContextLease: d2D1DeviceContextLease.GetAddressOf());

// Try to create an instance of the effect in use and store it in the current object
HRESULT hresult = d2D1DeviceContextEffective.Get()->CreateEffect(effectId: &effectId, effect: d2D1Effect);
Expand All @@ -260,7 +250,7 @@ private bool Realize(WIN2D_GET_D2D_IMAGE_FLAGS flags, float targetDpi, ID2D1Devi
using ComPtr<ID2D1Factory1> d2D1Factory1 = default;

// Get the ID2D1Factory1 object to register the effect (required by D2D1PixelShaderEffect)
deviceContext->GetFactory1(d2D1Factory1.GetAddressOf()).Assert();
d2D1DeviceContextEffective.Get()->GetFactory1(d2D1Factory1.GetAddressOf()).Assert();

// Register the effect with the factory (pass the same D2D1 draw transform mapper factory that was used before)
D2D1PixelShaderEffect.RegisterForD2D1Factory1<T>(d2D1Factory1.Get(), out _);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,26 +280,20 @@ private bool ApplyDpiCompensation(
// Create an ID2D1Effect for the DPI compensation, if there isn't one already
if (!sourceReference.HasDpiCompensationEffect)
{
using ComPtr<ID2D1DeviceContextLease> d2D1DeviceContextLease = default;
using ComPtr<ID2D1DeviceContext> d2D1DeviceContextEffective = default;

// Just like when realizing the current effect, rent a device context from the pool if one is not available.
// That is, either get the ID2D1DeviceContextPool interface and rent a device, or just use the input one.
if (d2D1DeviceContext is null)
using (ComPtr<ID2D1DeviceContext> d2D1DeviceContextEffective = default)
using (ComPtr<ID2D1DeviceContextLease> d2D1DeviceContextLease = default)
{
this.canvasDevice.Get()->GetD2DDeviceContextLease(d2D1DeviceContextLease.GetAddressOf()).Assert();

d2D1DeviceContextLease.Get()->GetD2DDeviceContext(d2D1DeviceContextEffective.GetAddressOf()).Assert();
// Just like when realizing the current effect, rent a device context from the pool if one is not available
this.canvasDevice.Get()->GetEffectiveD2DDeviceContextWithOptionalLease(
d2D1DeviceContext: d2D1DeviceContext,
d2D1DeviceContextEffective: d2D1DeviceContextEffective.GetAddressOf(),
d2D1DeviceContextLease: d2D1DeviceContextLease.GetAddressOf());

// Create the DPI compensation effect
d2D1DeviceContextEffective.Get()->CreateEffect(
effectId: (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in CLSID.CLSID_D2D1DpiCompensation)),
effect: d2D1EffectDpiCompensation.GetAddressOf()).Assert();
}
else
{
*&d2D1DeviceContextEffective = new ComPtr<ID2D1DeviceContext>(d2D1DeviceContext);
}

// Create the DPI compensation effect
d2D1DeviceContextEffective.Get()->CreateEffect(
effectId: (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in CLSID.CLSID_D2D1DpiCompensation)),
effect: d2D1EffectDpiCompensation.GetAddressOf()).Assert();

D2D1_BORDER_MODE d2D1BorderMode = D2D1_BORDER_MODE_HARD;
D2D1_DPICOMPENSATION_INTERPOLATION_MODE d2D1DpiCompensationInterpolationMode = D2D1_DPICOMPENSATION_INTERPOLATION_MODE_LINEAR;
Expand Down

0 comments on commit c7e12d1

Please sign in to comment.