/// <summary> /// Synchronously renders a complete frame to the specified render target. /// Automatically sets up the device's viewport and the view transform of your materials and restores them afterwards. /// </summary> public bool SynchronousDrawToRenderTarget(RenderTarget2D renderTarget, DefaultMaterialSet materials, Action <Frame> drawBehavior) { if (renderTarget.IsDisposed) { return(false); } if (!SynchronousDrawsEnabled) { throw new InvalidOperationException("Synchronous draws not available inside of Game.Draw"); } WaitForActiveDraw(); var oldDrawIsActive = Interlocked.Exchange(ref _SynchronousDrawIsActive, 1); if (oldDrawIsActive != 0) { throw new InvalidOperationException("A synchronous draw is already in progress"); } _SynchronousDrawFinishedSignal.Reset(); WaitForActiveDraw(); try { using (var frame = Manager.CreateFrame()) { materials.PushViewTransform(ViewTransform.CreateOrthographic(renderTarget.Width, renderTarget.Height)); ClearBatch.AddNew(frame, int.MinValue, materials.Clear, clearColor: Color.Transparent); drawBehavior(frame); PrepareNextFrame(frame, false); var oldRenderTargets = Device.GetRenderTargets(); var oldViewport = Device.Viewport; try { Device.SetRenderTarget(renderTarget); RenderManager.ResetDeviceState(Device); Device.Viewport = new Viewport(0, 0, renderTarget.Width, renderTarget.Height); RenderFrameToDraw(frame, false); } finally { Device.SetRenderTargets(oldRenderTargets); materials.PopViewTransform(); Device.Viewport = oldViewport; } } return(true); } finally { _SynchronousDrawFinishedSignal.Set(); Interlocked.Exchange(ref _SynchronousDrawIsActive, 0); } }
private bool DoSynchronousDrawToRenderTarget( RenderTarget2D renderTarget, DefaultMaterialSet materials, Delegate drawBehavior, object userData, ref ViewTransform?viewTransform, string description ) { var oldLazyState = materials.LazyViewTransformChanges; try { materials.LazyViewTransformChanges = false; materials.ApplyViewTransform(materials.ViewTransform, true); using (var frame = Manager.CreateFrame(this)) { frame.ChangeRenderTargets = false; frame.Label = description; if (viewTransform.HasValue) { materials.PushViewTransform(in viewTransform); } else { materials.PushViewTransform(ViewTransform.CreateOrthographic(renderTarget.Width, renderTarget.Height)); } try { // FIXME: Should queued draws run here? They are probably meant to run in the next real frame var singleBehavior = drawBehavior as Action <Frame>; var multiBehavior = drawBehavior as PendingDrawHandler; if (singleBehavior != null) { singleBehavior(frame); } else if (multiBehavior != null) { multiBehavior(frame, materials, userData); } else { throw new ArgumentException("Draw behavior was not of a compatible type"); } RunBeforePrepareHandlers(); PrepareNextFrame(frame, false); Manager.DeviceManager.SetRenderTarget(renderTarget); RenderManager.ResetDeviceState(Device); Device.Clear(Color.Transparent); RenderFrameToDraw(frame, false); // We don't have to push/pop anymore because the stacks are cleared at the end of a frame. return(true); } finally { materials.PopViewTransform(); } } } finally { materials.LazyViewTransformChanges = oldLazyState; } }