public void SetFramebuffer(Framebuffer fb)
        {
            NoAllocSetFramebufferEntry entry = new NoAllocSetFramebufferEntry(Track(fb));

            AddEntry(SetFramebufferEntryID, ref entry);
        }
        public void ExecuteAll(OpenGLCommandExecutor executor)
        {
            int currentBlockIndex   = 0;
            EntryStorageBlock block = _blocks[currentBlockIndex];
            uint currentOffset      = 0;

            for (uint i = 0; i < _totalEntries; i++)
            {
                if (currentOffset == block.TotalSize)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                }

                uint id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                if (id == 0)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                    id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                }

                Debug.Assert(id != 0);
                currentOffset += 1;
                byte *entryBasePtr = block.BasePtr + currentOffset;
                switch (id)
                {
                case BeginEntryID:
                    executor.Begin();
                    currentOffset += BeginEntrySize;
                    break;

                case ClearColorTargetID:
                    NoAllocClearColorTargetEntry ccte = Unsafe.ReadUnaligned <NoAllocClearColorTargetEntry>(entryBasePtr);
                    executor.ClearColorTarget(ccte.Index, ccte.ClearColor);
                    currentOffset += ClearColorTargetEntrySize;
                    break;

                case ClearDepthTargetID:
                    NoAllocClearDepthTargetEntry cdte = Unsafe.ReadUnaligned <NoAllocClearDepthTargetEntry>(entryBasePtr);
                    executor.ClearDepthStencil(cdte.Depth, cdte.Stencil);
                    currentOffset += ClearDepthTargetEntrySize;
                    break;

                case DrawEntryID:
                    NoAllocDrawEntry de = Unsafe.ReadUnaligned <NoAllocDrawEntry>(entryBasePtr);
                    executor.Draw(de.VertexCount, de.InstanceCount, de.VertexStart, de.InstanceStart);
                    currentOffset += DrawEntrySize;
                    break;

                case DrawIndexedEntryID:
                    NoAllocDrawIndexedEntry die = Unsafe.ReadUnaligned <NoAllocDrawIndexedEntry>(entryBasePtr);
                    executor.DrawIndexed(die.IndexCount, die.InstanceCount, die.IndexStart, die.VertexOffset, die.InstanceStart);
                    currentOffset += DrawIndexedEntrySize;
                    break;

                case DrawIndirectEntryID:
                    NoAllocDrawIndirectEntry drawIndirectEntry = Unsafe.ReadUnaligned <NoAllocDrawIndirectEntry>(entryBasePtr);
                    executor.DrawIndirect(
                        drawIndirectEntry.IndirectBuffer.Get(_resourceList),
                        drawIndirectEntry.Offset,
                        drawIndirectEntry.DrawCount,
                        drawIndirectEntry.Stride);
                    currentOffset += DrawIndirectEntrySize;
                    break;

                case DrawIndexedIndirectEntryID:
                    NoAllocDrawIndexedIndirectEntry diie = Unsafe.ReadUnaligned <NoAllocDrawIndexedIndirectEntry>(entryBasePtr);
                    executor.DrawIndexedIndirect(diie.IndirectBuffer.Get(_resourceList), diie.Offset, diie.DrawCount, diie.Stride);
                    currentOffset += DrawIndexedIndirectEntrySize;
                    break;

                case DispatchEntryID:
                    NoAllocDispatchEntry dispatchEntry = Unsafe.ReadUnaligned <NoAllocDispatchEntry>(entryBasePtr);
                    executor.Dispatch(dispatchEntry.GroupCountX, dispatchEntry.GroupCountY, dispatchEntry.GroupCountZ);
                    currentOffset += DispatchEntrySize;
                    break;

                case DispatchIndirectEntryID:
                    NoAllocDispatchIndirectEntry dispatchIndir = Unsafe.ReadUnaligned <NoAllocDispatchIndirectEntry>(entryBasePtr);
                    executor.DispatchIndirect(dispatchIndir.IndirectBuffer.Get(_resourceList), dispatchIndir.Offset);
                    currentOffset += DispatchIndirectEntrySize;
                    break;

                case EndEntryID:
                    executor.End();
                    currentOffset += EndEntrySize;
                    break;

                case SetFramebufferEntryID:
                    NoAllocSetFramebufferEntry sfbe = Unsafe.ReadUnaligned <NoAllocSetFramebufferEntry>(entryBasePtr);
                    executor.SetFramebuffer(sfbe.Framebuffer.Get(_resourceList));
                    currentOffset += SetFramebufferEntrySize;
                    break;

                case SetIndexBufferEntryID:
                    NoAllocSetIndexBufferEntry sibe = Unsafe.ReadUnaligned <NoAllocSetIndexBufferEntry>(entryBasePtr);
                    executor.SetIndexBuffer(sibe.Buffer.Get(_resourceList), sibe.Format, sibe.Offset);
                    currentOffset += SetIndexBufferEntrySize;
                    break;

                case SetPipelineEntryID:
                    NoAllocSetPipelineEntry spe = Unsafe.ReadUnaligned <NoAllocSetPipelineEntry>(entryBasePtr);
                    executor.SetPipeline(spe.Pipeline.Get(_resourceList));
                    currentOffset += SetPipelineEntrySize;
                    break;

                case SetResourceSetEntryID:
                    NoAllocSetResourceSetEntry srse = Unsafe.ReadUnaligned <NoAllocSetResourceSetEntry>(entryBasePtr);
                    ResourceSet rs = srse.ResourceSet.Get(_resourceList);
                    uint *      dynamicOffsetsPtr = srse.DynamicOffsetCount > NoAllocSetResourceSetEntry.MaxInlineDynamicOffsets
                            ? (uint *)srse.DynamicOffsets_Block.Data
                            : srse.DynamicOffsets_Inline;
                    if (srse.IsGraphics)
                    {
                        executor.SetGraphicsResourceSet(
                            srse.Slot,
                            rs,
                            srse.DynamicOffsetCount,
                            ref Unsafe.AsRef <uint>(dynamicOffsetsPtr));
                    }
                    else
                    {
                        executor.SetComputeResourceSet(
                            srse.Slot,
                            rs,
                            srse.DynamicOffsetCount,
                            ref Unsafe.AsRef <uint>(dynamicOffsetsPtr));
                    }
                    currentOffset += SetResourceSetEntrySize;
                    break;

                case SetScissorRectEntryID:
                    NoAllocSetScissorRectEntry ssre = Unsafe.ReadUnaligned <NoAllocSetScissorRectEntry>(entryBasePtr);
                    executor.SetScissorRect(ssre.Index, ssre.X, ssre.Y, ssre.Width, ssre.Height);
                    currentOffset += SetScissorRectEntrySize;
                    break;

                case SetVertexBufferEntryID:
                    NoAllocSetVertexBufferEntry svbe = Unsafe.ReadUnaligned <NoAllocSetVertexBufferEntry>(entryBasePtr);
                    executor.SetVertexBuffer(svbe.Index, svbe.Buffer.Get(_resourceList), svbe.Offset);
                    currentOffset += SetVertexBufferEntrySize;
                    break;

                case SetViewportEntryID:
                    NoAllocSetViewportEntry svpe = Unsafe.ReadUnaligned <NoAllocSetViewportEntry>(entryBasePtr);
                    executor.SetViewport(svpe.Index, ref svpe.Viewport);
                    currentOffset += SetViewportEntrySize;
                    break;

                case UpdateBufferEntryID:
                    NoAllocUpdateBufferEntry ube = Unsafe.ReadUnaligned <NoAllocUpdateBufferEntry>(entryBasePtr);
                    byte *dataPtr = (byte *)ube.StagingBlock.Data;
                    executor.UpdateBuffer(
                        ube.Buffer.Get(_resourceList),
                        ube.BufferOffsetInBytes,
                        (IntPtr)dataPtr, ube.StagingBlockSize);
                    currentOffset += UpdateBufferEntrySize;
                    break;

                case CopyBufferEntryID:
                    NoAllocCopyBufferEntry cbe = Unsafe.ReadUnaligned <NoAllocCopyBufferEntry>(entryBasePtr);
                    executor.CopyBuffer(
                        cbe.Source.Get(_resourceList),
                        cbe.SourceOffset,
                        cbe.Destination.Get(_resourceList),
                        cbe.DestinationOffset,
                        cbe.SizeInBytes);
                    currentOffset += CopyBufferEntrySize;
                    break;

                case CopyTextureEntryID:
                    NoAllocCopyTextureEntry cte = Unsafe.ReadUnaligned <NoAllocCopyTextureEntry>(entryBasePtr);
                    executor.CopyTexture(
                        cte.Source.Get(_resourceList),
                        cte.SrcX, cte.SrcY, cte.SrcZ,
                        cte.SrcMipLevel,
                        cte.SrcBaseArrayLayer,
                        cte.Destination.Get(_resourceList),
                        cte.DstX, cte.DstY, cte.DstZ,
                        cte.DstMipLevel,
                        cte.DstBaseArrayLayer,
                        cte.Width, cte.Height, cte.Depth,
                        cte.LayerCount);
                    currentOffset += CopyTextureEntrySize;
                    break;

                case ResolveTextureEntryID:
                    NoAllocResolveTextureEntry rte = Unsafe.ReadUnaligned <NoAllocResolveTextureEntry>(entryBasePtr);
                    executor.ResolveTexture(rte.Source.Get(_resourceList), rte.Destination.Get(_resourceList));
                    currentOffset += ResolveTextureEntrySize;
                    break;

                case GenerateMipmapsEntryID:
                    NoAllocGenerateMipmapsEntry gme = Unsafe.ReadUnaligned <NoAllocGenerateMipmapsEntry>(entryBasePtr);
                    executor.GenerateMipmaps(gme.Texture.Get(_resourceList));
                    currentOffset += GenerateMipmapsEntrySize;
                    break;

                case PushDebugGroupEntryID:
                    NoAllocPushDebugGroupEntry pdge = Unsafe.ReadUnaligned <NoAllocPushDebugGroupEntry>(entryBasePtr);
                    executor.PushDebugGroup(pdge.Name.Get(_resourceList));
                    currentOffset += PushDebugGroupEntrySize;
                    break;

                case PopDebugGroupEntryID:
                    executor.PopDebugGroup();
                    currentOffset += PopDebugGroupEntrySize;
                    break;

                case InsertDebugMarkerEntryID:
                    NoAllocInsertDebugMarkerEntry idme = Unsafe.ReadUnaligned <NoAllocInsertDebugMarkerEntry>(entryBasePtr);
                    executor.InsertDebugMarker(idme.Name.Get(_resourceList));
                    currentOffset += InsertDebugMarkerEntrySize;
                    break;

                default:
                    throw new InvalidOperationException("Invalid entry ID: " + id);
                }
            }
        }
