private unsafe void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl) { uint vertexOffsetInVertices = 0; uint indexOffsetInElements = 0; if (draw_data.CmdListsCount == 0) { return; } uint totalVBSize = (uint)(draw_data.TotalVtxCount * sizeof(ImDrawVert)); if (totalVBSize > _vertexBuffer.SizeInBytes) { _vertexBuffer.Dispose(); _vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); } uint totalIBSize = (uint)(draw_data.TotalIdxCount * sizeof(ushort)); if (totalIBSize > _indexBuffer.SizeInBytes) { _indexBuffer.Dispose(); _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); } for (int i = 0; i < draw_data.CmdListsCount; i++) { ImDrawListPtr cmd_list = draw_data.CmdListsRange[i]; cl.UpdateBuffer( _vertexBuffer, vertexOffsetInVertices * (uint)sizeof(ImDrawVert), cmd_list.VtxBuffer.Data, (uint)(cmd_list.VtxBuffer.Size * sizeof(ImDrawVert))); cl.UpdateBuffer( _indexBuffer, indexOffsetInElements * sizeof(ushort), cmd_list.IdxBuffer.Data, (uint)(cmd_list.IdxBuffer.Size * sizeof(ushort))); vertexOffsetInVertices += (uint)cmd_list.VtxBuffer.Size; indexOffsetInElements += (uint)cmd_list.IdxBuffer.Size; } // Setup orthographic projection matrix into our constant buffer { var io = ImGui.GetIO(); Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( 0f, io.DisplaySize.X, io.DisplaySize.Y, 0.0f, -1.0f, 1.0f); _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); } cl.SetVertexBuffer(0, _vertexBuffer); cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); cl.SetPipeline(_pipeline); cl.SetGraphicsResourceSet(0, _mainResourceSet); draw_data.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale); // Render command lists int vtx_offset = 0; int idx_offset = 0; for (int n = 0; n < draw_data.CmdListsCount; n++) { ImDrawListPtr cmd_list = draw_data.CmdListsRange[n]; for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) { ImDrawCmdPtr pcmd = cmd_list.CmdBuffer[cmd_i]; if (pcmd.UserCallback != IntPtr.Zero) { throw new NotImplementedException(); } else { if (pcmd.TextureId != IntPtr.Zero) { if (pcmd.TextureId == _fontAtlasID) { cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); } else { cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd.TextureId)); } } cl.SetScissorRect( 0, (uint)pcmd.ClipRect.X, (uint)pcmd.ClipRect.Y, (uint)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (uint)(pcmd.ClipRect.W - pcmd.ClipRect.Y)); cl.DrawIndexed(pcmd.ElemCount, 1, (uint)idx_offset, vtx_offset, 0); } idx_offset += (int)pcmd.ElemCount; } vtx_offset += cmd_list.VtxBuffer.Size; } }
/// <summary> /// Updates a <see cref="DeviceBuffer"/> region with new data. /// This function must be used with a blittable value type <typeparamref name="T"/>. /// </summary> /// <typeparam name="T">The type of data to upload.</typeparam> /// <param name="buffer">The resource to update.</param> /// <param name="bufferOffsetInBytes">An offset, in bytes, from the beginning of the <see cref="DeviceBuffer"/> storage, at /// which new data will be uploaded.</param> /// <param name="source">The value to upload.</param> public unsafe void UpdateBuffer <T>( DeviceBuffer buffer, uint bufferOffsetInBytes, T source) where T : struct { ref byte sourceByteRef = ref Unsafe.AsRef <byte>(Unsafe.AsPointer(ref source));
private void CreateModelBuffer() { ModelBuffer = Renderer.VeldridFactory.CreateBuffer(new BufferDescription(sizeof(float) * 16, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); ModelResourceSet = Renderer.VeldridFactory.CreateResourceSet(new ResourceSetDescription(ModelResourceLayout, ModelBuffer)); }
// TODO: private protected /// <summary> /// </summary> /// <param name="indirectBuffer"></param> /// <param name="offset"></param> protected abstract void DispatchIndirectCore(DeviceBuffer indirectBuffer, uint offset);
private unsafe void RenderImDrawData(DrawData *draw_data, GraphicsDevice gd, CommandList cl) { uint vertexOffsetInVertices = 0; uint indexOffsetInElements = 0; if (draw_data->CmdListsCount == 0) { return; } uint totalVBSize = (uint)(draw_data->TotalVtxCount * sizeof(DrawVert)); if (totalVBSize > _vertexBuffer.SizeInBytes) { gd.DisposeWhenIdle(_vertexBuffer); _vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); } uint totalIBSize = (uint)(draw_data->TotalIdxCount * sizeof(ushort)); if (totalIBSize > _indexBuffer.SizeInBytes) { gd.DisposeWhenIdle(_indexBuffer); _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); } MappedResource vbMap = _gd.Map(_vertexBuffer, MapMode.Write); MappedResource ibMap = _gd.Map(_indexBuffer, MapMode.Write); for (int i = 0; i < draw_data->CmdListsCount; i++) { NativeDrawList *cmd_list = draw_data->CmdLists[i]; Unsafe.CopyBlock( (byte *)vbMap.Data.ToPointer() + vertexOffsetInVertices * sizeof(DrawVert), cmd_list->VtxBuffer.Data, (uint)(cmd_list->VtxBuffer.Size * sizeof(DrawVert))); Unsafe.CopyBlock( (byte *)ibMap.Data.ToPointer() + indexOffsetInElements * sizeof(ushort), cmd_list->IdxBuffer.Data, (uint)(cmd_list->IdxBuffer.Size * sizeof(ushort))); vertexOffsetInVertices += (uint)cmd_list->VtxBuffer.Size; indexOffsetInElements += (uint)cmd_list->IdxBuffer.Size; } _gd.Unmap(_vertexBuffer); _gd.Unmap(_indexBuffer); // Setup orthographic projection matrix into our constant buffer { var io = ImGui.GetIO(); Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( 0f, io.DisplaySize.X, io.DisplaySize.Y, 0.0f, -1.0f, 1.0f); _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); } cl.SetVertexBuffer(0, _vertexBuffer); cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); cl.SetPipeline(_pipeline); cl.SetGraphicsResourceSet(0, _mainResourceSet); ImGui.ScaleClipRects(draw_data, ImGui.GetIO().DisplayFramebufferScale); // Render command lists int vtx_offset = 0; int idx_offset = 0; for (int n = 0; n < draw_data->CmdListsCount; n++) { NativeDrawList *cmd_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { DrawCmd *pcmd = &(((DrawCmd *)cmd_list->CmdBuffer.Data)[cmd_i]); if (pcmd->UserCallback != IntPtr.Zero) { throw new NotImplementedException(); } else { if (pcmd->TextureId != IntPtr.Zero) { if (pcmd->TextureId == _fontAtlasID) { cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); } else { cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd->TextureId)); } } cl.SetScissorRect( 0, (uint)pcmd->ClipRect.X, (uint)pcmd->ClipRect.Y, (uint)(pcmd->ClipRect.Z - pcmd->ClipRect.X), (uint)(pcmd->ClipRect.W - pcmd->ClipRect.Y)); cl.DrawIndexed(pcmd->ElemCount, 1, (uint)idx_offset, vtx_offset, 0); } idx_offset += (int)pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.Size; } }
// TODO: private protected /// <summary> /// </summary> /// <param name="indirectBuffer"></param> /// <param name="offset"></param> /// <param name="drawCount"></param> /// <param name="stride"></param> protected abstract void DrawIndexedIndirectCore(DeviceBuffer indirectBuffer, uint offset, uint drawCount, uint stride);
/// <summary> /// Issues an indirect compute dispatch command based on the information contained in the given indirect /// <see cref="DeviceBuffer"/>. The information stored in the indirect Buffer should conform to the structure of /// <see cref="IndirectDispatchArguments"/>. /// </summary> /// <param name="indirectBuffer">The indirect Buffer to read from. Must have been created with the /// <see cref="BufferUsage.IndirectBuffer"/> flag.</param> /// <param name="offset">An offset, in bytes, from the start of the indirect buffer from which the draw commands will be /// read. This value must be a multiple of 4.</param> public void DispatchIndirect(DeviceBuffer indirectBuffer, uint offset) { ValidateIndirectBuffer(indirectBuffer); ValidateIndirectOffset(offset); DispatchIndirectCore(indirectBuffer, offset); }
// TODO: private protected /// <summary> /// </summary> /// <param name="buffer"></param> /// <param name="format"></param> protected abstract void SetIndexBufferCore(DeviceBuffer buffer, IndexFormat format);
// TODO: private protected /// <summary> /// </summary> /// <param name="index"></param> /// <param name="buffer"></param> protected abstract void SetVertexBufferCore(uint index, DeviceBuffer buffer);
/// <summary> /// Sets the active <see cref="DeviceBuffer"/>. /// When drawing, an <see cref="DeviceBuffer"/> must be bound. /// </summary> /// <param name="buffer">The new <see cref="DeviceBuffer"/>.</param> /// <param name="format">The format of data in the <see cref="DeviceBuffer"/>.</param> public void SetIndexBuffer(DeviceBuffer buffer, IndexFormat format) { SetIndexBuffer(buffer, format, 0); }
/// <summary> /// Sets the active <see cref="DeviceBuffer"/> for the given index. /// When drawing, the bound <see cref="DeviceBuffer"/> objects must be compatible with the bound <see cref="Pipeline"/>. /// The given buffer must be non-null. It is not necessary to un-bind vertex buffers for Pipelines which will not /// use them. All extra vertex buffers are simply ignored. /// </summary> /// <param name="index">The buffer slot.</param> /// <param name="buffer">The new <see cref="DeviceBuffer"/>.</param> public void SetVertexBuffer(uint index, DeviceBuffer buffer) { SetVertexBuffer(index, buffer, 0); }
/// <summary> /// Constructs a new <see cref="DeviceBufferRange"/>. /// </summary> /// <param name="buffer">The underlying <see cref="DeviceBuffer"/> that this range will refer to.</param> /// <param name="offset">The offset, in bytes, from the beginning of the buffer that this range will start at.</param> /// <param name="sizeInBytes">The total number of bytes that this range will encompass.</param> public DeviceBufferRange(DeviceBuffer buffer, uint offset, uint sizeInBytes) { Buffer = buffer; Offset = offset; SizeInBytes = sizeInBytes; }