/// <summary> /// Function to create a new texture that is bindable to the GPU. /// </summary> /// <param name="graphics">The graphics interface to use when creating the target.</param> /// <param name="info">The information about the texture.</param> /// <param name="initialData">[Optional] Initial data used to populate the texture.</param> /// <returns>A new <see cref="GorgonTexture2DView"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, or <paramref name="info"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// This is a convenience method that will create a <see cref="GorgonTexture2D"/> and a <see cref="GorgonTexture2DView"/> as a single object that users can use to apply a texture as a shader /// resource. This helps simplify creation of a texture by executing some prerequisite steps on behalf of the user. /// </para> /// <para> /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonTexture2DView"/> returned, disposal of either one will dispose of the other on your behalf. If /// the user created a <see cref="GorgonTexture2DView"/> from the <see cref="GorgonTexture2D.GetShaderResourceView"/> method on the <see cref="GorgonTexture2D"/>, then it's assumed the user knows /// what they are doing and will handle the disposal of the texture and view on their own. /// </para> /// <para> /// If an <paramref name="initialData"/> image is provided, and the width/height/depth is not the same as the values in the <paramref name="info"/> parameter, then the image data will be cropped to /// match the values in the <paramref name="info"/> parameter. Things like array count, and mip levels will still be taken from the <paramref name="initialData"/> image parameter. /// </para> /// </remarks> /// <seealso cref="GorgonTexture2D"/> public static GorgonTexture2DView CreateTexture(GorgonGraphics graphics, IGorgonTexture2DInfo info, IGorgonImage initialData = null) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } if (initialData != null) { if ((initialData.Width < info.Width) || (initialData.Height < info.Height)) { initialData.Expand(info.Width, info.Height, 1); } if ((initialData.Width > info.Width) || (initialData.Height > info.Height)) { initialData.Crop(new DX.Rectangle(0, 0, info.Width, info.Height), 1); } } var newInfo = new GorgonTexture2DInfo(info) { Usage = info.Usage == ResourceUsage.Staging ? ResourceUsage.Default : info.Usage, Binding = (info.Binding & TextureBinding.ShaderResource) != TextureBinding.ShaderResource ? (info.Binding | TextureBinding.ShaderResource) : info.Binding }; GorgonTexture2D texture = initialData == null ? new GorgonTexture2D(graphics, newInfo) : initialData.ToTexture2D(graphics, new GorgonTexture2DLoadOptions { Usage = newInfo.Usage, Binding = newInfo.Binding, MultisampleInfo = newInfo.MultisampleInfo, Name = newInfo.Name, IsTextureCube = newInfo.IsCubeMap }); GorgonTexture2DView result = texture.GetShaderResourceView(); result.OwnsResource = true; return(result); }
/// <summary> /// Function to rent a render target from the factory. /// </summary> /// <param name="targetInfo">The information about the render target to retrieve.</param> /// <param name="name">A unique user defined name for a new render target.</param> /// <param name="clearOnRetrieve">[Optional] <b>true</b> to clear the render target when retrieved, or <b>false</b> to leave the contents as-is.</param> /// <returns>The requested render target.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="targetInfo"/>, or the <paramref name="name"/> parameter is <b>null</b>.</exception> /// <exception cref="ArgumentException">Thrown when the <paramref name="name"/> parameter is empty.</exception> /// <remarks> /// <para> /// All calls to this method should be paired with a call to the <see cref="Return"/> method. Failure to do so may result in a leak. /// </para> /// <para> /// The optional <paramref name="clearOnRetrieve"/> parameter, if set to <b>true</b>,, will clear the contents of a render target that is being reused /// prior to returning it. In some cases this is not ideal, so setting it to <b>false</b> will preserve the contents. New render targets will always /// be cleared. /// </para> /// <note type="caution"> /// <para> /// For performance reasons, any exceptions thrown from this method will only be thrown when Gorgon is compiled as DEBUG. /// </para> /// </note> /// </remarks> public GorgonRenderTarget2DView Rent(IGorgonTexture2DInfo targetInfo, string name, bool clearOnRetrieve = true) { name.ValidateString(nameof(name)); targetInfo.ValidateObject(nameof(targetInfo)); ExpireTargets(); // Ensure the information is valid. GorgonTexture2DInfo newInfo = _textureInfoAllocator.Allocate(); newInfo.Copy(name, targetInfo); newInfo.Binding = targetInfo.Binding | TextureBinding.RenderTarget | TextureBinding.ShaderResource; newInfo.Usage = ResourceUsage.Default; for (int i = 0; i < _renderTargets.Count; ++i) { GorgonRenderTarget2DView rtv = _renderTargets[i]; GorgonTexture2D target = _renderTargets[i].Texture; if ((!_rented.Contains(rtv)) && (target.Width == newInfo.Width) && (target.Height == newInfo.Height) && (target.MipLevels == newInfo.MipLevels) && (target.ArrayCount == newInfo.ArrayCount) && (target.Format == newInfo.Format) && (target.Binding == newInfo.Binding) && (target.MultisampleInfo.Equals(newInfo.MultisampleInfo)) && (newInfo.IsCubeMap == target.IsCubeMap) && (string.Equals(newInfo.Name, rtv.Texture.Name, StringComparison.OrdinalIgnoreCase))) { if (clearOnRetrieve) { rtv.Clear(GorgonColor.BlackTransparent); } _renderTargets.Remove(rtv); _expiryTime.Remove(rtv); _rented.Add(rtv); return(rtv); } } if (_renderTargets.Count == 0) { _expiryTimer.Reset(); } var newRtv = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, newInfo); // Cache a default shader resource view (the texture holds the cache, we hold a separate one so we can clean it up later). _srvs.Add(newRtv.GetShaderResourceView()); newRtv.OwnerFactory = this; _rented.Add(newRtv); newRtv.Clear(GorgonColor.BlackTransparent); return(newRtv); }
/// <summary> /// Function to rent a render target from the factory. /// </summary> /// <param name="targetInfo">The information about the render target to retrieve.</param> /// <param name="name">[Optional] A user defined name for a new render target.</param> /// <param name="clearOnRetrieve">[Optional] <b>true</b> to clear the render target when retrieved, or <b>false</b> to leave the contents as-is.</param> /// <returns>The requested render target.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="targetInfo"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// All calls to this method should be paired with a call to the <see cref="Return"/> method. Failure to do so may result in a leak. /// </para> /// <para> /// The optional <paramref name="clearOnRetrieve"/> parameter, if set to <b>true</b>,, will clear the contents of a render target that is being reused /// prior to returning it. In some cases this is not ideal, so setting it to <b>false</b> will preserve the contents. New render targets will always /// be cleared. /// </para> /// <note type="caution"> /// <para> /// For performance reasons, any exceptions thrown from this method will only be thrown when Gorgon is compiled as DEBUG. /// </para> /// </note> /// </remarks> public GorgonRenderTarget2DView Rent(IGorgonTexture2DInfo targetInfo, string name = null, bool clearOnRetrieve = true) { targetInfo.ValidateObject(nameof(targetInfo)); // Ensure the information is valid. targetInfo = new GorgonTexture2DInfo(targetInfo, string.IsNullOrWhiteSpace(name) ? $"TempTarget_{_srvs.Count}_{targetInfo.Name}" : name) { Binding = targetInfo.Binding | TextureBinding.RenderTarget, Usage = ResourceUsage.Default }; for (int i = 0; i < _renderTargets.Count; ++i) { GorgonRenderTarget2DView rtv = _renderTargets[i]; GorgonTexture2D target = _renderTargets[i].Texture; if ((!_rented.Contains(rtv)) && (target.Width == targetInfo.Width) && (target.Height == targetInfo.Height) && (target.MipLevels == targetInfo.MipLevels) && (target.ArrayCount == targetInfo.ArrayCount) && (target.Format == targetInfo.Format) && (target.Binding == targetInfo.Binding) && (target.MultisampleInfo.Equals(targetInfo.MultisampleInfo)) && (targetInfo.IsCubeMap == target.IsCubeMap)) { if (clearOnRetrieve) { rtv.Clear(GorgonColor.BlackTransparent); } _renderTargets.Remove(rtv); _rented.Add(rtv); return(rtv); } } var newRtv = GorgonRenderTarget2DView.CreateRenderTarget(_graphics, targetInfo); // Cache a default shader resource view (the texture holds the cache, we hold a separate one so we can clean it up later). _srvs.Add(newRtv.GetShaderResourceView()); newRtv.OwnerFactory = this; _rented.Add(newRtv); newRtv.Clear(GorgonColor.BlackTransparent); return(newRtv); }
/// <summary> /// Function to create a new render target that is bindable to the GPU. /// </summary> /// <param name="graphics">The graphics interface to use when creating the target.</param> /// <param name="info">The information about the texture.</param> /// <param name="arrayIndex">[Optional] The index of a texture array to slice the view at.</param> /// <param name="arrayCount">[Optioanl] The number of array indices to view.</param> /// <returns>A new <see cref="GorgonRenderTarget2DView"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, or <paramref name="info"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// This is a convenience method that will create a <see cref="GorgonTexture2D"/> and a <see cref="GorgonRenderTarget2DView"/> as a single object that users can use to apply a render target texture. /// This helps simplify creation of a render target by executing some prerequisite steps on behalf of the user. /// </para> /// <para> /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonRenderTarget2DView"/> returned, disposal of either one will dispose of the other on your behalf. /// If the user created a <see cref="GorgonRenderTarget2DView"/> from the <see cref="GorgonTexture2D.GetRenderTargetView"/> method on the <see cref="GorgonTexture2D"/>, then it's assumed the user /// knows what they are doing and will handle the disposal of the texture and view on their own. /// </para> /// </remarks> /// <seealso cref="GorgonTexture2D"/> public static GorgonRenderTarget2DView CreateRenderTarget(GorgonGraphics graphics, IGorgonTexture2DInfo info, int arrayIndex = 0, int?arrayCount = null) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } TextureBinding binding = TextureBinding.RenderTarget; if ((info.Binding & TextureBinding.ShaderResource) == TextureBinding.ShaderResource) { binding |= TextureBinding.ShaderResource; } if ((info.Binding & TextureBinding.ShaderResource) == TextureBinding.ReadWriteView) { binding |= TextureBinding.ReadWriteView; } var newInfo = new GorgonTexture2DInfo(info) { Usage = ResourceUsage.Default, Binding = binding }; var texture = new GorgonTexture2D(graphics, newInfo); GorgonRenderTarget2DView result = texture.GetRenderTargetView(arrayIndex: arrayIndex, arrayCount: arrayCount ?? 1); result.OwnsResource = true; return(result); }
/// <summary> /// Function to create a new depth/stencil buffer that is bindable to the GPU. /// </summary> /// <param name="graphics">The graphics interface to use when creating the target.</param> /// <param name="info">The information about the depth/stencil texture.</param> /// <param name="viewFlags">[Optional] Flags used to determine if the depth buffer/stencil can be read by the GPU or not.</param> /// <returns>A new <see cref="GorgonDepthStencil2DView"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="graphics"/>, or <paramref name="info"/> parameter is <b>null</b>.</exception> /// <remarks> /// <para> /// This is a convenience method that will create a <see cref="GorgonTexture2D"/> and a <see cref="GorgonDepthStencil2DView"/> as a single object that users can use to apply a depth/stencil texture. /// This helps simplify creation of a render target by executing some prerequisite steps on behalf of the user. /// </para> /// <para> /// Since the <see cref="GorgonTexture2D"/> created by this method is linked to the <see cref="GorgonDepthStencil2DView"/> returned, disposal of either one will dispose of the other on your behalf. /// If the user created a <see cref="GorgonDepthStencil2DView"/> from the <see cref="GorgonTexture2D.GetRenderTargetView"/> method on the <see cref="GorgonTexture2D"/>, then it's assumed the user /// knows what they are doing and will handle the disposal of the texture and view on their own. /// </para> /// <para> /// To make the texture bindable on the GPU as a shader resource view, set the <see cref="IGorgonTexture2DInfo.Binding"/> to include the <see cref="TextureBinding.ShaderResource"/> flag in the value /// and set the <paramref name="viewFlags"/> to <see cref="DepthStencilViewFlags.ReadOnlyDepth"/>, <see cref="DepthStencilViewFlags.ReadOnlyStencil"/> or both. /// </para> /// </remarks> /// <seealso cref="GorgonTexture2D"/> public static GorgonDepthStencil2DView CreateDepthStencil(GorgonGraphics graphics, IGorgonTexture2DInfo info, DepthStencilViewFlags viewFlags = DepthStencilViewFlags.None) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } if (info == null) { throw new ArgumentNullException(nameof(info)); } TextureBinding binding = TextureBinding.DepthStencil; if ((info.Binding & TextureBinding.ShaderResource) == TextureBinding.ShaderResource) { if (viewFlags != DepthStencilViewFlags.None) { binding |= TextureBinding.ShaderResource; } else { // Do this to notify the user that something is amiss. graphics.Log.Print($"WARNING: Depth Stencil View {info.Name} - Depth/stencil texture has a binding of {TextureBinding.ShaderResource}, but has a view flags of {viewFlags}. The view will not be bindable to the shader pipeline.", LoggingLevel.Simple); } } else if (viewFlags != DepthStencilViewFlags.None) { // Do this to notify the user that something is amiss. graphics.Log.Print($"WARNING: Depth Stencil View {info.Name} - Depth/stencil view flag(s) are set to {viewFlags}, but the texture lacks a {TextureBinding.ShaderResource} binding.", LoggingLevel.Simple); } var newInfo = new GorgonTexture2DInfo(info) { // Can't see a reason to use anything other than default for dsvs Usage = ResourceUsage.Default, Binding = binding }; BufferFormat depthStencilFormat = newInfo.Format; if (((binding & TextureBinding.ShaderResource) == TextureBinding.ShaderResource) && (viewFlags != DepthStencilViewFlags.None)) { switch (newInfo.Format) { case BufferFormat.R32G8X24_Typeless: depthStencilFormat = BufferFormat.D32_Float_S8X24_UInt; break; case BufferFormat.R24G8_Typeless: depthStencilFormat = BufferFormat.D24_UNorm_S8_UInt; break; case BufferFormat.R16_Typeless: depthStencilFormat = BufferFormat.D16_UNorm; break; case BufferFormat.R32_Typeless: depthStencilFormat = BufferFormat.D32_Float; break; } } var texture = new GorgonTexture2D(graphics, newInfo); GorgonDepthStencil2DView result = texture.GetDepthStencilView(depthStencilFormat, flags: viewFlags); result.OwnsResource = true; return(result); }