/// <summary> /// 從WIC Frame建立貼圖資源(非DDS) /// </summary> /// <param name="d3dContext">If a Direct3D 11 device context is provided and the current device supports it for the given pixel format, it will auto-generate mipmaps.</param> private static Result CreateWICTexture(Device device, DeviceContext d3dContext, BitmapFrameDecode frame, int maxsize, ResourceUsage usage, BindFlags bind, CpuAccessFlags cpuAccess, ResourceOptionFlags option, LoadFlags load, out Resource texture, out ShaderResourceView textureView) { texture = null; textureView = null; if (frame.Size.Width <= 0 || frame.Size.Height <= 0) { return(Result.InvalidArg); } if (maxsize == 0) { switch (device.FeatureLevel) { case FeatureLevel.Level_9_1: case FeatureLevel.Level_9_2: maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case FeatureLevel.Level_9_3: maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case FeatureLevel.Level_10_0: case FeatureLevel.Level_10_1: maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; default: maxsize = Resource.MaximumTexture2DSize; /*D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION*/ break; } } Size2 frameSize = frame.Size; Size2 targetSize; if (frameSize.Width > maxsize || frameSize.Height > maxsize) { double ratio = Convert.ToDouble(frameSize.Height) / Convert.ToDouble(frameSize.Width); if (frameSize.Width > frameSize.Height) { targetSize.Width = maxsize; targetSize.Height = Math.Max(1, Convert.ToInt32(maxsize * ratio)); } else { targetSize.Height = maxsize; targetSize.Width = Math.Max(1, Convert.ToInt32(maxsize / ratio)); } } else { targetSize = frameSize; } #region Determine format Guid sourceFormat = frame.PixelFormat; Guid targetFormat = sourceFormat; DXGI.Format format = sourceFormat.ConvertWICToDXGIFormat(); int bpp = 0; if (format == DXGI.Format.Unknown) { if (sourceFormat == PixelFormat.Format96bppRGBFixedPoint) { if (WIC2) { targetFormat = PixelFormat.Format96bppRGBFloat; format = DXGI.Format.R32G32B32_Float; bpp = 96; } else { targetFormat = PixelFormat.Format128bppRGBAFloat; format = DXGI.Format.R32G32B32A32_Float; bpp = 128; } } else { targetFormat = sourceFormat.ConvertToNearest(); format = targetFormat.ConvertWICToDXGIFormat(); bpp = PixelFormat.GetBitsPerPixel(targetFormat); } if (format == DXGI.Format.Unknown) { return(Result.GetResultFromWin32Error(unchecked ((int)0x80070032))); } } else { bpp = PixelFormat.GetBitsPerPixel(sourceFormat); } if (format == DXGI.Format.R32G32B32_Float && d3dContext != null) { // Special case test for optional device support for autogen mipchains for R32G32B32_FLOAT var formatSupport = device.CheckFormatSupport(format); if (!formatSupport.HasFlag(FormatSupport.MipAutogen)) { targetFormat = PixelFormat.Format128bppRGBAFloat; format = DXGI.Format.R32G32B32A32_Float; bpp = 128; } } if (bpp == 0) { return(Result.Fail); } if (load.HasFlag(LoadFlags.ForceSrgb)) { format = format.MakeSRgb(); } else if (!load.HasFlag(LoadFlags.ignoreSrgb)) { bool sRGB = false; try { var metareader = frame.MetadataQueryReader; var containerFormat = metareader.ContainerFormat; if (containerFormat == ContainerFormatGuids.Png) { // Check for sRGB chunk if (metareader.TryGetMetadataByName("/sRGB/RenderingIntent", out var value) == Result.Ok) { sRGB = true; } } else if (metareader.TryGetMetadataByName("System.Image.ColorSpace", out var value) == Result.Ok) { sRGB = true; } if (sRGB) { format = format.MakeSRgb(); } } catch (SharpDXException) { // BMP, ICO are not supported. } } // Verify our target format is supported by the current device var support = device.CheckFormatSupport(format); if (!support.HasFlag(FormatSupport.Texture2D)) { targetFormat = PixelFormat.Format32bppRGBA; format = DXGI.Format.R8G8B8A8_UNorm; bpp = 32; } #endregion int stride = (targetSize.Width * bpp + 7) / 8; // round int imageSize = stride * targetSize.Height; IntPtr temp = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(imageSize); if (sourceFormat == targetFormat && frameSize == targetSize) // 不需要格式轉換 且 不需要改變大小 { frame.CopyPixels(stride, new DataPointer(temp, imageSize)); } else if (frameSize == targetSize) // 需要格式轉換 { using (var factory = new ImagingFactory2()) using (var coverter = new FormatConverter(factory)) { if (coverter.CanConvert(sourceFormat, targetFormat)) { coverter.Initialize(frame, targetFormat, BitmapDitherType.ErrorDiffusion, null, 0, BitmapPaletteType.MedianCut); coverter.CopyPixels(stride, new DataPointer(temp, imageSize)); } else { return(Result.UnexpectedFailure); } } } else if (sourceFormat == targetFormat) // 需要改變大小 { using (var factory = new ImagingFactory2()) using (var scaler = new BitmapScaler(factory)) { scaler.Initialize(frame, targetSize.Width, targetSize.Height, BitmapInterpolationMode.Fant); var pfScaler = scaler.PixelFormat; if (targetFormat == pfScaler) { scaler.CopyPixels(stride, new DataPointer(temp, imageSize)); } } } else // 需要格式轉換 且 需要改變大小 { using (var factory = new ImagingFactory2()) using (var scaler = new BitmapScaler(factory)) using (var coverter = new FormatConverter(factory)) { scaler.Initialize(frame, targetSize.Width, targetSize.Height, BitmapInterpolationMode.Fant); var pfScaler = scaler.PixelFormat; if (coverter.CanConvert(pfScaler, targetFormat)) { coverter.Initialize(scaler, targetFormat, BitmapDitherType.ErrorDiffusion, null, 0, BitmapPaletteType.MedianCut); coverter.CopyPixels(stride, new DataPointer(temp, imageSize)); } else { return(Result.UnexpectedFailure); } } } var autogen = false; if (d3dContext != null) { var formatSupport = device.CheckFormatSupport(format); if (formatSupport.HasFlag(FormatSupport.MipAutogen)) { autogen = true; } } var texture2DDescription = new Texture2DDescription() { Width = targetSize.Width, Height = targetSize.Height, MipLevels = autogen ? 0 : 1, ArraySize = 1, Format = format, SampleDescription = new DXGI.SampleDescription(1, 0), Usage = usage, CpuAccessFlags = cpuAccess, }; if (autogen) { texture2DDescription.BindFlags = bind | BindFlags.RenderTarget; texture2DDescription.OptionFlags = option | ResourceOptionFlags.GenerateMipMaps; } else { texture2DDescription.BindFlags = bind; texture2DDescription.OptionFlags = option; } Result result = Result.Ok; // 建立Texture2D !!! try { if (autogen) { texture = new Texture2D(device, texture2DDescription); } else { texture = new Texture2D(device, texture2DDescription, new DataBox[] { new DataBox(temp, stride, imageSize) }); } } catch (SharpDXException e) { System.Diagnostics.Debug.WriteLine(e.ToString()); result = Result.Fail; } if (result.Success) { var SRVDesc = new ShaderResourceViewDescription() { Format = format, Dimension = ShaderResourceViewDimension.Texture2D, Texture2D = new ShaderResourceViewDescription.Texture2DResource() { MipLevels = autogen ? -1 : 1 }, }; try { textureView = new ShaderResourceView(device, texture, SRVDesc); if (autogen) { DataBox data = new DataBox(temp, stride, imageSize); d3dContext.UpdateSubresource(data, texture); d3dContext.GenerateMips(textureView); } } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.ToString()); Utilities.Dispose(ref texture); result = Result.Fail; } } // 釋放 Unmanaged 資源 System.Runtime.InteropServices.Marshal.FreeCoTaskMem(temp); return(result); }
private static Result CreateD3DResources(Device d3dDevice, ResourceDimension resourceDimension, int width, int height, int depth, int mipCount, int arraySize, DXGI.Format format, ResourceUsage usage, BindFlags bindFlags, CpuAccessFlags cpuAccessFlags, ResourceOptionFlags miscFlags, bool forceSRGB, bool isCubeMap, DataBox[] initData, out Resource texture, out ShaderResourceView textureView) { texture = null; textureView = null; if (d3dDevice == null) { return(Result.InvalidArg); } if (forceSRGB) { format = format.MakeSRgb(); } ShaderResourceViewDescription SRVDesc = new ShaderResourceViewDescription { Format = format }; switch (resourceDimension) { case ResourceDimension.Texture1D: { Texture1DDescription desc = new Texture1DDescription { Width = width, MipLevels = mipCount, ArraySize = arraySize, Format = format, Usage = usage, BindFlags = bindFlags, CpuAccessFlags = cpuAccessFlags, OptionFlags = miscFlags & ~ResourceOptionFlags.TextureCube }; Texture1D tex = new Texture1D(d3dDevice, desc, initData); if (tex != null) { if (arraySize > 1) { SRVDesc.Dimension = ShaderResourceViewDimension.Texture1DArray; SRVDesc.Texture1DArray.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; SRVDesc.Texture1DArray.ArraySize = arraySize; } else { SRVDesc.Dimension = ShaderResourceViewDimension.Texture1D; SRVDesc.Texture1D.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; } textureView = new ShaderResourceView(d3dDevice, tex, SRVDesc); if (textureView == null) { tex.Dispose(); texture = null; return(Result.Fail); } texture = tex; } else { return(Result.Fail); } } break; case ResourceDimension.Texture2D: { Texture2DDescription desc = new Texture2DDescription { Width = width, Height = height, MipLevels = mipCount, ArraySize = arraySize, Format = format, SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), Usage = usage, BindFlags = bindFlags, CpuAccessFlags = cpuAccessFlags, }; if (isCubeMap) { desc.OptionFlags = miscFlags | ResourceOptionFlags.TextureCube; } else { desc.OptionFlags = miscFlags & ~ResourceOptionFlags.TextureCube; } Texture2D tex = new Texture2D(d3dDevice, desc, initData); if (tex != null) { if (isCubeMap) { if (arraySize > 6) { SRVDesc.Dimension = ShaderResourceViewDimension.TextureCubeArray; SRVDesc.TextureCubeArray.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; // Earlier we set arraySize to (NumCubes * 6) SRVDesc.TextureCubeArray.CubeCount = arraySize / 6; } else { SRVDesc.Dimension = ShaderResourceViewDimension.TextureCube; SRVDesc.TextureCube.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; } } else if (arraySize > 1) { SRVDesc.Dimension = ShaderResourceViewDimension.Texture2DArray; SRVDesc.Texture2DArray.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; SRVDesc.Texture2DArray.ArraySize = arraySize; } else { SRVDesc.Dimension = ShaderResourceViewDimension.Texture2D; SRVDesc.Texture2D.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; } textureView = new ShaderResourceView(d3dDevice, tex, SRVDesc); if (textureView == null) { tex.Dispose(); texture = null; return(Result.Fail); } texture = tex; } else { return(Result.Fail); } } break; case ResourceDimension.Texture3D: { Texture3DDescription desc = new Texture3DDescription { Width = width, Height = height, Depth = depth, MipLevels = mipCount, Format = format, Usage = usage, BindFlags = bindFlags, CpuAccessFlags = cpuAccessFlags, OptionFlags = miscFlags & ~ResourceOptionFlags.TextureCube }; Texture3D tex = new Texture3D(d3dDevice, desc, initData); if (tex != null) { SRVDesc.Dimension = ShaderResourceViewDimension.Texture3D; SRVDesc.Texture3D.MipLevels = (mipCount == 0) ? -1 : desc.MipLevels; textureView = new ShaderResourceView(d3dDevice, tex, SRVDesc); if (textureView == null) { tex.Dispose(); texture = null; return(Result.Fail); } texture = tex; } else { return(Result.Fail); } } break; } return(Result.Ok); }