Пример #1
0
        /// <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);
        }
Пример #2
0
        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);
        }