private void Draw() { _cl.Begin(); if (_windowResized) { _windowResized = false; _gd.ResizeMainWindow((uint)_window.Width, (uint)_window.Height); _cl.UpdateBuffer(_screenSizeBuffer, 0, new Vector4(_window.Width, _window.Height, 0, 0)); } _cl.SetPipeline(_computePipeline); _cl.SetComputeResourceSet(0, _computeResourceSet); _cl.SetComputeResourceSet(1, _computeScreenSizeResourceSet); _cl.Dispatch(1024, 1, 1); _cl.SetFramebuffer(_gd.SwapchainFramebuffer); _cl.SetFullViewports(); _cl.SetFullScissorRects(); _cl.ClearColorTarget(0, RgbaFloat.Black); _cl.SetPipeline(_graphicsPipeline); _cl.SetGraphicsResourceSet(0, _graphicsParticleResourceSet); _cl.SetGraphicsResourceSet(1, _screenSizeResourceSet); _cl.Draw(ParticleCount, 1, 0, 0); _cl.End(); _gd.ExecuteCommands(_cl); _gd.SwapBuffers(); }
private static async Task ExecuteOnGpu(GraphicsDevice device, int index, TestShader shader) { ShaderGeneratorContext context = new ShaderGeneratorContext(device); context.Visit(shader); PipelineState pipelineState = await context.CreateComputePipelineStateAsync(); DescriptorSet?descriptorSet = context.CreateShaderResourceViewDescriptorSet(); using (CommandList commandList = new CommandList(device, CommandListType.Compute)) { commandList.SetPipelineState(pipelineState); if (descriptorSet != null) { commandList.SetComputeRootDescriptorTable(0, descriptorSet); } commandList.Dispatch(1, 1, 1); await commandList.FlushAsync(); } float sum = shader.DestinationBuffer.Resource.GetArray <float>().Sum(); Console.WriteLine($"Origin: GPU, Thread: {index}, sum: {sum}."); }
protected override void Draw(float deltaSeconds) { _cl.Begin(); _ticks += deltaSeconds * 1000f; Vector4 shifts = new Vector4( _window.Width * MathF.Cos(_ticks / 500f), // Red shift _window.Height * MathF.Sin(_ticks / 1250f), // Green shift MathF.Sin(_ticks / 1000f), // Blue shift 0); // Padding _cl.UpdateBuffer(_shiftBuffer, 0, ref shifts); _cl.SetPipeline(_computePipeline); _cl.SetComputeResourceSet(0, _computeResourceSet); _cl.Dispatch((uint)_window.Width, (uint)_window.Height, 1); _cl.SetFramebuffer(_gd.SwapchainFramebuffer); _cl.SetFullViewports(); _cl.SetFullScissorRects(); _cl.ClearColorTarget(0, RgbaFloat.Black); _cl.SetPipeline(_graphicsPipeline); _cl.SetVertexBuffer(0, _vertexBuffer); _cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); _cl.SetGraphicsResourceSet(0, _graphicsResourceSet); _cl.DrawIndexed(6, 1, 0, 0, 0); _cl.End(); _gd.SubmitCommands(_cl); _gd.SwapBuffers(); }
protected override void Draw(float deltaSeconds) { if (!_initialized) { return; } _cl.Begin(); _cl.SetPipeline(_computePipeline); _cl.SetComputeResourceSet(0, _computeResourceSet); _cl.SetComputeResourceSet(1, _computeScreenSizeResourceSet); _cl.Dispatch(1024, 1, 1); _cl.SetFramebuffer(MainSwapchain.Framebuffer); _cl.SetFullViewports(); _cl.SetFullScissorRects(); _cl.ClearColorTarget(0, RgbaFloat.Black); _cl.SetPipeline(_graphicsPipeline); _cl.SetGraphicsResourceSet(0, _graphicsParticleResourceSet); _cl.SetGraphicsResourceSet(1, _screenSizeResourceSet); _cl.Draw(ParticleCount, 1, 0, 0); _cl.End(); GraphicsDevice.SubmitCommands(_cl); GraphicsDevice.SwapBuffers(MainSwapchain); }
private void DoComputeWork() { // Reuse the memory associated with command recording. // We can only reset when the associated command lists have finished execution on the GPU. DirectCmdListAlloc.Reset(); // A command list can be reset after it has been added to the command queue via ExecuteCommandList. // Reusing the command list reuses memory. CommandList.Reset(DirectCmdListAlloc, _psos["vecAdd"]); CommandList.SetComputeRootSignature(_rootSignature); CommandList.SetComputeRootShaderResourceView(0, _inputBufferA.GPUVirtualAddress); CommandList.SetComputeRootShaderResourceView(1, _inputBufferB.GPUVirtualAddress); CommandList.SetComputeRootUnorderedAccessView(2, _outputBuffer.GPUVirtualAddress); CommandList.Dispatch(1, 1, 1); // Schedule to copy the data to the default buffer to the readback buffer. CommandList.ResourceBarrierTransition(_outputBuffer, ResourceStates.Common, ResourceStates.CopySource); CommandList.CopyResource(_readBackBuffer, _outputBuffer); CommandList.ResourceBarrierTransition(_outputBuffer, ResourceStates.CopySource, ResourceStates.Common); // Done recording commands. CommandList.Close(); // Add the command list to the queue for execution. CommandQueue.ExecuteCommandList(CommandList); // Wait for the work to finish. FlushCommandQueue(); // Map the data so we can read it on CPU. var mappedData = new Data[NumDataElements]; IntPtr ptr = _readBackBuffer.Map(0); Utilities.Read(ptr, mappedData, 0, NumDataElements); using (var fstream = File.OpenWrite("results.txt")) { using (var strWriter = new StreamWriter(fstream)) { foreach (Data data in mappedData) { strWriter.WriteLine($"({data.V1.X}, {data.V1.Y}, {data.V1.Z}, {data.V2.X}, {data.V2.Y})"); } } } _readBackBuffer.Unmap(0); }
public static async Task RunAsync(GraphicsDevice device) { int count = 100; int sumCount = 10; List <Task> tasks = new List <Task>(); for (int i = 0; i < count; i++) { int index = i; Console.WriteLine($"Scheduling task {index}"); tasks.Add(Task.Run(async() => { GraphicsBuffer <float> buffer = GraphicsBuffer.Create <float>(device, sumCount, ResourceFlags.AllowUnorderedAccess); TestShader shader = new TestShader(buffer, Sigmoid); ShaderGeneratorContext context = new ShaderGeneratorContext(device); context.Visit(shader); ShaderGeneratorResult result = new ShaderGenerator(shader).GenerateShader(); PipelineState pipelineState = await context.CreateComputePipelineStateAsync(); DescriptorSet?descriptorSet = context.CreateShaderResourceViewDescriptorSet(); using (CommandList commandList = new CommandList(device, CommandListType.Compute)) { commandList.SetPipelineState(pipelineState); if (descriptorSet != null) { commandList.SetComputeRootDescriptorTable(0, descriptorSet); } commandList.Dispatch(1, 1, 1); await commandList.FlushAsync(); } float sum = buffer.GetData().Sum(); Console.WriteLine($"Thread: {index}, sum: {sum}."); })); } Console.WriteLine("Awaiting tasks..."); Console.WriteLine($"Task count: {tasks.Count}"); await Task.WhenAll(tasks); Console.WriteLine("DONE!"); }
private void RenderGPU() { _cl.UpdateBuffer(_sceneParamsBuffer, 0, ref _sceneParams); _cl.UpdateBuffer(_rayCountBuffer, 0, new Vector4()); _cl.SetPipeline(_computePipeline); _cl.SetComputeResourceSet(0, _computeSet); Debug.Assert(Width % 16 == 0 && Height % 16 == 0); uint xCount = Width / 16; uint yCount = Height / 16; _cl.Dispatch(xCount, yCount, 1); _cl.CopyBuffer(_rayCountBuffer, 0, _rayCountReadback, 0, _rayCountBuffer.SizeInBytes); }
private void RenderGpu() { commandList.UpdateBuffer(sceneParamsBuffer, 0, ref Raytracer.SceneParams); commandList.UpdateBuffer(rayCountBuffer, 0, new Vector4()); commandList.SetPipeline(computePipeline); commandList.SetComputeResourceSet(0, computeSet); Debug.Assert(Window.Width % 16 == 0 && Window.Height % 16 == 0); var xCount = (uint)Math.Ceiling(Window.Width / 16d); var yCount = (uint)Math.Ceiling(Window.Height / 16d); commandList.Dispatch(xCount, yCount, 1); commandList.CopyBuffer(rayCountBuffer, 0, rayCountReadback, 0, rayCountBuffer.SizeInBytes); Raytracer.SceneParams.FrameCount++; }
/// <summary> /// Pass the graph plot through the velocity compute shader, to adjust the node velocity based on the positions of other nodes /// </summary> /// <param name="RSetDesc">Position shader resource set</param> /// <param name="cl">Commandlist to run the commands on</param> /// <param name="plot">PlottedGraph to compute</param> /// <param name="delta">A float representing how much time has passed since the last frame. Higher values => bigger movements</param> private void RenderVelocity(ResourceSetDescription RSetDesc, CommandList cl, PlottedGraph plot, float delta) { //if (GlobalConfig.Settings.Logs.BulkLogging) Logging.RecordLogEvent($"RenderVelocity {this.EngineID}", Logging.LogFilterType.BulkDebugLogFile); _timer.Restart(); cl.Begin(); ResourceSet resourceSet = _gd.ResourceFactory.CreateResourceSet(RSetDesc); uint nodeCount = (uint)plot.RenderedNodeCount(); //if (GlobalConfig.Settings.Logs.BulkLogging) Logging.RecordLogEvent($"RenderVelocityBlocks {this.EngineID}", Logging.LogFilterType.BulkDebugLogFile); GraphLayoutState layout = plot.LayoutState; VelocityShaderParams parameters = new VelocityShaderParams { delta = delta, //not used temperature = Math.Min(plot.Temperature, GlobalConfig.MaximumNodeTemperature), repulsionK = GlobalConfig.RepulsionK, nodeCount = nodeCount }; Debug.Assert(nodeCount <= (layout.VelocitiesVRAM1 !.SizeInBytes / 16)); //if (GlobalConfig.Settings.Logs.BulkLogging) Logging.RecordLogEvent($"RenderVelocity {this.EngineID} submit", Logging.LogFilterType.BulkDebugLogFile); cl.UpdateBuffer(_velocityParamsBuffer, 0, parameters); cl.SetPipeline(_velocityComputePipeline); cl.SetComputeResourceSet(0, resourceSet); //16 == sizeof(Vector4) uint elemCount = layout.VelocitiesVRAM1 !.SizeInBytes / 16; uint grpSizeX = (uint)Math.Ceiling(elemCount / 256.0); //Console.WriteLine($"VRAM Size: {layout.VelocitiesVRAM1!.SizeInBytes}bytes, WkX: {grpSizeX}, nodeCount: {nodeCount}, bufVel4Count: {layout.VelocitiesVRAM1!.SizeInBytes/16}"); cl.Dispatch(grpSizeX, 1, 1); //_cl.Dispatch((uint)Math.Ceiling(layout.VelocitiesVRAM1!.SizeInBytes / (256.0 * 16)), 1, 1); //if (GlobalConfig.Settings.Logs.BulkLogging) Logging.RecordLogEvent($"RenderVelocity {this.EngineID} done in {watch.ElapsedMilliseconds} MS", Logging.LogFilterType.BulkDebugLogFile); cl.End(); _timer.Stop(); VelocitySetupTime = _timer.Elapsed.TotalMilliseconds; _timer.Restart(); _gd !.SubmitCommands(cl); _gd !.WaitForIdle(); _gd.DisposeWhenIdle(resourceSet); _timer.Stop(); VelocityTime = _timer.Elapsed.TotalMilliseconds; }
/// <summary> /// Dispatches the compute shader and sets the counter value, change per iteration effect parameters right before this call. /// </summary> public void DrawIteration() { if (FCompiled && drawCommandList != null && drawRenderDrawContext != null) { // Apply the effect, TODO: only update parameters here and Apply only once in Draw EffectInstance.Apply(drawRenderDrawContext.GraphicsContext); // Dispatch compute shader if (IsIndirect) { drawCommandList.DispatchIndirect(IndirectArgsBuffer, ArgsBufferAlignedByteOffset); } else { drawCommandList.Dispatch(ThreadGroupCounts.X, ThreadGroupCounts.Y, ThreadGroupCounts.Z); } } }
private static async Task ExecuteOnGpu(GraphicsDevice device, StructuredBuffer <float> sourceBufferView, WriteableStructuredBuffer <float> destinationBufferView) { bool generateWithDelegate = false; DescriptorSet descriptorSet = new DescriptorSet(device, 2); descriptorSet.AddResourceViews(destinationBufferView); descriptorSet.AddResourceViews(sourceBufferView); // Generate computer shader ShaderGenerator shaderGenerator = generateWithDelegate ? CreateShaderGeneratorWithDelegate(sourceBufferView, destinationBufferView) : CreateShaderGeneratorWithClass(); ShaderGeneratorResult result = shaderGenerator.GenerateShader(); // Compile shader byte[] shaderBytecode = ShaderCompiler.Compile(ShaderStage.ComputeShader, result.ShaderSource, result.EntryPoints["compute"]); DescriptorRange[] descriptorRanges = new DescriptorRange[] { new DescriptorRange(DescriptorRangeType.UnorderedAccessView, 1, 0), new DescriptorRange(DescriptorRangeType.ShaderResourceView, 1, 0) }; RootParameter rootParameter = new RootParameter(new RootDescriptorTable(descriptorRanges), ShaderVisibility.All); RootSignatureDescription rootSignatureDescription = new RootSignatureDescription(RootSignatureFlags.None, new[] { rootParameter }); RootSignature rootSignature = new RootSignature(device, rootSignatureDescription); PipelineState pipelineState = new PipelineState(device, rootSignature, shaderBytecode); // Execute computer shader using (CommandList commandList = new CommandList(device, CommandListType.Compute)) { commandList.SetPipelineState(pipelineState); commandList.SetComputeRootDescriptorTable(0, descriptorSet); commandList.Dispatch(1, 1, 1); await commandList.FlushAsync(); } }
private void Draw() { _cl.Begin(); if (_windowResized) { _windowResized = false; _gd.ResizeMainWindow((uint)_window.Width, (uint)_window.Height); _cl.UpdateBuffer(_screenSizeBuffer, 0, new Vector4(_window.Width, _window.Height, 0, 0)); CreateWindowSizedResources(); } int ticks = Environment.TickCount; Vector4 shifts = new Vector4( _window.Width * MathF.Cos(ticks / 500f), // Red shift _window.Height * MathF.Sin(ticks / 1250f), // Green shift MathF.Sin(ticks / 1000f), // Blue shift 0); // Padding _cl.UpdateBuffer(_shiftBuffer, 0, ref shifts); _cl.SetPipeline(_computePipeline); _cl.SetComputeResourceSet(0, _computeResourceSet); _cl.Dispatch((uint)_window.Width, (uint)_window.Height, 1); _cl.SetFramebuffer(_gd.SwapchainFramebuffer); _cl.SetFullViewports(); _cl.SetFullScissorRects(); _cl.ClearColorTarget(0, RgbaFloat.Black); _cl.SetPipeline(_graphicsPipeline); _cl.SetVertexBuffer(0, _vertexBuffer); _cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); _cl.SetGraphicsResourceSet(0, _graphicsResourceSet); _cl.DrawIndexed(6, 1, 0, 0, 0); _cl.End(); _gd.ExecuteCommands(_cl); _gd.SwapBuffers(); }
/// <summary> /// Executes the specified test. /// </summary> /// <param name="generationResult">The generation result.</param> /// <param name="csFunctionName">Name of the cs function.</param> /// <param name="output">The output.</param> public void Execute( ShaderGenerationResult generationResult, string csFunctionName, ITestOutputHelper output) { if (Executed) { output.WriteLine( $"The {Name} tests have already been executed!"); return; } TestSets testSets = TestSets; Mappings mappings = testSets.Mappings; if (ToolChain == null) { /* * Generate the test data and the result set data for the CPU. */ AllocateResults(output); using (new TestTimer(output, $"Running {testSets.TestLoops} iterations on the {Name} backend")) { for (int test = 0; test < testSets.TestLoops; test++) { foreach (MethodMap method in mappings.MethodMaps) { method.ExecuteCPU(TestSets.TestData, Results, test); } } return; } } GeneratedShaderSet set; CompileResult compilationResult; // Compile shader for this backend. using (new TestTimer(output, $"Compiling Compute Shader for {ToolChain.GraphicsBackend}")) { set = generationResult.GetOutput(Backend).Single(); compilationResult = ToolChain.Compile(set.ComputeShaderCode, Stage.Compute, set.ComputeFunction.Name); } if (compilationResult.HasError) { output.WriteLine($"Failed to compile Compute Shader from set \"{set.Name}\"!"); output.WriteLine(compilationResult.ToString()); return; } Assert.NotNull(compilationResult.CompiledOutput); using (GraphicsDevice graphicsDevice = ToolChain.CreateHeadless()) { if (!graphicsDevice.Features.ComputeShader) { output.WriteLine( $"The {ToolChain.GraphicsBackend} backend does not support compute shaders, skipping!"); return; } ResourceFactory factory = graphicsDevice.ResourceFactory; using (DeviceBuffer inOutBuffer = factory.CreateBuffer( new BufferDescription( (uint)mappings.BufferSize, BufferUsage.StructuredBufferReadWrite, (uint)mappings.StructSize))) using (Shader computeShader = factory.CreateShader( new ShaderDescription( ShaderStages.Compute, compilationResult.CompiledOutput, csFunctionName))) using (ResourceLayout inOutStorageLayout = factory.CreateResourceLayout( new ResourceLayoutDescription( new ResourceLayoutElementDescription("InOutBuffer", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute)))) using (Pipeline computePipeline = factory.CreateComputePipeline(new ComputePipelineDescription( computeShader, new[] { inOutStorageLayout }, 1, 1, 1))) using (ResourceSet computeResourceSet = factory.CreateResourceSet( new ResourceSetDescription(inOutStorageLayout, inOutBuffer))) using (CommandList commandList = factory.CreateCommandList()) { // Ensure the headless graphics device is the backend we expect. Assert.Equal(ToolChain.GraphicsBackend, graphicsDevice.BackendType); output.WriteLine($"Created compute pipeline for {Name} backend."); // Allocate the results buffer AllocateResults(output); using (new TestTimer(output, $"Running {testSets.TestLoops} iterations on the {Name} backend")) { // Loop for each test for (int test = 0; test < testSets.TestLoops; test++) { // Update parameter buffer graphicsDevice.UpdateBuffer( inOutBuffer, 0, // Get the portion of test data for the current test loop Marshal.UnsafeAddrOfPinnedArrayElement(testSets.TestData, mappings.BufferSize * test), (uint)mappings.BufferSize); graphicsDevice.WaitForIdle(); // Execute compute shaders commandList.Begin(); commandList.SetPipeline(computePipeline); commandList.SetComputeResourceSet(0, computeResourceSet); commandList.Dispatch((uint)mappings.Methods, 1, 1); commandList.End(); graphicsDevice.SubmitCommands(commandList); graphicsDevice.WaitForIdle(); // Read back parameters using a staging buffer using (DeviceBuffer stagingBuffer = factory.CreateBuffer( new BufferDescription(inOutBuffer.SizeInBytes, BufferUsage.Staging))) { commandList.Begin(); commandList.CopyBuffer(inOutBuffer, 0, stagingBuffer, 0, stagingBuffer.SizeInBytes); commandList.End(); graphicsDevice.SubmitCommands(commandList); graphicsDevice.WaitForIdle(); // Read back test results MappedResource map = graphicsDevice.Map(stagingBuffer, MapMode.Read); mappings.SetResults(map.Data, Results, test); graphicsDevice.Unmap(stagingBuffer); } } } } } }
public void FillBuffer_WithOffsets(uint srcSetMultiple, uint srcBindingMultiple, uint dstSetMultiple, uint dstBindingMultiple, bool combinedLayout) { if (!GD.Features.ComputeShader) { return; } Debug.Assert((GD.StructuredBufferMinOffsetAlignment % sizeof(uint)) == 0); uint valueCount = 512; uint dataSize = valueCount * sizeof(uint); uint totalSrcAlignment = GD.StructuredBufferMinOffsetAlignment * (srcSetMultiple + srcBindingMultiple); uint totalDstAlignment = GD.StructuredBufferMinOffsetAlignment * (dstSetMultiple + dstBindingMultiple); DeviceBuffer copySrc = RF.CreateBuffer( new BufferDescription(totalSrcAlignment + dataSize, BufferUsage.StructuredBufferReadOnly, sizeof(uint))); DeviceBuffer copyDst = RF.CreateBuffer( new BufferDescription(totalDstAlignment + dataSize, BufferUsage.StructuredBufferReadWrite, sizeof(uint))); ResourceLayout[] layouts; ResourceSet[] sets; DeviceBufferRange srcRange = new DeviceBufferRange(copySrc, srcSetMultiple * GD.StructuredBufferMinOffsetAlignment, dataSize); DeviceBufferRange dstRange = new DeviceBufferRange(copyDst, dstSetMultiple * GD.StructuredBufferMinOffsetAlignment, dataSize); if (combinedLayout) { layouts = new[] { RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopySrc", ResourceKind.StructuredBufferReadOnly, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding), new ResourceLayoutElementDescription( "CopyDst", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))) }; sets = new[] { RF.CreateResourceSet(new ResourceSetDescription(layouts[0], srcRange, dstRange)) }; } else { layouts = new[] { RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopySrc", ResourceKind.StructuredBufferReadOnly, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))), RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription( "CopyDst", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute, ResourceLayoutElementOptions.DynamicBinding))) }; sets = new[] { RF.CreateResourceSet(new ResourceSetDescription(layouts[0], srcRange)), RF.CreateResourceSet(new ResourceSetDescription(layouts[1], dstRange)), }; } Pipeline pipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, combinedLayout ? "FillBuffer" : "FillBuffer_SeparateLayout"), layouts, 1, 1, 1)); uint[] srcData = Enumerable.Range(0, (int)copySrc.SizeInBytes / sizeof(uint)).Select(i => (uint)i).ToArray(); GD.UpdateBuffer(copySrc, 0, srcData); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(pipeline); if (combinedLayout) { uint[] offsets = new[] { srcBindingMultiple *GD.StructuredBufferMinOffsetAlignment, dstBindingMultiple *GD.StructuredBufferMinOffsetAlignment }; cl.SetComputeResourceSet(0, sets[0], offsets); } else { uint offset = srcBindingMultiple * GD.StructuredBufferMinOffsetAlignment; cl.SetComputeResourceSet(0, sets[0], 1, ref offset); offset = dstBindingMultiple * GD.StructuredBufferMinOffsetAlignment; cl.SetComputeResourceSet(1, sets[1], 1, ref offset); } cl.Dispatch(512, 1, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer readback = GetReadback(copyDst); MappedResourceView <uint> readView = GD.Map <uint>(readback, MapMode.Read); for (uint i = 0; i < valueCount; i++) { uint srcIndex = totalSrcAlignment / sizeof(uint) + i; uint expected = srcData[(int)srcIndex]; uint dstIndex = totalDstAlignment / sizeof(uint) + i; uint actual = readView[dstIndex]; Assert.Equal(expected, actual); } GD.Unmap(readback); }
public void BasicCompute() { if (!GD.Features.ComputeShader) { return; } ResourceLayout layout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Params", ResourceKind.UniformBuffer, ShaderStages.Compute), new ResourceLayoutElementDescription("Source", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute), new ResourceLayoutElementDescription("Destination", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute))); uint width = 1024; uint height = 1024; DeviceBuffer paramsBuffer = RF.CreateBuffer(new BufferDescription((uint)Unsafe.SizeOf <BasicComputeTestParams>(), BufferUsage.UniformBuffer)); DeviceBuffer sourceBuffer = RF.CreateBuffer(new BufferDescription(width * height * 4, BufferUsage.StructuredBufferReadWrite, 4)); DeviceBuffer destinationBuffer = RF.CreateBuffer(new BufferDescription(width * height * 4, BufferUsage.StructuredBufferReadWrite, 4)); GD.UpdateBuffer(paramsBuffer, 0, new BasicComputeTestParams { Width = width, Height = height }); float[] sourceData = new float[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = y * (int)width + x; sourceData[index] = index; } } GD.UpdateBuffer(sourceBuffer, 0, sourceData); ResourceSet rs = RF.CreateResourceSet(new ResourceSetDescription(layout, paramsBuffer, sourceBuffer, destinationBuffer)); Pipeline pipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "BasicComputeTest"), layout, 16, 16, 1)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(pipeline); cl.SetComputeResourceSet(0, rs); cl.Dispatch(width / 16, width / 16, 1); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); DeviceBuffer sourceReadback = GetReadback(sourceBuffer); DeviceBuffer destinationReadback = GetReadback(destinationBuffer); MappedResourceView <float> sourceReadView = GD.Map <float>(sourceReadback, MapMode.Read); MappedResourceView <float> destinationReadView = GD.Map <float>(destinationReadback, MapMode.Read); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = y * (int)width + x; Assert.Equal(2 * sourceData[index], sourceReadView[index]); Assert.Equal(sourceData[index], destinationReadView[index]); } } GD.Unmap(sourceReadback); GD.Unmap(destinationReadback); }
public void ComputeShader3dTexture() { // Just a dumb compute shader that fills a 3D texture with the same value from a uniform multiplied by the depth. string shaderText = @" #version 450 layout(set = 0, binding = 0, rgba32f) uniform image3D TextureToFill; layout(set = 0, binding = 1) uniform FillValueBuffer { float FillValue; float Padding1; float Padding2; float Padding3; }; layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; void main() { ivec3 textureCoordinate = ivec3(gl_GlobalInvocationID.xyz); float dataToStore = FillValue * (textureCoordinate.z + 1); imageStore(TextureToFill, textureCoordinate, vec4(dataToStore)); } "; const float FillValue = 42.42f; const uint OutputTextureSize = 32; using Shader computeShader = RF.CreateFromSpirv(new ShaderDescription( ShaderStages.Compute, Encoding.ASCII.GetBytes(shaderText), "main")); using ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("TextureToFill", ResourceKind.TextureReadWrite, ShaderStages.Compute), new ResourceLayoutElementDescription("FillValueBuffer", ResourceKind.UniformBuffer, ShaderStages.Compute))); using Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( computeShader, computeLayout, 16, 16, 1)); using DeviceBuffer fillValueBuffer = RF.CreateBuffer(new BufferDescription((uint)Marshal.SizeOf <FillValueStruct>(), BufferUsage.UniformBuffer)); // Create our output texture. using Texture computeTargetTexture = RF.CreateTexture(TextureDescription.Texture3D( OutputTextureSize, OutputTextureSize, OutputTextureSize, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled | TextureUsage.Storage)); using TextureView computeTargetTextureView = RF.CreateTextureView(computeTargetTexture); using ResourceSet computeResourceSet = RF.CreateResourceSet(new ResourceSetDescription( computeLayout, computeTargetTextureView, fillValueBuffer)); using CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.UpdateBuffer(fillValueBuffer, 0, new FillValueStruct(FillValue)); // Use the compute shader to fill the texture. cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeResourceSet); const uint GroupDivisorXY = 16; cl.Dispatch(OutputTextureSize / GroupDivisorXY, OutputTextureSize / GroupDivisorXY, OutputTextureSize); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); // Read back from our texture and make sure it has been properly filled. for (uint depth = 0; depth < computeTargetTexture.Depth; depth++) { RgbaFloat expectedFillValue = new RgbaFloat(new System.Numerics.Vector4(FillValue * (depth + 1))); int notFilledCount = CountTexelsNotFilledAtDepth(GD, computeTargetTexture, expectedFillValue, depth); if (notFilledCount == 0) { // Expected behavior: Console.WriteLine($"All texels were properly set at depth {depth}"); } else { // Unexpected behavior: uint totalTexels = computeTargetTexture.Width * computeTargetTexture.Height; throw new Exception($"{notFilledCount} of {totalTexels} texels were not properly set at depth {depth}"); } } }
private static async Task Main() { // Create graphics device using GraphicsDevice device = new GraphicsDevice(FeatureLevel.Level11_0); // Create graphics buffer int width = 10; int height = 10; float[] array = new float[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = i; } float[] outputArray = new float[width * height]; using GraphicsBuffer <float> sourceBuffer = GraphicsBuffer.ShaderResource.New(device, array.AsSpan()); using GraphicsBuffer <float> destinationBuffer = GraphicsBuffer.UnorderedAccess.New <float>(device, array.Length * 2); GraphicsBuffer <float> slicedDestinationBuffer = destinationBuffer.Slice(20, 60); slicedDestinationBuffer = slicedDestinationBuffer.Slice(10, 50); DescriptorSet descriptorSet = new DescriptorSet(device, 2); descriptorSet.AddUnorderedAccessViews(slicedDestinationBuffer); descriptorSet.AddShaderResourceViews(sourceBuffer); // Generate computer shader bool generateWithDelegate = true; ShaderGenerator shaderGenerator = generateWithDelegate ? CreateShaderGeneratorWithDelegate(sourceBuffer, destinationBuffer) : CreateShaderGeneratorWithClass(); ShaderGeneratorResult result = shaderGenerator.GenerateShader(); // Copmile shader byte[] shaderBytecode = ShaderCompiler.Compile(DxcShaderStage.ComputeShader, result.ShaderSource, result.EntryPoints["compute"]); DescriptorRange1[] descriptorRanges = new DescriptorRange1[] { new DescriptorRange1(DescriptorRangeType.UnorderedAccessView, 1, 0), new DescriptorRange1(DescriptorRangeType.ShaderResourceView, 1, 0) }; RootParameter1 rootParameter = new RootParameter1(new RootDescriptorTable1(descriptorRanges), ShaderVisibility.All); var rootSignatureDescription = new VersionedRootSignatureDescription(new RootSignatureDescription1(RootSignatureFlags.None, new[] { rootParameter })); var rootSignature = device.CreateRootSignature(rootSignatureDescription); PipelineState pipelineState = new PipelineState(device, rootSignature, shaderBytecode); // Execute computer shader using (CommandList commandList = new CommandList(device, CommandListType.Compute)) { commandList.SetPipelineState(pipelineState); commandList.SetComputeRootDescriptorTable(0, descriptorSet); commandList.Dispatch(1, 1, 1); await commandList.FlushAsync(); } // Print matrix Console.WriteLine("Before:"); PrintMatrix(array, width, height); destinationBuffer.GetData(outputArray.AsSpan()); Console.WriteLine(); Console.WriteLine("After:"); PrintMatrix(outputArray, width, height); }
public void Dispatch(CommandList cl, uint x, uint y, uint z) { cl.SetPipeline(Pipeline); cl.SetComputeResourceSet(0, ResourceSet); cl.Dispatch(x, y, z); }
/// <summary> /// Update the node attributes compute VRAM buffer (alpha, node size, mouseover details) /// </summary> /// <param name="cl">Thread-specific CommandList</param> /// <param name="graph">ProtoGraph being drawn</param> /// <param name="inputAttributes">Attributes buffer being updated</param> /// <param name="resources">Shader resources ResourceSet</param> /// <param name="delta">Time-delta from the last update</param> /// <param name="mouseoverNodeID">Index of the node the mouse is over</param> /// <param name="useAnimAttribs">Flag to specify the graph is in animated-alpha mode</param> private unsafe void RenderNodeAttribs(CommandList cl, PlottedGraph graph, DeviceBuffer inputAttributes, ResourceSet resources, float delta, int mouseoverNodeID, bool useAnimAttribs) { if (GlobalConfig.Settings.Logs.BulkLogging) { Logging.RecordLogEvent($"RenderNodeAttribs {this.EngineID}", Logging.LogFilterType.BulkDebugLogFile); } AttribShaderParams parms = new AttribShaderParams { delta = delta, hoveredNodeID = mouseoverNodeID, nodeCount = (uint)Math.Min(graph.RenderedNodeCount(), graph.LayoutState.AttributesVRAM1 !.SizeInBytes / 16), MinimumAlpha = GlobalConfig.AnimatedFadeMinimumAlpha, hoverMode = (mouseoverNodeID != -1) ? 1 : 0, isAnimated = useAnimAttribs ? 1: 0 }; graph.GetActiveNodeIndexes(out List <uint> pulseNodes, out List <uint> lingerNodes, out uint[] deactivatedNodes); if (GlobalConfig.Settings.Logs.BulkLogging) { Logging.RecordLogEvent($"RenderNodeAttribs {this.EngineID} updating attribsbuf {inputAttributes.Name}", Logging.LogFilterType.BulkDebugLogFile); } cl.UpdateBuffer(_attribsParamsBuffer, 0, parms); float currentPulseAlpha = Math.Max(GlobalConfig.AnimatedFadeMinimumAlpha, GraphicsMaths.getPulseAlpha()); //todo - merge contiguous regions to reduce command count float[] valArray = new float[3]; foreach (uint idx in pulseNodes) { if (idx >= graph.RenderedNodeCount()) { break; } if (inputAttributes.SizeInBytes <= idx * 4 * sizeof(float) + (2 * sizeof(float))) { break; } valArray[0] = GlobalConfig.NodeSize; //start big valArray[1] = 1.0f; //full alpha valArray[2] = 1.0f; //pulse fixed(float *dataPtr = valArray) { Debug.Assert((idx * 4 * sizeof(float) + valArray.Length * sizeof(float)) < inputAttributes.SizeInBytes); cl.UpdateBuffer(inputAttributes, idx * 4 * sizeof(float), (IntPtr)dataPtr, (uint)valArray.Length * sizeof(float)); } } //make the active node pulse if (graph.IsAnimated) { uint activeNodeIdx = graph.LastAnimatedVert; if (!lingerNodes.Contains(activeNodeIdx)) { valArray[0] = currentPulseAlpha; fixed(float *dataPtr = valArray) { uint nodeAlphaOffset = (activeNodeIdx * 4 * sizeof(float)) + (2 * sizeof(float)); if (nodeAlphaOffset + sizeof(float) <= inputAttributes.SizeInBytes) { cl.UpdateBuffer(inputAttributes, nodeAlphaOffset, (IntPtr)dataPtr, sizeof(float)); } } } } foreach (uint idx in lingerNodes) { if (idx >= graph.RenderedNodeCount()) { break; } if (inputAttributes.SizeInBytes <= idx * 4 * sizeof(float) + (2 * sizeof(float))) { break; } valArray[0] = 2.0f + currentPulseAlpha; fixed(float *dataPtr = valArray) { Debug.Assert((idx * 4 * sizeof(float) + (2 * sizeof(float)) + sizeof(float)) < inputAttributes.SizeInBytes); cl.UpdateBuffer(inputAttributes, idx * 4 * sizeof(float) + (2 * sizeof(float)), (IntPtr)dataPtr, sizeof(float)); } } foreach (uint idx in deactivatedNodes) { if (idx >= graph.RenderedNodeCount()) { break; } if (inputAttributes.SizeInBytes <= idx * 4 * sizeof(float) + (2 * sizeof(float))) { break; } valArray[0] = 0.8f; fixed(float *dataPtr = valArray) { Debug.Assert((idx * 4 * sizeof(float) + (2 * sizeof(float)) + sizeof(float)) < inputAttributes.SizeInBytes); cl.UpdateBuffer(inputAttributes, idx * 4 * sizeof(float) + (2 * sizeof(float)), (IntPtr)dataPtr, sizeof(float)); } } if (graph.HighlightsChanged) { ApplyHighlightAttributes(cl, graph, inputAttributes); } cl.SetPipeline(_nodeAttribComputePipeline); cl.SetComputeResourceSet(0, resources); cl.Dispatch((uint)Math.Ceiling(inputAttributes.SizeInBytes / (256.0 * sizeof(Vector4))), 1, 1); }
public void ComputeGeneratedTexture() { if (!GD.Features.ComputeShader) { return; } uint width = 4; uint height = 1; TextureDescription texDesc = TextureDescription.Texture2D( width, height, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.Sampled | TextureUsage.Storage); Texture computeOutput = RF.CreateTexture(texDesc); texDesc.Usage = TextureUsage.RenderTarget; Texture finalOutput = RF.CreateTexture(texDesc); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, finalOutput)); ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("ComputeOutput", ResourceKind.TextureReadWrite, ShaderStages.Compute))); ResourceSet computeSet = RF.CreateResourceSet(new ResourceSetDescription(computeLayout, computeOutput)); Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "ComputeTextureGenerator"), computeLayout, 4, 1, 1)); ResourceLayout graphicsLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("Input", ResourceKind.TextureReadOnly, ShaderStages.Fragment), new ResourceLayoutElementDescription("InputSampler", ResourceKind.Sampler, ShaderStages.Fragment))); ResourceSet graphicsSet = RF.CreateResourceSet(new ResourceSetDescription(graphicsLayout, computeOutput, GD.PointSampler)); Pipeline graphicsPipeline = RF.CreateGraphicsPipeline(new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.CullNone, PrimitiveTopology.TriangleStrip, new ShaderSetDescription( Array.Empty <VertexLayoutDescription>(), TestShaders.LoadVertexFragment(RF, "FullScreenBlit")), graphicsLayout, framebuffer.OutputDescription)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeSet); cl.Dispatch(1, 1, 1); cl.SetFramebuffer(framebuffer); cl.ClearColorTarget(0, new RgbaFloat()); cl.SetPipeline(graphicsPipeline); cl.SetGraphicsResourceSet(0, graphicsSet); cl.Draw(4); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); Texture readback = GetReadback(finalOutput); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(readback, MapMode.Read); Assert.Equal(RgbaFloat.Red, readView[0, 0]); Assert.Equal(RgbaFloat.Green, readView[1, 0]); Assert.Equal(RgbaFloat.Blue, readView[2, 0]); Assert.Equal(RgbaFloat.White, readView[3, 0]); GD.Unmap(readback); }
public void ComputeGeneratedVertices() { if (!GD.Features.ComputeShader) { return; } uint width = 512; uint height = 512; Texture output = RF.CreateTexture( TextureDescription.Texture2D(width, height, 1, 1, PixelFormat.R32_G32_B32_A32_Float, TextureUsage.RenderTarget)); Framebuffer framebuffer = RF.CreateFramebuffer(new FramebufferDescription(null, output)); uint vertexSize = (uint)Unsafe.SizeOf <ColoredVertex>(); DeviceBuffer buffer = RF.CreateBuffer(new BufferDescription( vertexSize * 4, BufferUsage.StructuredBufferReadWrite, vertexSize, true)); ResourceLayout computeLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("OutputVertices", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute))); ResourceSet computeSet = RF.CreateResourceSet(new ResourceSetDescription(computeLayout, buffer)); Pipeline computePipeline = RF.CreateComputePipeline(new ComputePipelineDescription( TestShaders.LoadCompute(RF, "ComputeColoredQuadGenerator"), computeLayout, 1, 1, 1)); ResourceLayout graphicsLayout = RF.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("InputVertices", ResourceKind.StructuredBufferReadOnly, ShaderStages.Vertex))); ResourceSet graphicsSet = RF.CreateResourceSet(new ResourceSetDescription(graphicsLayout, buffer)); Pipeline graphicsPipeline = RF.CreateGraphicsPipeline(new GraphicsPipelineDescription( BlendStateDescription.SingleOverrideBlend, DepthStencilStateDescription.Disabled, RasterizerStateDescription.Default, PrimitiveTopology.TriangleStrip, new ShaderSetDescription( Array.Empty <VertexLayoutDescription>(), TestShaders.LoadVertexFragment(RF, "ColoredQuadRenderer")), graphicsLayout, framebuffer.OutputDescription)); CommandList cl = RF.CreateCommandList(); cl.Begin(); cl.SetPipeline(computePipeline); cl.SetComputeResourceSet(0, computeSet); cl.Dispatch(1, 1, 1); cl.SetFramebuffer(framebuffer); cl.ClearColorTarget(0, new RgbaFloat()); cl.SetPipeline(graphicsPipeline); cl.SetGraphicsResourceSet(0, graphicsSet); cl.Draw(4); cl.End(); GD.SubmitCommands(cl); GD.WaitForIdle(); Texture readback = GetReadback(output); MappedResourceView <RgbaFloat> readView = GD.Map <RgbaFloat>(readback, MapMode.Read); for (uint y = 0; y < height; y++) { for (uint x = 0; x < width; x++) { Assert.Equal(RgbaFloat.Red, readView[x, y]); } } GD.Unmap(readback); }
void ILowLevelAPIRender.Draw(RenderContext renderContext, RenderDrawContext drawContext, RenderView renderView, RenderViewStage renderViewStage, CommandList commandList) { if (!enabledPin.Value) { return; } try { var pipelineState = this.pipelineState ?? (this.pipelineState = new MutablePipelineState(renderContext.GraphicsDevice)); // TODO1: PerFrame could be done in Update if we'd have access to frame time // TODO2: This code can be optimized by using parameter accessors and not parameter keys parameters.SetPerFrameParameters(perFrameParams, drawContext.RenderContext); parameters.SetPerViewParameters(perViewParams, renderView); if (worldPin != null) { var world = worldPin.ShaderValue; parameters.SetPerDrawParameters(perDrawParams, renderView, ref world); } // Set permutation parameters before updating the effect (needed by compiler) parameters.Set(ComputeEffectShaderKeys.ThreadNumbers, threadNumbersPin.Value); // Give user chance to override parameterSetterPin?.Value.Invoke(parameters, renderView, drawContext); if (instance.UpdateEffect(renderContext.GraphicsDevice) || pipelineStateDirty) { threadGroupCountAccessor = parameters.GetAccessor(ComputeShaderBaseKeys.ThreadGroupCountGlobal); foreach (var p in Inputs.OfType <ParameterPin>()) { p.Update(parameters); } pipelineState.State.SetDefaults(); pipelineState.State.RootSignature = instance.RootSignature; pipelineState.State.EffectBytecode = instance.Effect.Bytecode; pipelineState.Update(); pipelineStateDirty = false; } // Apply pipeline state commandList.SetPipelineState(pipelineState.CurrentState); // Set thread group count as provided by input pin var threadGroupCount = dispatchCountPin.Value; parameters.Set(ComputeShaderBaseKeys.ThreadGroupCountGlobal, threadGroupCount); // TODO: This can be optimized by uploading only parameters from the PerDispatch groups - look in Xenkos RootEffectRenderFeature var iterationCount = Math.Max(iterationCountPin.Value, 1); for (int i = 0; i < iterationCount; i++) { // Give user chance to override iterationParameterSetterPin.Value?.Invoke(parameters, renderView, drawContext, i); // The thread group count can be set for each dispatch threadGroupCount = parameters.Get(threadGroupCountAccessor); // Upload the parameters instance.Apply(drawContext.GraphicsContext); // Draw a full screen quad commandList.Dispatch(threadGroupCount.X, threadGroupCount.Y, threadGroupCount.Z); } } catch (Exception e) { var re = new RuntimeException(e.InnermostException(), this); RuntimeGraph.ReportException(re); } }