Compute Shader to identify dirty regions of a CanvasBitmap
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Bug
- Clarity
- Needs clarification
- Activity status
- Stale
- Tech stack
- csharp
- Domain
- computer-graphics
Research direction
Start at GetDirtyPixelRegion and the LoadReadOnlyTexture2D calls where the COM exception is reported, then inspect the GetDirtyRects shader entry point and its texture and buffer inputs. Reproduce the exception and verify that the two bitmap inputs can be loaded and compared successfully, with the resulting buffer representing the dirty bounding region.
Written by the indexing model from the issue text.
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
}
}
}
}
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 148
- Avg merge
- 4h 32m
- Merged PRs (30d)
- 3
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Sergio0694/ComputeSharp
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Sergio0694/ComputeSharp#936 · 2 comments ·
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
Sergio0694/ComputeSharp#931 ·
-
D2D1: D2D.SampleInputAtOffset with a compound offset expression silently samples wrong coordinates Openbug :bug: untriaged :toolbox:
Difficulty 3/5 1-2 days Newbie friendliness 75/100
Sergio0694/ComputeSharp#929 ·
-
PIX integration Openquestion :question: untriaged :toolbox:
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Sergio0694/ComputeSharp#926 ·
-
CopyToAsync Openproposal :bulb: untriaged :toolbox:
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Sergio0694/ComputeSharp#925 ·
All issues in Sergio0694/ComputeSharp
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100