Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
SwapChainGraphicsPresenter.Direct3D.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 
24 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D
25 using System;
26 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
27 using System.Windows.Forms;
28 #endif
29 using SharpDX;
30 using SharpDX.DXGI;
31 
32 namespace SiliconStudio.Paradox.Graphics
33 {
34  /// <summary>
35  /// Graphics presenter for SwapChain.
36  /// </summary>
37  public class SwapChainGraphicsPresenter : GraphicsPresenter
38  {
39  private RenderTarget backBuffer;
40 
41  private SwapChain swapChain;
42 
43  private int bufferCount;
44 
45  public SwapChainGraphicsPresenter(GraphicsDevice device, PresentationParameters presentationParameters)
46  : base(device, presentationParameters)
47  {
48  PresentInterval = presentationParameters.PresentationInterval;
49 
50  // Initialize the swap chain
51  swapChain = CreateSwapChain();
52 
53  var backBufferTexture = new Texture2D(device, swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0));
54  backBuffer = backBufferTexture.ToRenderTarget();
55 
56  // Reload should get backbuffer from swapchain as well
57  //backBufferTexture.Reload = graphicsResource => ((Texture2D)graphicsResource).Recreate(swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0));
58  }
59 
60  public override RenderTarget BackBuffer
61  {
62  get
63  {
64  return backBuffer;
65  }
66  }
67 
68  public override object NativePresenter
69  {
70  get
71  {
72  return swapChain;
73  }
74  }
75 
76  public override bool IsFullScreen
77  {
78  get
79  {
80 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
81  return false;
82 #else
83  return swapChain.IsFullScreen;
84 #endif
85  }
86 
87  set
88  {
89 #if !SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
90  if (swapChain == null)
91  return;
92 
93  var outputIndex = Description.PreferredFullScreenOutputIndex;
94 
95  // no outputs connected to the current graphics adapter
96  var output = GraphicsDevice.Adapter != null && outputIndex < GraphicsDevice.Adapter.Outputs.Length ? GraphicsDevice.Adapter.Outputs[outputIndex] : null;
97 
98  Output currentOutput = null;
99 
100  try
101  {
102  Bool isCurrentlyFullscreen;
103  swapChain.GetFullscreenState(out isCurrentlyFullscreen, out currentOutput);
104 
105  // check if the current fullscreen monitor is the same as new one
106  if (isCurrentlyFullscreen == value && output != null && currentOutput != null && currentOutput.NativePointer == output.NativeOutput.NativePointer)
107  return;
108  }
109  finally
110  {
111  if (currentOutput != null)
112  currentOutput.Dispose();
113  }
114 
115  bool switchToFullScreen = value;
116  // If going to fullscreen mode: call 1) SwapChain.ResizeTarget 2) SwapChain.IsFullScreen
117  var description = new ModeDescription(backBuffer.Width, backBuffer.Height, Description.RefreshRate.ToSharpDX(), (SharpDX.DXGI.Format)Description.BackBufferFormat);
118  if (switchToFullScreen)
119  {
120  // Force render target destruction
121  // TODO: We should track all user created render targets that points to back buffer as well (or deny their creation?)
122  backBuffer.OnDestroyed();
123 
124  OnDestroyed();
125 
126  Description.IsFullScreen = true;
127 
128  OnRecreated();
129 
130  // Recreate render target
131  backBuffer.OnRecreate();
132  }
133  else
134  {
135  Description.IsFullScreen = false;
136  swapChain.IsFullScreen = false;
137 
138  // call 1) SwapChain.IsFullScreen 2) SwapChain.Resize
139  Resize(backBuffer.Width, backBuffer.Height, backBuffer.Texture.ViewFormat);
140  }
141 
142  // If going to window mode:
143  if (!switchToFullScreen)
144  {
145  // call 1) SwapChain.IsFullScreen 2) SwapChain.Resize
146  description.RefreshRate = new SharpDX.DXGI.Rational(0, 0);
147  swapChain.ResizeTarget(ref description);
148  }
149 #endif
150  }
151  }
152 
153  public override void Present()
154  {
155  try
156  {
157  swapChain.Present((int) PresentInterval, PresentFlags.None);
158  }
159  catch (SharpDXException sharpDxException)
160  {
161  throw new GraphicsException("Unexpected error on Present", sharpDxException, GraphicsDevice.GraphicsDeviceStatus);
162  }
163  }
164 
165  protected override void OnNameChanged()
166  {
167  base.OnNameChanged();
168  if (Name != null && GraphicsDevice != null && GraphicsDevice.IsDebugMode && swapChain != null)
169  {
170  swapChain.DebugName = Name;
171  }
172  }
173 
174  public override void OnDestroyed()
175  {
176  // Manually update back buffer texture
177  backBuffer.Texture.OnDestroyed();
178  backBuffer.Texture.LifetimeState = GraphicsResourceLifetimeState.Destroyed;
179 
180  swapChain.Dispose();
181  swapChain = null;
182 
183  base.OnDestroyed();
184  }
185 
186  public override void OnRecreated()
187  {
188  base.OnRecreated();
189 
190  // Recreate swap chain
191  swapChain = CreateSwapChain();
192 
193  // Get newly created native texture
194  var backBufferTexture = swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0);
195 
196  // Put it in our back buffer texture
197  // TODO: Update new size
198  ((Texture2D)backBuffer.Texture).Recreate(backBufferTexture);
199  backBuffer.Texture.LifetimeState = GraphicsResourceLifetimeState.Active;
200  }
201 
202  protected override void ResizeBackBuffer(int width, int height, PixelFormat format)
203  {
204  // Manually update back buffer texture
205  backBuffer.Texture.OnDestroyed();
206 
207  // Force render target destruction
208  // TODO: We should track all user created render targets that points to back buffer as well (or deny their creation?)
209  backBuffer.OnDestroyed();
210 
211 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
212  var swapChainPanel = Description.DeviceWindowHandle.NativeHandle as Windows.UI.Xaml.Controls.SwapChainPanel;
213  if (swapChainPanel != null)
214  {
215  var swapChain2 = swapChain.QueryInterface<SwapChain2>();
216  if (swapChain2 != null)
217  {
218  swapChain2.MatrixTransform = Matrix3x2.Scaling(1f / swapChainPanel.CompositionScaleX, 1f / swapChainPanel.CompositionScaleY);
219  swapChain2.Dispose();
220  }
221  }
222 #endif
223 
224  swapChain.ResizeBuffers(bufferCount, width, height, (SharpDX.DXGI.Format)format, SwapChainFlags.None);
225 
226  // Get newly created native texture
227  var backBufferTexture = swapChain.GetBackBuffer<SharpDX.Direct3D11.Texture2D>(0);
228 
229  // Put it in our back buffer texture
230  ((Texture2D)backBuffer.Texture).Recreate(backBufferTexture);
231 
232  // Recreate render target
233  backBuffer.OnRecreate();
234 
235  // Update variables
236  // TODO: Should be kept readonly, maybe with reflection (ugly) or some other IL trick?
237  backBuffer.Texture.Width = width;
238  backBuffer.Texture.Height = height;
239  backBuffer.Width = width;
240  backBuffer.Height = height;
241  }
242 
243  protected override void ResizeDepthStencilBuffer(int width, int height, PixelFormat format)
244  {
245  var newTextureDescrition = DepthStencilBuffer.Texture.NativeDescription;
246  newTextureDescrition.Width = width;
247  newTextureDescrition.Height = height;
248 
249  // Manually update the texture
250  DepthStencilBuffer.Texture.OnDestroyed();
251 
252  // Force buffer destruction
253  // TODO: We should track all user created depth buffer that points to depthStencilBuffer as well (or deny their creation?)
254  DepthStencilBuffer.OnDestroyed();
255 
256  // Put it in our back buffer texture
257  DepthStencilBuffer.Texture.Recreate(newTextureDescrition);
258 
259  // Recreate render target
260  DepthStencilBuffer.OnRecreate();
261 
262  // Update variables
263  // TODO: Should be kept readonly, maybe with reflection (ugly) or some other IL trick?
264  DepthStencilBuffer.Texture.Width = width;
265  DepthStencilBuffer.Texture.Height = height;
266  DepthStencilBuffer.DescriptionInternal.Width = width;
267  DepthStencilBuffer.DescriptionInternal.Height = height;
268  }
269 
270 
271  private SwapChain CreateSwapChain()
272  {
273  // Check for Window Handle parameter
274  if (Description.DeviceWindowHandle == null)
275  {
276  throw new ArgumentException("DeviceWindowHandle cannot be null");
277  }
278 
279 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
280  return CreateSwapChainForWindowsRuntime();
281 #else
282  return CreateSwapChainForDesktop();
283 #endif
284  }
285 
286 #if SILICONSTUDIO_PLATFORM_WINDOWS_RUNTIME
287  private SwapChain CreateSwapChainForWindowsRuntime()
288  {
289  bufferCount = 2;
290  var description = new SwapChainDescription1
291  {
292  // Automatic sizing
293  Width = Description.BackBufferWidth,
294  Height = Description.BackBufferHeight,
295  Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm, // TODO: Check if we can use the Description.BackBufferFormat
296  Stereo = false,
297  SampleDescription = new SharpDX.DXGI.SampleDescription((int)Description.MultiSampleCount, 0),
298  Usage = Usage.BackBuffer | Usage.RenderTargetOutput,
299  // Use two buffers to enable flip effect.
300  BufferCount = bufferCount,
301  Scaling = SharpDX.DXGI.Scaling.Stretch,
302  SwapEffect = SharpDX.DXGI.SwapEffect.FlipSequential,
303  };
304 
305  SwapChain swapChain = null;
306  switch (Description.DeviceWindowHandle.Context)
307  {
308  case Games.AppContextType.WindowsRuntime:
309  {
310  var nativePanel = ComObject.As<ISwapChainPanelNative>(Description.DeviceWindowHandle.NativeHandle);
311  // Creates the swap chain for XAML composition
312  swapChain = new SwapChain1(GraphicsAdapterFactory.NativeFactory, GraphicsDevice.NativeDevice, ref description);
313 
314  // Associate the SwapChainPanel with the swap chain
315  nativePanel.SwapChain = swapChain;
316  break;
317  }
318  default:
319  throw new NotSupportedException(string.Format("Window context [{0}] not supported while creating SwapChain", Description.DeviceWindowHandle.Context));
320  }
321 
322  return swapChain;
323  }
324 #else
325  private SwapChain CreateSwapChainForDesktop()
326  {
327  var control = Description.DeviceWindowHandle.NativeHandle as Control;
328  if (control == null)
329  {
330  throw new NotSupportedException(string.Format("Form of type [{0}] is not supported. Only System.Windows.Control are supported", Description.DeviceWindowHandle != null ? Description.DeviceWindowHandle.GetType().Name : "null"));
331  }
332 
333  bufferCount = 1;
334  var description = new SwapChainDescription
335  {
336  ModeDescription = new ModeDescription(Description.BackBufferWidth, Description.BackBufferHeight, Description.RefreshRate.ToSharpDX(), (SharpDX.DXGI.Format)Description.BackBufferFormat),
337  BufferCount = bufferCount, // TODO: Do we really need this to be configurable by the user?
338  OutputHandle = control.Handle,
339  SampleDescription = new SampleDescription((int)Description.MultiSampleCount, 0),
340  SwapEffect = SwapEffect.Discard,
341  Usage = SharpDX.DXGI.Usage.BackBuffer | SharpDX.DXGI.Usage.RenderTargetOutput,
342  IsWindowed = true,
343  Flags = Description.IsFullScreen ? SwapChainFlags.AllowModeSwitch : SwapChainFlags.None,
344  };
345 
346  var newSwapChain = new SwapChain(GraphicsAdapterFactory.NativeFactory, GraphicsDevice.NativeDevice, description);
347  if (Description.IsFullScreen)
348  {
349  // Before fullscreen switch
350  newSwapChain.ResizeTarget(ref description.ModeDescription);
351 
352  // Switch to full screen
353  newSwapChain.IsFullScreen = true;
354 
355  // This is really important to call ResizeBuffers AFTER switching to IsFullScreen
356  newSwapChain.ResizeBuffers(bufferCount, Description.BackBufferWidth, Description.BackBufferHeight, (SharpDX.DXGI.Format)Description.BackBufferFormat, SwapChainFlags.AllowModeSwitch);
357  }
358 
359  return newSwapChain;
360  }
361 #endif
362  }
363 }
364 #endif
HRESULT Resize(_In_ const Image &srcImage, _In_ size_t width, _In_ size_t height, _In_ DWORD filter, _Out_ ScratchImage &image)
Flags
Enumeration of the new Assimp's flags.
PresentInterval
Defines flags that describe the relationship between the adapter refresh rate and the rate at which P...
Creates a render target buffer.
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
A 2-channels stereo sounds.
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
The texture dimension is 2D.