-
-
Notifications
You must be signed in to change notification settings - Fork 138
Open
Labels
question ❓Further information is requestedFurther information is requesteduntriaged 🧰A new issue that needs initial triageA new issue that needs initial triage
Description
I'm trying to create a compute shader to identify the bounding box of dirty regions between two CanvasBitmaps, because Direct3D11CaptureFrame objects don't receive dirty regions in Windows10 and Win11 prior to build 26100. I have the following code sketched out, but am getting a COM exception early on. Any tips/advice?
public partial class TextureDiffer {
private static GraphicsDevice gpu = GraphicsDevice.GetDefault();
public static RectInt32 GetDirtyPixelRegion(CanvasBitmap beforeBitmap, CanvasBitmap afterBitmap) {
int length = (int)(beforeBitmap.SizeInPixels.Width * beforeBitmap.SizeInPixels.Height * 4);
// Copy pixel data from CanvasBitmaps into buffers
// NOTE: this is unfortunately copying data out of GPU to CPU, only for us to copy back to GPU
// It would be so much nicer if we just wrap a CanvasBitmap or CanvasRenderTarget and directly access the texture
var beforeSpan = new ReadOnlySpan<byte>(beforeBitmap.GetPixelBytes());
var afterSpan = new ReadOnlySpan<byte>(afterBitmap.GetPixelBytes());
// vvvvvvvvvvvvvvvvvvvv the issue starts here for me
// the following line throws a 'System.ComponentModel.Win32Exception' in ComputeSharp.Core.dll error
using (var beforeFrameBuffer = gpu.LoadReadOnlyTexture2D<Rgba32, float4>(beforeSpan))
using (var afterFrameBuffer = gpu.LoadReadOnlyTexture2D<Rgba32, float4>(afterSpan)) {
// the above lines throw a 'System.ComponentModel.Win32Exception' in ComputeSharp.Core.dll error
// Create an output buffer to store the min/max dirty rectangle
using var resultBuffer = gpu.AllocateReadWriteBuffer<int>(4); // minX, minY, maxX, maxY
resultBuffer[0] = int.MaxValue;
resultBuffer[1] = int.MaxValue;
// Launch the shader to compare the two frames
gpu.For(
resultBuffer.Length,
new GetDirtyRects(length, beforeFrameBuffer, afterFrameBuffer, resultBuffer));
// Read the result buffer (minX, minY, maxX, maxY)
var resultsArray = resultBuffer;
var mbr = new {
minX = resultsArray[0],
minY = resultsArray[1],
maxX = resultsArray[2],
maxY = resultsArray[3]
};
// Return the dirty region as a Rect
return new RectInt32 {
X = mbr.minX,
Y = mbr.minY,
Width = mbr.maxX - mbr.minX,
Height = mbr.maxY - mbr.minY
};
}
}
// Compute shader to compare two frames and find the dirty region
[ThreadGroupSize(16, 16, 1)]
[GeneratedComputeShaderDescriptor]
public readonly partial struct GetDirtyRects(
int width,
ReadOnlyTexture2D<Rgba32, float4> beforeBuffer,
ReadOnlyTexture2D<Rgba32, float4> afterBuffer,
ReadWriteBuffer<int> resultBuffer
) : IComputeShader {
public void Execute() {
int index = ThreadIds.X + (ThreadIds.Y * width);
float4 before = beforeBuffer[ThreadIds.XY].RGBA;
float4 after = afterBuffer[ThreadIds.XY].RGBA;
// Compare the before and after pixels
if (before.R != after.R || before.G != after.G || before.B != after.B || before.A != after.A) {
// Update min/max bounding rectangle using atomic operations
Hlsl.InterlockedMin(ref resultBuffer[0], ThreadIds.X); // Update minX
Hlsl.InterlockedMin(ref resultBuffer[1], ThreadIds.Y); // Update minY
Hlsl.InterlockedMax(ref resultBuffer[2], ThreadIds.X); // Update maxX
Hlsl.InterlockedMax(ref resultBuffer[3], ThreadIds.Y); // Update maxY
}
}
}
}
Metadata
Metadata
Assignees
Labels
question ❓Further information is requestedFurther information is requesteduntriaged 🧰A new issue that needs initial triageA new issue that needs initial triage