protected SwapChain(ref Descriptor desc, Device device, string label) : base(ref desc, device, label) { Assert.Debug(desc.MaxFramesInFlight > 0, "Invalid in-flight framecount!"); Assert.Debug(desc.BufferCount > 0, "Invalid backbuffer count!"); Assert.Debug(desc.AssociatedGraphicsQueue != null, "No graphics queue passed!"); Assert.Debug(desc.AssociatedGraphicsQueue.Desc.Type == CommandListType.Graphics, "Passed command queue needs to be a graphics queue!"); var fenceDesc = new Fence.Descriptor { InitialValue = 0 }; FrameFence = device.Create(ref fenceDesc); FrameFence.AddRef(); Create(); BackbufferResources = new Resource[desc.BufferCount]; var resourceDesc = new Resource.Descriptor { Type = Resource.Descriptor.Types.Backbuffer, DataDimension = Dimension.Texture2D }; for (uint i = 0; i < BackbufferResources.Length; ++i) { BackbufferResources[i] = device.Create(ref resourceDesc, "Backbuffer"); BackbufferResources[i].CreateFromSwapChain(this, i); } }
/// <summary> /// Waits until all prepared frames are renderd and the GPU has no more tasks. /// Use this method carefully since it will usually come with a huge stall! /// </summary> public void WaitUntilAllFramesCompleted() { if (NumCompletedFramesGPU != NumCompletedFramesCPU) { FrameFence.WaitForCompletion(NumCompletedFramesCPU, TimeSpan.MaxValue); } }
/// <summary> /// Swaps backbuffer. If syncInterval is bigger than zero, this function must wait until the GPU is able to perform the swap. (TODO: Is that correct?) /// </summary> /// <remarks> /// Signals the internal frameFence that is used to determine how many frames are inflight. /// Does not call any additional wait function (like WaitForFreeInflightFrame). /// </remarks> /// <param name="syncInterval">Synchronize presentation after the nth vertical blank. 0 means no synchronization.</param> public void EndFrame(uint syncInterval = 1) { // Present and mark end of frame with fence signal. Present(syncInterval); ++NumCompletedFramesCPU; FrameFence.Signal(NumCompletedFramesCPU); activeInFlightFrameIndex = (activeInFlightFrameIndex + 1) % Desc.MaxFramesInFlight; }
/// <summary> /// Waits until only Desc.MaxFramesInFlight-1 frames are inflight and will then trigger the OnBeginRendering event. /// If an application is highly GPU bound, it will wait for the GPU to complete the rendering for this swapChain in this function. /// </summary> public void BeginFrame() { // Fullfill the MaxFramesInFlight constraint. Assert.Debug(NumFramesInFlight <= Desc.MaxFramesInFlight, "It should be impossible to have more than Desc.MaxFramesInFlight frames in flight."); if (NumFramesInFlight == Desc.MaxFramesInFlight) { FrameFence.WaitForCompletion(NumCompletedFramesGPU + 1, TimeSpan.MaxValue); } // Anounce frame start to all listeners. OnBeginFrame?.Invoke(activeInFlightFrameIndex); }
internal override void Destroy() { WaitUntilAllFramesCompleted(); FrameFence.RemoveRef(); FrameFence.Destroy(); foreach (var resource in BackbufferResources) { resource.RemoveRef(); resource.Dispose(); } BackbufferResources = null; base.Destroy(); }