Ejemplo n.º 3
0
        private void FreeAllHandles()
        {
            int currentBlockIndex   = 0;
            EntryStorageBlock block = _blocks[currentBlockIndex];
            uint currentOffset      = 0;

            for (uint i = 0; i < _totalEntries; i++)
            {
                if (currentOffset == block.TotalSize)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                }

                uint id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                if (id == 0)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                    id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                }

                Debug.Assert(id != 0);
                currentOffset += 1;
                byte *entryBasePtr = block.BasePtr + currentOffset;
                switch (id)
                {
                case BeginEntryID:
                    currentOffset += BeginEntrySize;
                    break;

                case ClearColorTargetID:
                    currentOffset += ClearColorTargetEntrySize;
                    break;

                case ClearDepthTargetID:
                    currentOffset += ClearDepthTargetEntrySize;
                    break;

                case DrawEntryID:
                    currentOffset += DrawEntrySize;
                    break;

                case DrawIndexedEntryID:
                    currentOffset += DrawIndexedEntrySize;
                    break;

                case DrawIndirectEntryID:
                    ref NoAllocDrawIndirectEntry drawIndirectEntry = ref Unsafe.AsRef <NoAllocDrawIndirectEntry>(entryBasePtr);
                    drawIndirectEntry.IndirectBuffer.Free();
                    currentOffset += DrawIndirectEntrySize;
                    break;

                case DrawIndexedIndirectEntryID:
                    ref NoAllocDrawIndexedIndirectEntry diie = ref Unsafe.AsRef <NoAllocDrawIndexedIndirectEntry>(entryBasePtr);
                    diie.IndirectBuffer.Free();
                    currentOffset += DrawIndexedIndirectEntrySize;
                    break;

                case DispatchEntryID:
                    currentOffset += DispatchEntrySize;
                    break;

                case DispatchIndirectEntryID:
                    ref NoAllocDispatchIndirectEntry dispatchIndirect = ref Unsafe.AsRef <NoAllocDispatchIndirectEntry>(entryBasePtr);
                    dispatchIndirect.IndirectBuffer.Free();
                    currentOffset += DispatchIndirectEntrySize;
                    break;

                case EndEntryID:
                    currentOffset += EndEntrySize;
                    break;

                case SetFramebufferEntryID:
                    ref NoAllocSetFramebufferEntry sfbe = ref Unsafe.AsRef <NoAllocSetFramebufferEntry>(entryBasePtr);
                    sfbe.Framebuffer.Free();
                    currentOffset += SetFramebufferEntrySize;
                    break;

                case SetIndexBufferEntryID:
                    ref NoAllocSetIndexBufferEntry sibe = ref Unsafe.AsRef <NoAllocSetIndexBufferEntry>(entryBasePtr);
                    sibe.Buffer.Free();
                    currentOffset += SetIndexBufferEntrySize;
                    break;

                case SetPipelineEntryID:
                    ref NoAllocSetPipelineEntry spe = ref Unsafe.AsRef <NoAllocSetPipelineEntry>(entryBasePtr);
                    spe.Pipeline.Free();
                    currentOffset += SetPipelineEntrySize;
                    break;

                case SetGraphicsResourceSetEntryID:
                    ref NoAllocSetGraphicsResourceSetEntry sgrse = ref Unsafe.AsRef <NoAllocSetGraphicsResourceSetEntry>(entryBasePtr);
                    sgrse.ResourceSet.Free();
                    currentOffset += SetGraphicsResourceSetEntrySize;
                    break;

                case SetComputeResourceSetEntryID:
                    ref NoAllocSetComputeResourceSetEntry scrse = ref Unsafe.AsRef <NoAllocSetComputeResourceSetEntry>(entryBasePtr);
                    scrse.ResourceSet.Free();
                    currentOffset += SetComputeResourceSetEntrySize;
                    break;

                case SetScissorRectEntryID:
                    currentOffset += SetScissorRectEntrySize;
                    break;

                case SetVertexBufferEntryID:
                    ref NoAllocSetVertexBufferEntry svbe = ref Unsafe.AsRef <NoAllocSetVertexBufferEntry>(entryBasePtr);
                    svbe.Buffer.Free();
                    currentOffset += SetVertexBufferEntrySize;
                    break;

                case SetViewportEntryID:
                    currentOffset += SetViewportEntrySize;
                    break;

                case UpdateBufferEntryID:
                    ref NoAllocUpdateBufferEntry ube = ref Unsafe.AsRef <NoAllocUpdateBufferEntry>(entryBasePtr);
                    ube.Buffer.Free();
                    ube.StagingBlock.GCHandle.Free();
                    currentOffset += UpdateBufferEntrySize;
                    break;

                case CopyBufferEntryID:
                    ref NoAllocCopyBufferEntry cbe = ref Unsafe.AsRef <NoAllocCopyBufferEntry>(entryBasePtr);
                    cbe.Source.Free();
                    cbe.Destination.Free();
                    currentOffset += CopyBufferEntrySize;
                    break;

                case CopyTextureEntryID:
                    ref NoAllocCopyTextureEntry cte = ref Unsafe.AsRef <NoAllocCopyTextureEntry>(entryBasePtr);
                    cte.Source.Free();
                    cte.Destination.Free();
                    currentOffset += CopyTextureEntrySize;
                    break;

                case ResolveTextureEntryID:
                    ref NoAllocResolveTextureEntry rte = ref Unsafe.AsRef <NoAllocResolveTextureEntry>(entryBasePtr);
                    rte.Source.Free();
                    rte.Destination.Free();
                    currentOffset += ResolveTextureEntrySize;
                    break;

                default:
                    throw new InvalidOperationException("Invalid entry ID: " + id);
                }
            }
        }
