mirror of
https://github.com/DarthAffe/ScreenCapture.NET.git
synced 2025-12-12 21:38:42 +00:00
commit
ae35ac891a
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using SharpGen.Runtime;
|
using SharpGen.Runtime;
|
||||||
using Vortice.Direct3D;
|
using Vortice.Direct3D;
|
||||||
@ -184,13 +184,26 @@ public sealed class DX11ScreenCapture : IScreenCapture
|
|||||||
captureZone.Y + captureZone.UnscaledHeight, 1));
|
captureZone.Y + captureZone.UnscaledHeight, 1));
|
||||||
|
|
||||||
MappedSubresource mapSource = _context.Map(stagingTexture, 0, MapMode.Read, MapFlags.None);
|
MappedSubresource mapSource = _context.Map(stagingTexture, 0, MapMode.Read, MapFlags.None);
|
||||||
IntPtr sourcePtr = mapSource.DataPointer;
|
|
||||||
lock (captureZone.Buffer)
|
lock (captureZone.Buffer)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < captureZone.Height; y++)
|
Span<byte> source = mapSource.AsSpan(captureZone.Stride * captureZone.Height);
|
||||||
|
switch (Display.Rotation)
|
||||||
{
|
{
|
||||||
Marshal.Copy(sourcePtr, captureZone.Buffer, y * captureZone.Stride, captureZone.Stride);
|
case Rotation.Rotation90:
|
||||||
sourcePtr += mapSource.RowPitch;
|
CopyRotate90(source, captureZone);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rotation.Rotation180:
|
||||||
|
CopyRotate180(source, captureZone);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rotation.Rotation270:
|
||||||
|
CopyRotate270(source, captureZone);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CopyRotate0(source, captureZone);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,11 +213,74 @@ public sealed class DX11ScreenCapture : IScreenCapture
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void CopyRotate0(in Span<byte> source, in CaptureZone captureZone) => source.CopyTo(captureZone.Buffer.AsSpan());
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void CopyRotate90(in Span<byte> source, in CaptureZone captureZone)
|
||||||
|
{
|
||||||
|
int width = captureZone.Width;
|
||||||
|
int height = captureZone.Height;
|
||||||
|
Span<byte> destination = captureZone.Buffer.AsSpan();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
int offset = ((y * width) + x) * BPP;
|
||||||
|
int destinationOffset = ((x * height) + ((height - 1) - y)) * BPP;
|
||||||
|
destination[destinationOffset] = source[offset];
|
||||||
|
destination[destinationOffset + 1] = source[offset + 1];
|
||||||
|
destination[destinationOffset + 2] = source[offset + 2];
|
||||||
|
destination[destinationOffset + 3] = source[offset + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void CopyRotate180(in Span<byte> source, in CaptureZone captureZone)
|
||||||
|
{
|
||||||
|
int width = captureZone.Width;
|
||||||
|
int height = captureZone.Height;
|
||||||
|
Span<byte> destination = captureZone.Buffer.AsSpan();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
int offset = ((y * width) + x) * BPP;
|
||||||
|
int destinationOffset = destination.Length - offset;
|
||||||
|
destination[destinationOffset - 4] = source[offset];
|
||||||
|
destination[destinationOffset - 3] = source[offset + 1];
|
||||||
|
destination[destinationOffset - 2] = source[offset + 2];
|
||||||
|
destination[destinationOffset - 1] = source[offset + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void CopyRotate270(in Span<byte> source, in CaptureZone captureZone)
|
||||||
|
{
|
||||||
|
int width = captureZone.Width;
|
||||||
|
int height = captureZone.Height;
|
||||||
|
Span<byte> destination = captureZone.Buffer.AsSpan();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
int offset = ((y * width) + x) * BPP;
|
||||||
|
int destinationOffset = ((((width - 1) - x) * height) + y) * BPP;
|
||||||
|
destination[destinationOffset] = source[offset];
|
||||||
|
destination[destinationOffset + 1] = source[offset + 1];
|
||||||
|
destination[destinationOffset + 2] = source[offset + 2];
|
||||||
|
destination[destinationOffset + 3] = source[offset + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CaptureZone RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
|
public CaptureZone RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
|
||||||
{
|
{
|
||||||
ValidateCaptureZoneAndThrow(x, y, width, height);
|
ValidateCaptureZoneAndThrow(x, y, width, height);
|
||||||
|
|
||||||
|
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
|
||||||
|
(x, y, width, height) = (y, x, height, width);
|
||||||
|
|
||||||
int unscaledWidth = width;
|
int unscaledWidth = width;
|
||||||
int unscaledHeight = height;
|
int unscaledHeight = height;
|
||||||
(width, height) = CalculateScaledSize(unscaledWidth, unscaledHeight, downscaleLevel);
|
(width, height) = CalculateScaledSize(unscaledWidth, unscaledHeight, downscaleLevel);
|
||||||
@ -252,6 +328,9 @@ public sealed class DX11ScreenCapture : IScreenCapture
|
|||||||
|
|
||||||
ValidateCaptureZoneAndThrow(newX, newY, newUnscaledWidth, newUnscaledHeight);
|
ValidateCaptureZoneAndThrow(newX, newY, newUnscaledWidth, newUnscaledHeight);
|
||||||
|
|
||||||
|
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
|
||||||
|
(newX, newY, newUnscaledWidth, newUnscaledHeight) = (newY, newX, newUnscaledHeight, newUnscaledWidth);
|
||||||
|
|
||||||
captureZone.X = newX;
|
captureZone.X = newX;
|
||||||
captureZone.Y = newY;
|
captureZone.Y = newY;
|
||||||
|
|
||||||
@ -361,13 +440,18 @@ public sealed class DX11ScreenCapture : IScreenCapture
|
|||||||
_output = adapter.GetOutput(Display.Index) ?? throw new ApplicationException("Couldn't get DirectX-Output.");
|
_output = adapter.GetOutput(Display.Index) ?? throw new ApplicationException("Couldn't get DirectX-Output.");
|
||||||
using IDXGIOutput5 output = _output.QueryInterface<IDXGIOutput5>();
|
using IDXGIOutput5 output = _output.QueryInterface<IDXGIOutput5>();
|
||||||
|
|
||||||
|
int width = Display.Width;
|
||||||
|
int height = Display.Height;
|
||||||
|
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
|
||||||
|
(width, height) = (height, width);
|
||||||
|
|
||||||
Texture2DDescription captureTextureDesc = new()
|
Texture2DDescription captureTextureDesc = new()
|
||||||
{
|
{
|
||||||
CPUAccessFlags = CpuAccessFlags.None,
|
CPUAccessFlags = CpuAccessFlags.None,
|
||||||
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
|
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
|
||||||
Format = Format.B8G8R8A8_UNorm,
|
Format = Format.B8G8R8A8_UNorm,
|
||||||
Width = Display.Width,
|
Width = width,
|
||||||
Height = Display.Height,
|
Height = height,
|
||||||
MiscFlags = ResourceOptionFlags.None,
|
MiscFlags = ResourceOptionFlags.None,
|
||||||
MipLevels = 1,
|
MipLevels = 1,
|
||||||
ArraySize = 1,
|
ArraySize = 1,
|
||||||
|
|||||||
@ -53,12 +53,20 @@ public class DX11ScreenCaptureService : IScreenCaptureService
|
|||||||
{
|
{
|
||||||
int width = output.Description.DesktopCoordinates.Right - output.Description.DesktopCoordinates.Left;
|
int width = output.Description.DesktopCoordinates.Right - output.Description.DesktopCoordinates.Left;
|
||||||
int height = output.Description.DesktopCoordinates.Bottom - output.Description.DesktopCoordinates.Top;
|
int height = output.Description.DesktopCoordinates.Bottom - output.Description.DesktopCoordinates.Top;
|
||||||
yield return new Display(i, output.Description.DeviceName, width, height, graphicsCard);
|
yield return new Display(i, output.Description.DeviceName, width, height, GetRotation(output.Description.Rotation), graphicsCard);
|
||||||
output.Dispose();
|
output.Dispose();
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Rotation GetRotation(ModeRotation rotation) => rotation switch
|
||||||
|
{
|
||||||
|
ModeRotation.Rotate90 => Rotation.Rotation90,
|
||||||
|
ModeRotation.Rotate180 => Rotation.Rotation180,
|
||||||
|
ModeRotation.Rotate270 => Rotation.Rotation270,
|
||||||
|
_ => Rotation.None
|
||||||
|
};
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IScreenCapture GetScreenCapture(Display display)
|
public IScreenCapture GetScreenCapture(Display display)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -31,6 +31,11 @@ public readonly struct Display
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the rotation of the <see cref="Display"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Rotation Rotation { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.
|
/// Gets the <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -47,13 +52,15 @@ public readonly struct Display
|
|||||||
/// <param name="deviceName">The name of the <see cref="Display"/>.</param>
|
/// <param name="deviceName">The name of the <see cref="Display"/>.</param>
|
||||||
/// <param name="width">The with of the <see cref="Display"/>.</param>
|
/// <param name="width">The with of the <see cref="Display"/>.</param>
|
||||||
/// <param name="height">The height of the <see cref="Display"/>.</param>
|
/// <param name="height">The height of the <see cref="Display"/>.</param>
|
||||||
|
/// <param name="rotation">The rotation of the <see cref="Display"/>.</param>
|
||||||
/// <param name="graphicsCard">The <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.</param>
|
/// <param name="graphicsCard">The <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.</param>
|
||||||
public Display(int index, string deviceName, int width, int height, GraphicsCard graphicsCard)
|
public Display(int index, string deviceName, int width, int height, Rotation rotation, GraphicsCard graphicsCard)
|
||||||
{
|
{
|
||||||
this.Index = index;
|
this.Index = index;
|
||||||
this.DeviceName = deviceName;
|
this.DeviceName = deviceName;
|
||||||
this.Width = width;
|
this.Width = width;
|
||||||
this.Height = height;
|
this.Height = height;
|
||||||
|
this.Rotation = rotation;
|
||||||
this.GraphicsCard = graphicsCard;
|
this.GraphicsCard = graphicsCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +80,7 @@ public readonly struct Display
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int GetHashCode() => HashCode.Combine(Index, GraphicsCard);
|
public override int GetHashCode() => HashCode.Combine(Index, GraphicsCard);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether two <see cref="Display"/> are equal.
|
/// Determines whether two <see cref="Display"/> are equal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
12
ScreenCapture.NET/Model/Rotation.cs
Normal file
12
ScreenCapture.NET/Model/Rotation.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace ScreenCapture.NET;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a display-rotation.
|
||||||
|
/// </summary>
|
||||||
|
public enum Rotation
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Rotation90 = 90,
|
||||||
|
Rotation180 = 180,
|
||||||
|
Rotation270 = 270
|
||||||
|
}
|
||||||
@ -62,7 +62,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Vortice.Direct3D11" Version="2.3.0" />
|
<PackageReference Include="Vortice.Direct3D11" Version="2.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user