Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
Texture2DBase.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 using SiliconStudio.Core;
4 using SiliconStudio.Core.ReferenceCounting;
5 using SiliconStudio.Paradox.Games;
6 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_DIRECT3D
7 // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 using System;
27 using System.IO;
28 
29 using SharpDX.DXGI;
30 using SharpDX.Direct3D;
31 using SharpDX.Direct3D11;
32 using SharpDX.IO;
33 
34 namespace SiliconStudio.Paradox.Graphics
35 {
36  /// <summary>
37  /// A Texture 2D frontend to <see cref="SharpDX.Direct3D11.Texture2D"/>.
38  /// </summary>
39  public partial class Texture2DBase
40  {
41  private SharpDX.DXGI.Surface dxgiSurface;
42  protected internal Texture2DDescription NativeDescription;
43  internal Texture2D TextureDepthStencilBuffer;
44 
45  /// <summary>
46  /// Initializes a new instance of the <see cref="Texture2DBase" /> class.
47  /// </summary>
48  /// <param name="device">The <see cref="GraphicsDevice"/>.</param>
49  /// <param name="description2D">The description.</param>
50  /// <param name="dataBoxes">A variable-length parameters list containing data rectangles.</param>
51  protected internal Texture2DBase(GraphicsDevice device, TextureDescription description2D, DataBox[] dataBoxes = null)
52  : base(device, CheckMipLevels(device, ref description2D), ViewType.Full, 0, 0)
53  {
54  NativeDescription = ConvertToNativeDescription(device, description2D);
55  //System.Diagnostics.Debug.WriteLine("Texture2D {0}x{1} {2}", NativeDescription.Width, NativeDescription.Height, NativeDescription.Format);
56  NativeDeviceChild = new SharpDX.Direct3D11.Texture2D(device.NativeDevice, NativeDescription, ConvertDataBoxes(dataBoxes));
57  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
58  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
59 
60  // If we have a depthStencilBufferForShaderResource, then we should override the default shader resource view
61  if (TextureDepthStencilBuffer != null)
62  nativeShaderResourceView = TextureDepthStencilBuffer.nativeShaderResourceView;
63  }
64 
65  /// <summary>
66  /// Specialised constructor for use only by derived classes.
67  /// </summary>
68  /// <param name="device">The <see cref="GraphicsDevice" />.</param>
69  /// <param name="texture">The texture.</param>
70  protected internal Texture2DBase(GraphicsDevice device, Texture2DBase texture, ViewType viewType, int viewArraySlice, int viewMipLevel, PixelFormat viewFormat = PixelFormat.None)
71  : base(device, texture, viewType, viewArraySlice, viewMipLevel, viewFormat)
72  {
73  // Copy the device child, but don't use NativeDeviceChild, as it is registering it for disposing.
74  _nativeDeviceChild = texture._nativeDeviceChild;
75  NativeResource = texture.NativeResource;
76  NativeDescription = texture.NativeDescription;
77  NativeShaderResourceView = GetShaderResourceView(viewType, viewArraySlice, viewMipLevel);
78  NativeUnorderedAccessView = GetUnorderedAccessView(viewArraySlice, viewMipLevel);
79  dxgiSurface = texture.dxgiSurface;
80  }
81 
82  /// <summary>
83  /// Specialised constructor for use only by derived classes.
84  /// </summary>
85  /// <param name="device">The <see cref="GraphicsDevice"/>.</param>
86  /// <param name="texture">The texture.</param>
87  protected internal Texture2DBase(GraphicsDevice device, SharpDX.Direct3D11.Texture2D texture)
88  : base(device, ConvertFromNativeDescription(texture.Description), ViewType.Full, 0, 0)
89  {
90  // Copy the device child, but don't use NativeDeviceChild, as it is registering it for disposing.
91  NativeDescription = texture.Description;
92  NativeDeviceChild = texture;
93  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
94  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
95  }
96 
97  internal override ShaderResourceView GetShaderResourceView(ViewType viewType, int arrayOrDepthSlice, int mipIndex)
98  {
99  if ((this.NativeDescription.BindFlags & BindFlags.ShaderResource) == 0)
100  return null;
101 
102  int arrayCount;
103  int mipCount;
104  GetViewSliceBounds(viewType, ref arrayOrDepthSlice, ref mipIndex, out arrayCount, out mipCount);
105 
106  // Create the view
107  var srvDescription = new ShaderResourceViewDescription() { Format = ComputeShaderResourceViewFormat()};
108 
109  // Initialize for texture arrays or texture cube
110  if (this.Description.ArraySize > 1)
111  {
112  // If texture cube
113  if ((this.NativeDescription.OptionFlags & ResourceOptionFlags.TextureCube) != 0)
114  {
115  srvDescription.Dimension = ShaderResourceViewDimension.TextureCube;
116  srvDescription.TextureCube.MipLevels = mipCount;
117  srvDescription.TextureCube.MostDetailedMip = mipIndex;
118  }
119  else
120  {
121  // Else regular Texture2D
122  srvDescription.Dimension = this.NativeDescription.SampleDescription.Count > 1 ? ShaderResourceViewDimension.Texture2DMultisampledArray : ShaderResourceViewDimension.Texture2DArray;
123 
124  // Multisample?
125  if (this.NativeDescription.SampleDescription.Count > 1)
126  {
127  srvDescription.Texture2DMSArray.ArraySize = arrayCount;
128  srvDescription.Texture2DMSArray.FirstArraySlice = arrayOrDepthSlice;
129  }
130  else
131  {
132  srvDescription.Texture2DArray.ArraySize = arrayCount;
133  srvDescription.Texture2DArray.FirstArraySlice = arrayOrDepthSlice;
134  srvDescription.Texture2DArray.MipLevels = mipCount;
135  srvDescription.Texture2DArray.MostDetailedMip = mipIndex;
136  }
137  }
138  }
139  else
140  {
141  srvDescription.Dimension = this.NativeDescription.SampleDescription.Count > 1 ? ShaderResourceViewDimension.Texture2DMultisampled : ShaderResourceViewDimension.Texture2D;
142  if (this.NativeDescription.SampleDescription.Count <= 1)
143  {
144  srvDescription.Texture2D.MipLevels = mipCount;
145  srvDescription.Texture2D.MostDetailedMip = mipIndex;
146  }
147  }
148 
149  // Default ShaderResourceView
150  return new ShaderResourceView(this.GraphicsDevice.NativeDevice, NativeResource, srvDescription);
151  }
152 
153  /// <inheritdoc/>
154  protected internal override void OnDestroyed()
155  {
156  base.OnDestroyed();
157  DestroyImpl();
158  }
159 
160  /// <inheritdoc/>
161  protected internal override bool OnRecreate()
162  {
163  // Dependency: wait for underlying texture to be recreated
164  if (ParentTexture != null && ParentTexture.LifetimeState != GraphicsResourceLifetimeState.Active)
165  return false;
166 
167  base.OnRecreate();
168 
169  // Only a view?
170  if (ParentTexture != null)
171  {
172  // Copy the device child, but don't use NativeDeviceChild, as it is registering it for disposing.
173  _nativeDeviceChild = ParentTexture._nativeDeviceChild;
174  NativeResource = ParentTexture.NativeResource;
175  NativeDescription = ((Texture2D)ParentTexture).NativeDescription;
176  dxgiSurface = ((Texture2D)ParentTexture).dxgiSurface;
177 
178  return true;
179  }
180  else
181  {
182  // Render Target / Depth Stencil are considered as "dynamic"
183  if ((Description.Usage == GraphicsResourceUsage.Immutable
184  || Description.Usage == GraphicsResourceUsage.Default)
185  && (NativeDescription.BindFlags & (BindFlags.RenderTarget | BindFlags.DepthStencil)) == 0)
186  return false;
187 
188  NativeDeviceChild = new SharpDX.Direct3D11.Texture2D(GraphicsDevice.NativeDevice, NativeDescription);
189  }
190 
191  // Recreate SRV/UAV
192  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
193  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
194 
195  // If we have a depthStencilBufferForShaderResource, then we should override the default shader resource view
196  if (TextureDepthStencilBuffer != null)
197  nativeShaderResourceView = TextureDepthStencilBuffer.nativeShaderResourceView;
198 
199  return true;
200  }
201 
202  public override Texture Clone()
203  {
204  throw new NotImplementedException();
205  }
206 
207  internal void Recreate(Texture2DDescription description)
208  {
209  NativeDescription = description;
210  NativeDeviceChild = new SharpDX.Direct3D11.Texture2D(GraphicsDevice.NativeDevice, NativeDescription);
211  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
212  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
213 
214  // If we have a depthStencilBufferForShaderResource, then we should override the default shader resource view
215  if (TextureDepthStencilBuffer != null)
216  nativeShaderResourceView = TextureDepthStencilBuffer.nativeShaderResourceView;
217  }
218 
219  internal void Recreate(SharpDX.Direct3D11.Texture2D texture2D)
220  {
221  NativeDescription = texture2D.Description;
222  NativeDeviceChild = texture2D;
223  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
224  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
225 
226  // If we have a depthStencilBufferForShaderResource, then we should override the default shader resource view
227  if (TextureDepthStencilBuffer != null)
228  nativeShaderResourceView = TextureDepthStencilBuffer.nativeShaderResourceView;
229  }
230 
231  public override void Recreate(DataBox[] dataBoxes = null)
232  {
233  NativeDeviceChild = new SharpDX.Direct3D11.Texture2D(GraphicsDevice.NativeDevice, NativeDescription, ConvertDataBoxes(dataBoxes));
234  NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel);
235  NativeUnorderedAccessView = GetUnorderedAccessView(ArraySlice, MipLevel);
236 
237  // If we have a depthStencilBufferForShaderResource, then we should override the default shader resource view
238  if (TextureDepthStencilBuffer != null)
239  nativeShaderResourceView = TextureDepthStencilBuffer.nativeShaderResourceView;
240  }
241 
242  private Format ComputeShaderResourceViewFormat()
243  {
244  var format = NativeDescription.Format;
245  Format viewFormat = format;
246 
247  // Special case for DepthStencil ShaderResourceView that are bound as Float
248  if ((Description.Flags & TextureFlags.DepthStencil) != 0)
249  {
250  // Determine TypeLess Format and ShaderResourceView Format
251  switch (format)
252  {
253  case SharpDX.DXGI.Format.R16_Typeless:
254  viewFormat = SharpDX.DXGI.Format.R16_Float;
255  break;
256  case SharpDX.DXGI.Format.R32_Typeless:
257  viewFormat = SharpDX.DXGI.Format.R32_Float;
258  break;
259  case SharpDX.DXGI.Format.R24G8_Typeless:
260  viewFormat = SharpDX.DXGI.Format.R24_UNorm_X8_Typeless;
261  break;
262  case SharpDX.DXGI.Format.R32G8X24_Typeless:
263  viewFormat = SharpDX.DXGI.Format.R32_Float_X8X24_Typeless;
264  break;
265  }
266  }
267 
268  return viewFormat;
269  }
270 
271  internal override UnorderedAccessView GetUnorderedAccessView(int arrayOrDepthSlice, int mipIndex)
272  {
273  if ((this.NativeDescription.BindFlags & BindFlags.UnorderedAccess) == 0)
274  return null;
275 
276  int arrayCount;
277  int mipCount;
278  GetViewSliceBounds(ViewType.Single, ref arrayOrDepthSlice, ref mipIndex, out arrayCount, out mipCount);
279 
280  var uavDescription = new UnorderedAccessViewDescription()
281  {
282  Format = (Format)this.Description.Format,
283  Dimension = this.Description.ArraySize > 1 ? UnorderedAccessViewDimension.Texture2DArray : UnorderedAccessViewDimension.Texture2D
284  };
285 
286  if (this.Description.ArraySize > 1)
287  {
288  uavDescription.Texture2DArray.ArraySize = arrayCount;
289  uavDescription.Texture2DArray.FirstArraySlice = arrayOrDepthSlice;
290  uavDescription.Texture2DArray.MipSlice = mipIndex;
291  }
292  else
293  {
294  uavDescription.Texture2D.MipSlice = mipIndex;
295  }
296 
297  return new UnorderedAccessView(GraphicsDevice.NativeDevice, NativeResource, uavDescription);
298  }
299 
300  internal override RenderTargetView GetRenderTargetView(ViewType viewType, int arrayOrDepthSlice, int mipIndex)
301  {
302  if ((this.NativeDescription.BindFlags & BindFlags.RenderTarget) == 0)
303  return null;
304 
305  if (viewType == ViewType.MipBand)
306  throw new NotSupportedException("ViewSlice.MipBand is not supported for render targets");
307 
308  int arrayCount;
309  int mipCount;
310  GetViewSliceBounds(viewType, ref arrayOrDepthSlice, ref mipIndex, out arrayCount, out mipCount);
311 
312  // Create the render target view
313  var rtvDescription = new RenderTargetViewDescription() { Format = this.NativeDescription.Format };
314 
315  if (this.Description.ArraySize > 1)
316  {
317  rtvDescription.Dimension = this.NativeDescription.SampleDescription.Count > 1 ? RenderTargetViewDimension.Texture2DMultisampledArray : RenderTargetViewDimension.Texture2DArray;
318  if (this.NativeDescription.SampleDescription.Count > 1)
319  {
320  rtvDescription.Texture2DMSArray.ArraySize = arrayCount;
321  rtvDescription.Texture2DMSArray.FirstArraySlice = arrayOrDepthSlice;
322  }
323  else
324  {
325  rtvDescription.Texture2DArray.ArraySize = arrayCount;
326  rtvDescription.Texture2DArray.FirstArraySlice = arrayOrDepthSlice;
327  rtvDescription.Texture2DArray.MipSlice = mipIndex;
328  }
329  }
330  else
331  {
332  rtvDescription.Dimension = this.NativeDescription.SampleDescription.Count > 1 ? RenderTargetViewDimension.Texture2DMultisampled : RenderTargetViewDimension.Texture2D;
333  if (this.NativeDescription.SampleDescription.Count <= 1)
334  rtvDescription.Texture2D.MipSlice = mipIndex;
335  }
336 
337  return new RenderTargetView(GraphicsDevice.NativeDevice, NativeResource, rtvDescription);
338  }
339 
340  protected static TextureDescription ConvertFromNativeDescription(Texture2DDescription description)
341  {
342  var desc = new TextureDescription()
343  {
344  Dimension = TextureDimension.Texture2D,
345  Width = description.Width,
346  Height = description.Height,
347  Depth = 1,
348  Level = (MSAALevel)description.SampleDescription.Count,
349  Format = (PixelFormat)description.Format,
350  MipLevels = description.MipLevels,
351  Usage = (GraphicsResourceUsage)description.Usage,
352  ArraySize = description.ArraySize,
353  Flags = TextureFlags.None
354  };
355 
356  if ((description.BindFlags & BindFlags.RenderTarget) !=0)
357  desc.Flags |= TextureFlags.RenderTarget;
358  if ((description.BindFlags & BindFlags.UnorderedAccess) != 0)
359  desc.Flags |= TextureFlags.UnorderedAccess;
360  if ((description.BindFlags & BindFlags.DepthStencil) != 0)
361  desc.Flags |= TextureFlags.DepthStencil;
362  if ((description.BindFlags & BindFlags.ShaderResource) != 0)
363  desc.Flags |= TextureFlags.ShaderResource;
364 
365  return desc;
366  }
367 
368  protected static Texture2DDescription ConvertToNativeDescription(GraphicsDevice device, TextureDescription description)
369  {
370  var format = (Format) description.Format;
371  var flags = description.Flags;
372 
373  // If the texture is going to be bound on the depth stencil, for to use TypeLess format
374  if ((flags & TextureFlags.DepthStencil) != 0)
375  {
376  if (device.Features.Profile < GraphicsProfile.Level_10_0)
377  {
378  flags &= ~TextureFlags.ShaderResource;
379  }
380  else
381  {
382  // Determine TypeLess Format and ShaderResourceView Format
383  switch (description.Format)
384  {
385  case PixelFormat.D16_UNorm:
386  format = SharpDX.DXGI.Format.R16_Typeless;
387  break;
388  case PixelFormat.D32_Float:
389  format = SharpDX.DXGI.Format.R32_Typeless;
390  break;
391  case PixelFormat.D24_UNorm_S8_UInt:
392  format = SharpDX.DXGI.Format.R24G8_Typeless;
393  break;
394  case PixelFormat.D32_Float_S8X24_UInt:
395  format = SharpDX.DXGI.Format.R32G8X24_Typeless;
396  break;
397  default:
398  throw new InvalidOperationException(string.Format("Unsupported DepthFormat [{0}] for depth buffer", description.Format));
399  }
400  }
401  }
402 
403  var desc = new Texture2DDescription()
404  {
405  Width = description.Width,
406  Height = description.Height,
407  ArraySize = description.ArraySize,
408  // TODO calculate appropriate MultiSamples
409  SampleDescription = new SampleDescription(1, 0),
410  BindFlags = GetBindFlagsFromTextureFlags(flags),
411  Format = format,
412  MipLevels = description.MipLevels,
413  Usage = (ResourceUsage)description.Usage,
414  CpuAccessFlags = GetCpuAccessFlagsFromUsage(description.Usage),
415  OptionFlags = ResourceOptionFlags.None
416  };
417 
418  if (description.Dimension == TextureDimension.TextureCube)
419  desc.OptionFlags = ResourceOptionFlags.TextureCube;
420 
421  return desc;
422  }
423 
424  #region Helper functions
425 
426  /// <summary>
427  /// Check and modify if necessary the mipmap levels of the image (Troubles with DXT images whose resolution in less than 4x4 in DX9.x).
428  /// </summary>
429  /// <param name="device">The graphics device.</param>
430  /// <param name="description">The texture description.</param>
431  /// <returns>The updated texture description.</returns>
432  private static TextureDescription CheckMipLevels(GraphicsDevice device, ref TextureDescription description)
433  {
434  if (device.Features.Profile < GraphicsProfile.Level_10_0 && (description.Flags & TextureFlags.DepthStencil) == 0 && description.Format.IsCompressed())
435  {
436  description.MipLevels = Math.Min(CalculateMipCount(description.Width, description.Height), description.MipLevels);
437  }
438  return description;
439  }
440 
441  /// <summary>
442  /// Calculates the mip level from a specified size.
443  /// </summary>
444  /// <param name="size">The size.</param>
445  /// <param name="minimumSizeLastMip">The minimum size of the last mip.</param>
446  /// <returns>The mip level.</returns>
447  /// <exception cref="System.ArgumentOutOfRangeException">Value must be > 0;size</exception>
448  private static int CalculateMipCountFromSize(int size, int minimumSizeLastMip = 4)
449  {
450  if (size <= 0)
451  {
452  throw new ArgumentOutOfRangeException("Value must be > 0", "size");
453  }
454 
455  if (minimumSizeLastMip <= 0)
456  {
457  throw new ArgumentOutOfRangeException("Value must be > 0", "minimumSizeLastMip");
458  }
459 
460  int level = 1;
461  while ((size / 2) >= minimumSizeLastMip)
462  {
463  size = Math.Max(1, size / 2);
464  level++;
465  }
466  return level;
467  }
468 
469  /// <summary>
470  /// Calculates the mip level from a specified width,height,depth.
471  /// </summary>
472  /// <param name="width">The width.</param>
473  /// <param name="height">The height.</param>
474  /// <param name="minimumSizeLastMip">The minimum size of the last mip.</param>
475  /// <returns>The mip level.</returns>
476  /// <exception cref="System.ArgumentOutOfRangeException">Value must be &gt; 0;size</exception>
477  private static int CalculateMipCount(int width, int height, int minimumSizeLastMip = 4)
478  {
479  return Math.Min(CalculateMipCountFromSize(width, minimumSizeLastMip), CalculateMipCountFromSize(height, minimumSizeLastMip));
480  }
481 
482  #endregion
483  }
484 }
485 #endif
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
GraphicsResourceUsage
Identifies expected resource use during rendering. The usage directly reflects whether a resource is ...
MSAALevel
Multisample count level.
Definition: MSAALevel.cs:29
The clone mixin to clone the current mixins where the clone is emitted.
TextureDimension
Defines the dimension of a texture.
Flags
Enumeration of the new Assimp's flags.
ViewType
Defines how a view is selected from a resource.
Definition: ViewType.cs:31
Same as Deferred mode, except sprites are sorted by texture prior to drawing. This can improve perfor...
Gets a texture view for the whole texture for all mips/arrays dimensions.
GraphicsResourceLifetimeState
Describes the lifetime state of a graphics resource.
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
GraphicsProfile
Identifies the set of supported devices for the demo based on device capabilities.
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
The texture dimension is 2D.