Ejemplo n.º 4
0
        public void ExecuteAll(OpenGLCommandExecutor executor)
        {
            int currentBlockIndex   = 0;
            EntryStorageBlock block = _blocks[currentBlockIndex];
            uint currentOffset      = 0;

            for (uint i = 0; i < _totalEntries; i++)
            {
                if (currentOffset == block.TotalSize)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                }

                uint id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                if (id == 0)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                    id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                }

                Debug.Assert(id != 0);
                currentOffset += 1;
                byte *entryBasePtr = block.BasePtr + currentOffset;
                switch (id)
                {
                case BeginEntryID:
                    executor.Begin();
                    currentOffset += BeginEntrySize;
                    break;

                case ClearColorTargetID:
                    ref NoAllocClearColorTargetEntry ccte = ref Unsafe.AsRef <NoAllocClearColorTargetEntry>(entryBasePtr);
                    executor.ClearColorTarget(ccte.Index, ccte.ClearColor);
                    currentOffset += ClearColorTargetEntrySize;
                    break;

                case ClearDepthTargetID:
                    ref NoAllocClearDepthTargetEntry cdte = ref Unsafe.AsRef <NoAllocClearDepthTargetEntry>(entryBasePtr);
                    executor.ClearDepthStencil(cdte.Depth, cdte.Stencil);
                    currentOffset += ClearDepthTargetEntrySize;
                    break;

                case DrawEntryID:
                    ref NoAllocDrawEntry de = ref Unsafe.AsRef <NoAllocDrawEntry>(entryBasePtr);
                    executor.Draw(de.VertexCount, de.InstanceCount, de.VertexStart, de.InstanceStart);
                    currentOffset += DrawEntrySize;
                    break;

                case DrawIndexedEntryID:
                    ref NoAllocDrawIndexedEntry die = ref Unsafe.AsRef <NoAllocDrawIndexedEntry>(entryBasePtr);
                    executor.DrawIndexed(die.IndexCount, die.InstanceCount, die.IndexStart, die.VertexOffset, die.InstanceCount);
                    currentOffset += DrawIndexedEntrySize;
                    break;

                case DrawIndirectEntryID:
                    ref NoAllocDrawIndirectEntry drawIndirectEntry = ref Unsafe.AsRef <NoAllocDrawIndirectEntry>(entryBasePtr);
                    executor.DrawIndirect(
                        drawIndirectEntry.IndirectBuffer,
                        drawIndirectEntry.Offset,
                        drawIndirectEntry.DrawCount,
                        drawIndirectEntry.Stride);
                    currentOffset += DrawIndirectEntrySize;
                    break;

                case DrawIndexedIndirectEntryID:
                    ref NoAllocDrawIndexedIndirectEntry diie = ref Unsafe.AsRef <NoAllocDrawIndexedIndirectEntry>(entryBasePtr);
                    executor.DrawIndexedIndirect(diie.IndirectBuffer, diie.Offset, diie.DrawCount, diie.Stride);
                    currentOffset += DrawIndexedIndirectEntrySize;
                    break;

                case DispatchEntryID:
                    ref NoAllocDispatchEntry dispatchEntry = ref Unsafe.AsRef <NoAllocDispatchEntry>(entryBasePtr);
                    executor.Dispatch(dispatchEntry.GroupCountX, dispatchEntry.GroupCountY, dispatchEntry.GroupCountZ);
                    currentOffset += DispatchEntrySize;
                    break;

                case DispatchIndirectEntryID:
                    ref NoAllocDispatchIndirectEntry dispatchIndir = ref Unsafe.AsRef <NoAllocDispatchIndirectEntry>(entryBasePtr);
                    executor.DispatchIndirect(dispatchIndir.IndirectBuffer, dispatchIndir.Offset);
                    currentOffset += DispatchIndirectEntrySize;
                    break;

                case EndEntryID:
                    executor.End();
                    currentOffset += EndEntrySize;
                    break;

                case SetFramebufferEntryID:
                    ref NoAllocSetFramebufferEntry sfbe = ref Unsafe.AsRef <NoAllocSetFramebufferEntry>(entryBasePtr);
                    executor.SetFramebuffer(sfbe.Framebuffer);
                    currentOffset += SetFramebufferEntrySize;
                    break;

                case SetIndexBufferEntryID:
                    ref NoAllocSetIndexBufferEntry sibe = ref Unsafe.AsRef <NoAllocSetIndexBufferEntry>(entryBasePtr);
                    executor.SetIndexBuffer(sibe.Buffer.Item, sibe.Format);
                    currentOffset += SetIndexBufferEntrySize;
                    break;

                case SetPipelineEntryID:
                    ref NoAllocSetPipelineEntry spe = ref Unsafe.AsRef <NoAllocSetPipelineEntry>(entryBasePtr);
                    executor.SetPipeline(spe.Pipeline);
                    currentOffset += SetPipelineEntrySize;
                    break;

                case SetGraphicsResourceSetEntryID:
                    ref NoAllocSetGraphicsResourceSetEntry sgrse = ref Unsafe.AsRef <NoAllocSetGraphicsResourceSetEntry>(entryBasePtr);
                    executor.SetGraphicsResourceSet(sgrse.Slot, sgrse.ResourceSet);
                    currentOffset += SetGraphicsResourceSetEntrySize;
                    break;

                case SetComputeResourceSetEntryID:
                    ref NoAllocSetComputeResourceSetEntry scrse = ref Unsafe.AsRef <NoAllocSetComputeResourceSetEntry>(entryBasePtr);
                    executor.SetComputeResourceSet(scrse.Slot, scrse.ResourceSet);
                    currentOffset += SetComputeResourceSetEntrySize;
                    break;

                case SetScissorRectEntryID:
                    ref NoAllocSetScissorRectEntry ssre = ref Unsafe.AsRef <NoAllocSetScissorRectEntry>(entryBasePtr);
                    executor.SetScissorRect(ssre.Index, ssre.X, ssre.Y, ssre.Width, ssre.Height);
                    currentOffset += SetScissorRectEntrySize;
                    break;

                case SetVertexBufferEntryID:
                    ref NoAllocSetVertexBufferEntry svbe = ref Unsafe.AsRef <NoAllocSetVertexBufferEntry>(entryBasePtr);
                    executor.SetVertexBuffer(svbe.Index, svbe.Buffer.Item);
                    currentOffset += SetVertexBufferEntrySize;
                    break;

                case SetViewportEntryID:
                    ref NoAllocSetViewportEntry svpe = ref Unsafe.AsRef <NoAllocSetViewportEntry>(entryBasePtr);
                    executor.SetViewport(svpe.Index, ref svpe.Viewport);
                    currentOffset += SetViewportEntrySize;
                    break;

                case UpdateBufferEntryID:
                    ref NoAllocUpdateBufferEntry ube = ref Unsafe.AsRef <NoAllocUpdateBufferEntry>(entryBasePtr);
                    fixed(byte *dataPtr = &ube.StagingBlock.Array[0])
                    {
                        executor.UpdateBuffer(
                            ube.Buffer.Item,
                            ube.BufferOffsetInBytes,
                            (IntPtr)dataPtr, ube.StagingBlock.SizeInBytes);
                    }

                    currentOffset += UpdateBufferEntrySize;
                    break;

                case CopyBufferEntryID:
                    ref NoAllocCopyBufferEntry cbe = ref Unsafe.AsRef <NoAllocCopyBufferEntry>(entryBasePtr);
                    executor.CopyBuffer(
                        cbe.Source,
                        cbe.SourceOffset,
                        cbe.Destination,
                        cbe.DestinationOffset,
                        cbe.SizeInBytes);
                    currentOffset += CopyBufferEntrySize;
                    break;

                case CopyTextureEntryID:
                    ref NoAllocCopyTextureEntry cte = ref Unsafe.AsRef <NoAllocCopyTextureEntry>(entryBasePtr);
                    executor.CopyTexture(
                        cte.Source,
                        cte.SrcX, cte.SrcY, cte.SrcZ,
                        cte.SrcMipLevel,
                        cte.SrcBaseArrayLayer,
                        cte.Destination,
                        cte.DstX, cte.DstY, cte.DstZ,
                        cte.DstMipLevel,
                        cte.DstBaseArrayLayer,
                        cte.Width, cte.Height, cte.Depth,
                        cte.LayerCount);
                    currentOffset += CopyTextureEntrySize;
                    break;

                case ResolveTextureEntryID:
                    ref NoAllocResolveTextureEntry rte = ref Unsafe.AsRef <NoAllocResolveTextureEntry>(entryBasePtr);
                    executor.ResolveTexture(rte.Source.Item, rte.Destination.Item);
                    currentOffset += ResolveTextureEntrySize;
                    break;

                default:
                    throw new InvalidOperationException("Invalid entry ID: " + id);
                }
            }
        }
        private void FreeAllHandles()
        {
            int currentBlockIndex   = 0;
            EntryStorageBlock block = _blocks[currentBlockIndex];
            uint currentOffset      = 0;

            for (uint i = 0; i < _totalEntries; i++)
            {
                if (currentOffset == block.TotalSize)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                }

                uint id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                if (id == 0)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                    id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                }

                Debug.Assert(id != 0);
                currentOffset += 1;
                byte *entryBasePtr = block.BasePtr + currentOffset;
                switch (id)
                {
                case BeginEntryID:
                    currentOffset += BeginEntrySize;
                    break;

                case ClearColorTargetID:
                    currentOffset += ClearColorTargetEntrySize;
                    break;

                case ClearDepthTargetID:
                    currentOffset += ClearDepthTargetEntrySize;
                    break;

                case DrawEntryID:
                    currentOffset += DrawEntrySize;
                    break;

                case EndEntryID:
                    currentOffset += EndEntrySize;
                    break;

                case SetFramebufferEntryID:
                    ref NoAllocSetFramebufferEntry sfbe = ref Unsafe.AsRef <NoAllocSetFramebufferEntry>(entryBasePtr);
                    sfbe.Framebuffer.Free();
                    currentOffset += SetFramebufferEntrySize;
                    break;

                case SetIndexBufferEntryID:
                    ref NoAllocSetIndexBufferEntry sibe = ref Unsafe.AsRef <NoAllocSetIndexBufferEntry>(entryBasePtr);
                    sibe.IndexBuffer.Free();
                    currentOffset += SetIndexBufferEntrySize;
                    break;

                case SetPipelineEntryID:
                    ref NoAllocSetPipelineEntry spe = ref Unsafe.AsRef <NoAllocSetPipelineEntry>(entryBasePtr);
                    spe.Pipeline.Free();
                    currentOffset += SetPipelineEntrySize;
                    break;

                case SetResourceSetEntryID:
                    ref NoAllocSetResourceSetEntry srse = ref Unsafe.AsRef <NoAllocSetResourceSetEntry>(entryBasePtr);
                    srse.ResourceSet.Free();
                    currentOffset += SetResourceSetEntrySize;
                    break;

                case SetScissorRectEntryID:
                    currentOffset += SetScissorRectEntrySize;
                    break;

                case SetVertexBufferEntryID:
                    ref NoAllocSetVertexBufferEntry svbe = ref Unsafe.AsRef <NoAllocSetVertexBufferEntry>(entryBasePtr);
                    svbe.VertexBuffer.Free();
                    currentOffset += SetVertexBufferEntrySize;
                    break;

                case SetViewportEntryID:
                    currentOffset += SetViewportEntrySize;
                    break;

                case UpdateBufferEntryID:
                    ref NoAllocUpdateBufferEntry ube = ref Unsafe.AsRef <NoAllocUpdateBufferEntry>(entryBasePtr);
                    ube.Buffer.Free();
                    ube.StagingBlock.GCHandle.Free();
                    currentOffset += UpdateBufferEntrySize;
                    break;

                case UpdateTextureEntryID:
                    ref NoAllocUpdateTextureEntry ute = ref Unsafe.AsRef <NoAllocUpdateTextureEntry>(entryBasePtr);
                    ute.Texture.Free();
                    ute.StagingBlock.GCHandle.Free();
                    currentOffset += UpdateTextureEntrySize;
                    break;

                case UpdateTextureCubeEntryID:
                    ref NoAllocUpdateTextureCubeEntry utce = ref Unsafe.AsRef <NoAllocUpdateTextureCubeEntry>(entryBasePtr);
                    utce.Texture.Free();
                    utce.StagingBlock.GCHandle.Free();
                    currentOffset += UpdateTextureCubeEntrySize;
                    break;

                default:
                    throw new InvalidOperationException("Invalid entry ID: " + id);
                }
            }
        }
        public void ExecuteAll(OpenGLCommandExecutor executor)
        {
            int currentBlockIndex   = 0;
            EntryStorageBlock block = _blocks[currentBlockIndex];
            uint currentOffset      = 0;

            for (uint i = 0; i < _totalEntries; i++)
            {
                if (currentOffset == block.TotalSize)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                }

                uint id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                if (id == 0)
                {
                    currentBlockIndex += 1;
                    block              = _blocks[currentBlockIndex];
                    currentOffset      = 0;
                    id = Unsafe.Read <byte>(block.BasePtr + currentOffset);
                }

                Debug.Assert(id != 0);
                currentOffset += 1;
                byte *entryBasePtr = block.BasePtr + currentOffset;
                switch (id)
                {
                case BeginEntryID:
                    executor.Begin();
                    currentOffset += BeginEntrySize;
                    break;

                case ClearColorTargetID:
                    ref NoAllocClearColorTargetEntry ccte = ref Unsafe.AsRef <NoAllocClearColorTargetEntry>(entryBasePtr);
                    executor.ClearColorTarget(ccte.Index, ccte.ClearColor);
                    currentOffset += ClearColorTargetEntrySize;
                    break;

                case ClearDepthTargetID:
                    ref NoAllocClearDepthTargetEntry cdte = ref Unsafe.AsRef <NoAllocClearDepthTargetEntry>(entryBasePtr);
                    executor.ClearDepthTarget(cdte.Depth);
                    currentOffset += ClearDepthTargetEntrySize;
                    break;

                case DrawEntryID:
                    ref NoAllocDrawEntry de = ref Unsafe.AsRef <NoAllocDrawEntry>(entryBasePtr);
                    executor.Draw(de.IndexCount, de.InstanceCount, de.IndexStart, de.VertexOffset, de.InstanceCount);
                    currentOffset += DrawEntrySize;
                    break;

                case EndEntryID:
                    executor.End();
                    currentOffset += EndEntrySize;
                    break;

                case SetFramebufferEntryID:
                    ref NoAllocSetFramebufferEntry sfbe = ref Unsafe.AsRef <NoAllocSetFramebufferEntry>(entryBasePtr);
                    executor.SetFramebuffer(sfbe.Framebuffer);
                    currentOffset += SetFramebufferEntrySize;
                    break;

                case SetIndexBufferEntryID:
                    ref NoAllocSetIndexBufferEntry sibe = ref Unsafe.AsRef <NoAllocSetIndexBufferEntry>(entryBasePtr);
                    executor.SetIndexBuffer(sibe.IndexBuffer.Item);
                    currentOffset += SetIndexBufferEntrySize;
                    break;

                case SetPipelineEntryID:
                    ref NoAllocSetPipelineEntry spe = ref Unsafe.AsRef <NoAllocSetPipelineEntry>(entryBasePtr);
                    executor.SetPipeline(spe.Pipeline);
                    currentOffset += SetPipelineEntrySize;
                    break;

                case SetResourceSetEntryID:
                    ref NoAllocSetResourceSetEntry srse = ref Unsafe.AsRef <NoAllocSetResourceSetEntry>(entryBasePtr);
                    executor.SetResourceSet(srse.Slot, srse.ResourceSet);
                    currentOffset += SetResourceSetEntrySize;
                    break;

                case SetScissorRectEntryID:
                    ref NoAllocSetScissorRectEntry ssre = ref Unsafe.AsRef <NoAllocSetScissorRectEntry>(entryBasePtr);
                    executor.SetScissorRect(ssre.Index, ssre.X, ssre.Y, ssre.Width, ssre.Height);
                    currentOffset += SetScissorRectEntrySize;
                    break;

                case SetVertexBufferEntryID:
                    ref NoAllocSetVertexBufferEntry svbe = ref Unsafe.AsRef <NoAllocSetVertexBufferEntry>(entryBasePtr);
                    executor.SetVertexBuffer(svbe.Index, svbe.VertexBuffer.Item);
                    currentOffset += SetVertexBufferEntrySize;
                    break;

                case SetViewportEntryID:
                    ref NoAllocSetViewportEntry svpe = ref Unsafe.AsRef <NoAllocSetViewportEntry>(entryBasePtr);
                    executor.SetViewport(svpe.Index, ref svpe.Viewport);
                    currentOffset += SetViewportEntrySize;
                    break;

                case UpdateBufferEntryID:
                    ref NoAllocUpdateBufferEntry ube = ref Unsafe.AsRef <NoAllocUpdateBufferEntry>(entryBasePtr);
                    executor.UpdateBuffer(
                        ube.Buffer.Item,
                        ube.BufferOffsetInBytes,
                        new StagingBlock(ube.StagingBlock.Array, ube.StagingBlock.SizeInBytes, _memoryPool));
                    currentOffset += UpdateBufferEntrySize;
                    break;

                case UpdateTextureEntryID:
                    ref NoAllocUpdateTextureEntry ute = ref Unsafe.AsRef <NoAllocUpdateTextureEntry>(entryBasePtr);
                    executor.UpdateTexture(
                        ute.Texture,
                        new StagingBlock(ute.StagingBlock.Array, ute.StagingBlock.SizeInBytes, _memoryPool),
                        ute.X,
                        ute.Y,
                        ute.Z,
                        ute.Width,
                        ute.Height,
                        ute.Depth,
                        ute.MipLevel,
                        ute.ArrayLayer);
                    currentOffset += UpdateTextureEntrySize;
                    break;

                case UpdateTextureCubeEntryID:
                    ref NoAllocUpdateTextureCubeEntry utce = ref Unsafe.AsRef <NoAllocUpdateTextureCubeEntry>(entryBasePtr);
                    executor.UpdateTextureCube(
                        utce.Texture,
                        new StagingBlock(utce.StagingBlock.Array, utce.StagingBlock.SizeInBytes, _memoryPool),
                        utce.Face,
                        utce.X,
                        utce.Y,
                        utce.Width,
                        utce.Height,
                        utce.MipLevel,
                        utce.ArrayLayer);
                    currentOffset += UpdateTextureCubeEntrySize;
                    break;

                default:
                    throw new InvalidOperationException("Invalid entry ID: " + id);
                }
            }
        }