コード例 #1
0
ファイル: Chunk.cs プロジェクト: ylyking/RdcFileRepack
        public override void Load(ChunkMeta meta, BinaryReader br)
        {
            base.Load(meta, br);

            uint Buffer = br.ReadUInt32();

            resourceId           = br.ReadUInt64(); // SwapbufferID
            BackbufferDescriptor = D3D11Reader.Read_D3D11_TEXTURE2D_DESC(br) as D3D11_TEXTURE2D_DESC;

            name = "Serialised Swap Chain Buffer"; // fakeBB
        }
コード例 #2
0
        public virtual void GetDesc(
            out D3D11_TEXTURE2D_DESC pDesc
            )
        {
            var fp = GetFunctionPointer(10);

            if (m_GetDescFunc == null)
            {
                m_GetDescFunc = (GetDescFunc)Marshal.GetDelegateForFunctionPointer(fp, typeof(GetDescFunc));
            }

            m_GetDescFunc(m_ptr, out pDesc);
        }
コード例 #3
0
ファイル: ID3D11Device.cs プロジェクト: ousttrue/ShrimpDX
        public virtual int CreateTexture2D(
            ref D3D11_TEXTURE2D_DESC pDesc,
            ref D3D11_SUBRESOURCE_DATA pInitialData,
            out ID3D11Texture2D ppTexture2D
            )
        {
            var fp = GetFunctionPointer(5);

            if (m_CreateTexture2DFunc == null)
            {
                m_CreateTexture2DFunc = (CreateTexture2DFunc)Marshal.GetDelegateForFunctionPointer(fp, typeof(CreateTexture2DFunc));
            }
            ppTexture2D = new ID3D11Texture2D();
            return(m_CreateTexture2DFunc(m_ptr, ref pDesc, ref pInitialData, out ppTexture2D.PtrForNew));
        }
コード例 #4
0
        ID3D11RenderTargetView Begin(HWND hWnd, out float width, out float height)
        {
            using (var texture = m_swapchain.GetBackbuffer(m_d3d11.Device, hWnd.Value))
            {
                var desc = new D3D11_TEXTURE2D_DESC();
                texture.GetDesc(ref desc);
                width  = (float)desc.Width;
                height = (float)desc.Height;

                var rtv_desc = new D3D11_RENDER_TARGET_VIEW_DESC
                {
                    Format        = desc.Format,
                    ViewDimension = D3D11_RTV_DIMENSION.TEXTURE2D
                };
                var rtv = new ID3D11RenderTargetView();
                m_d3d11.Device.CreateRenderTargetView(texture.Ptr, ref rtv_desc, ref rtv.PtrForNew).ThrowIfFailed();
                return(rtv);
            }
        }
コード例 #5
0
ファイル: Chunk.cs プロジェクト: ylyking/RdcFileRepack
        public override void Load(ChunkMeta meta, BinaryReader br)
        {
            base.Load(meta, br);
            Descriptor = D3D11Reader.Read_D3D11_TEXTURE2D_DESC(br) as D3D11_TEXTURE2D_DESC;

            // unused, just for the sake of the user
            {
                uint numSubresources = Descriptor.MipLevels != 0
                                           ? Descriptor.MipLevels
                                           : Common.CalcNumMips(Descriptor.Width, Descriptor.Height, 1);
                numSubresources *= Descriptor.ArraySize;

                pInitialDatas = D3D11Reader.Read_D3D11_Array <D3D11_SUBRESOURCE_DATA>(br); // 初始化第一步
                resourceId    = br.ReadUInt64();

                if (pInitialDatas != null)
                {
                    D3D11Reader.Read_CreateTextureData(br, pInitialDatas, Descriptor.Width, Descriptor.Height, 1, Descriptor.Format,
                                                       Descriptor.MipLevels, Descriptor.ArraySize, pInitialDatas != null); // 初始化第二步
                }
            }
        }
コード例 #6
0
ファイル: D3D11Reader.cs プロジェクト: ylyking/RdcFileRepack
    public static object Read_D3D11_TEXTURE2D_DESC(BinaryReader br)
    {
        D3D11_TEXTURE2D_DESC desc = new D3D11_TEXTURE2D_DESC();

        desc.offset = br.BaseStream.Position;

        desc.Width              = br.ReadUInt32();
        desc.Height             = br.ReadUInt32();
        desc.MipLevels          = br.ReadUInt32();
        desc.ArraySize          = br.ReadUInt32();
        desc.Format             = (DXGI_FORMAT)br.ReadUInt32();
        desc.SampleDesc         = new DXGI_SAMPLE_DESC();
        desc.SampleDesc.Count   = br.ReadUInt32();
        desc.SampleDesc.Quality = br.ReadUInt32();
        desc.Usage              = (D3D11_USAGE)br.ReadUInt32();
        desc.BindFlags          = br.ReadUInt32();
        desc.CPUAccessFlags     = br.ReadUInt32();
        desc.MiscFlags          = br.ReadUInt32();

        desc.length = br.BaseStream.Position - desc.offset;
        return(desc);
    }
コード例 #7
0
ファイル: Main.cs プロジェクト: zhuowp/DirectN
        private void Init()
        {
            // this code is ported from https://gist.github.com/d7samurai/261c69490cce0620d0bfc93003cd1052
            var fac   = DXGIFunctions.CreateDXGIFactory2();
            var flags = D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if DEBUG
            flags |= D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_DEBUG;
#endif

            var d3D11Device = D3D11Functions.D3D11CreateDevice(null, D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_HARDWARE, flags, out _deviceContext);

            var mt = d3D11Device.As <ID3D11Multithread>();
            mt?.SetMultithreadProtected(true);

            var desc = new DXGI_SWAP_CHAIN_DESC1();
            desc.Format           = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
            desc.SampleDesc.Count = 1;
            desc.BufferUsage      = Constants.DXGI_USAGE_RENDER_TARGET_OUTPUT;
            desc.BufferCount      = 2;

            // note: this causes a warning in debug
            // DXGI WARNING: IDXGIFactory::CreateSwapChain: Blt-model swap effects (DXGI_SWAP_EFFECT_DISCARD and DXGI_SWAP_EFFECT_SEQUENTIAL) are legacy swap effects that are predominantly superceded by their flip-model counterparts (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL and DXGI_SWAP_EFFECT_FLIP_DISCARD). Please consider updating your application to leverage flip-model swap effects to benefit from modern presentation enhancements. More information is available at http://aka.ms/dxgiflipmodel. [ MISCELLANEOUS WARNING #294: ]
            _swapChain = fac.CreateSwapChainForHwnd <IDXGISwapChain1>(d3D11Device, Handle, desc);
            var frameBuffer = _swapChain.GetBuffer <ID3D11Texture2D>(0);
            _renderTargetView = d3D11Device.CreateRenderTargetView(frameBuffer);

            frameBuffer.Object.GetDesc(out var depthBufferDesc);
            _width  = depthBufferDesc.Width;
            _height = depthBufferDesc.Height;

            depthBufferDesc.Format    = DXGI_FORMAT.DXGI_FORMAT_D24_UNORM_S8_UINT;
            depthBufferDesc.BindFlags = (uint)D3D11_BIND_FLAG.D3D11_BIND_DEPTH_STENCIL;
            var depthBuffer = d3D11Device.CreateTexture2D <ID3D11Texture2D>(depthBufferDesc);

            _depthBufferView = d3D11Device.CreateDepthStencilView(depthBuffer);

            var vsBlob = D3D11Functions.D3DCompileFromFile("shaders.hlsl", "vs_main", "vs_5_0");
            _vertexShader = d3D11Device.CreateVertexShader(vsBlob);

            var inputElements = new D3D11_INPUT_ELEMENT_DESC[] {
                new D3D11_INPUT_ELEMENT_DESC {
                    SemanticName = "POS", Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32_FLOAT
                },
                new D3D11_INPUT_ELEMENT_DESC {
                    SemanticName = "NOR", Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32_FLOAT, AlignedByteOffset = unchecked ((uint)Constants.D3D11_APPEND_ALIGNED_ELEMENT)
                },
                new D3D11_INPUT_ELEMENT_DESC {
                    SemanticName = "TEX", Format = DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT, AlignedByteOffset = unchecked ((uint)Constants.D3D11_APPEND_ALIGNED_ELEMENT)
                },
                new D3D11_INPUT_ELEMENT_DESC {
                    SemanticName = "COL", Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT, AlignedByteOffset = unchecked ((uint)Constants.D3D11_APPEND_ALIGNED_ELEMENT)
                },
            };
            _inputLayout = d3D11Device.CreateInputLayout(inputElements, vsBlob);

            var psBlob = D3D11Functions.D3DCompileFromFile("shaders.hlsl", "ps_main", "ps_5_0");
            _pixelShader = d3D11Device.CreatePixelShader(psBlob);

            var rasterizerDesc = new D3D11_RASTERIZER_DESC();
            rasterizerDesc.FillMode = D3D11_FILL_MODE.D3D11_FILL_SOLID;
            rasterizerDesc.CullMode = D3D11_CULL_MODE.D3D11_CULL_BACK;
            _rasterizerState        = d3D11Device.CreateRasterizerState(rasterizerDesc);

            var samplerDesc = new D3D11_SAMPLER_DESC();
            samplerDesc.Filter         = D3D11_FILTER.D3D11_FILTER_MIN_MAG_MIP_POINT;
            samplerDesc.AddressU       = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_BORDER;
            samplerDesc.AddressV       = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_BORDER;
            samplerDesc.AddressW       = D3D11_TEXTURE_ADDRESS_MODE.D3D11_TEXTURE_ADDRESS_BORDER;
            samplerDesc.BorderColor    = new float[4];
            samplerDesc.BorderColor[0] = 1;
            samplerDesc.BorderColor[1] = 1;
            samplerDesc.BorderColor[2] = 1;
            samplerDesc.BorderColor[3] = 1;
            samplerDesc.ComparisonFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_NEVER;
            _samplerState = d3D11Device.CreateSamplerState(samplerDesc);

            var depthStencilDesc = new D3D11_DEPTH_STENCIL_DESC();
            depthStencilDesc.DepthEnable    = true;
            depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK.D3D11_DEPTH_WRITE_MASK_ALL;
            depthStencilDesc.DepthFunc      = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_LESS;
            _depthStencilState = d3D11Device.CreateDepthStencilState(depthStencilDesc);

            var blendDesc = new D3D11_BLEND_DESC();
            blendDesc.RenderTarget = new D3D11_RENDER_TARGET_BLEND_DESC[8];
            blendDesc.RenderTarget[0].BlendEnable           = true;
            blendDesc.RenderTarget[0].SrcBlend              = D3D11_BLEND.D3D11_BLEND_SRC_ALPHA;
            blendDesc.RenderTarget[0].DestBlend             = D3D11_BLEND.D3D11_BLEND_INV_SRC_ALPHA;
            blendDesc.RenderTarget[0].BlendOp               = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD;
            blendDesc.RenderTarget[0].SrcBlendAlpha         = D3D11_BLEND.D3D11_BLEND_ZERO;
            blendDesc.RenderTarget[0].DestBlendAlpha        = D3D11_BLEND.D3D11_BLEND_ZERO;
            blendDesc.RenderTarget[0].BlendOpAlpha          = D3D11_BLEND_OP.D3D11_BLEND_OP_ADD;
            blendDesc.RenderTarget[0].RenderTargetWriteMask = (byte)(D3D11_COLOR_WRITE_ENABLE.D3D11_COLOR_WRITE_ENABLE_ALL);
            _blendState = d3D11Device.CreateBlendState(blendDesc);

            var constantBufferDesc = new D3D11_BUFFER_DESC();
            constantBufferDesc.ByteWidth      = (uint)Marshal.SizeOf <VS_CONSTANT_BUFFER>();
            constantBufferDesc.Usage          = D3D11_USAGE.D3D11_USAGE_DYNAMIC;
            constantBufferDesc.BindFlags      = (uint)D3D11_BIND_FLAG.D3D11_BIND_CONSTANT_BUFFER;
            constantBufferDesc.CPUAccessFlags = (uint)D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_WRITE;
            if ((constantBufferDesc.ByteWidth % 16) != 0)
            {
                throw new InvalidOperationException("Constant buffer size must be a multiple of 16.");
            }

            _constantBuffer = d3D11Device.CreateBuffer(constantBufferDesc);

            var vertexBufferDesc = new D3D11_BUFFER_DESC();
            var gc = GCHandle.Alloc(Data.VertexData, GCHandleType.Pinned);
            vertexBufferDesc.ByteWidth = (uint)Data.VertexData.SizeOf();
            vertexBufferDesc.Usage     = D3D11_USAGE.D3D11_USAGE_IMMUTABLE;
            vertexBufferDesc.BindFlags = (uint)D3D11_BIND_FLAG.D3D11_BIND_VERTEX_BUFFER;

            var vertexData = new D3D11_SUBRESOURCE_DATA();
            vertexData.pSysMem = gc.AddrOfPinnedObject();
            _vertexBuffer      = d3D11Device.CreateBuffer(vertexBufferDesc, vertexData);
            gc.Free();

            var indexBufferDesc = new D3D11_BUFFER_DESC();
            gc = GCHandle.Alloc(Data.IndexData, GCHandleType.Pinned);
            indexBufferDesc.ByteWidth = (uint)Data.IndexData.SizeOf();
            indexBufferDesc.Usage     = D3D11_USAGE.D3D11_USAGE_IMMUTABLE;
            indexBufferDesc.BindFlags = (uint)D3D11_BIND_FLAG.D3D11_BIND_INDEX_BUFFER;

            var indexData = new D3D11_SUBRESOURCE_DATA();
            indexData.pSysMem = gc.AddrOfPinnedObject();
            _indexBuffer      = d3D11Device.CreateBuffer(indexBufferDesc, indexData);
            gc.Free();

            var textureDesc = new D3D11_TEXTURE2D_DESC();
            textureDesc.Width            = 20;
            textureDesc.Height           = 20;
            textureDesc.MipLevels        = 1;
            textureDesc.ArraySize        = 1;
            textureDesc.Format           = DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
            textureDesc.SampleDesc.Count = 1;
            textureDesc.Usage            = D3D11_USAGE.D3D11_USAGE_IMMUTABLE;
            textureDesc.BindFlags        = (uint)D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE;

            gc = GCHandle.Alloc(Data.TextureData, GCHandleType.Pinned);
            var textureData = new D3D11_SUBRESOURCE_DATA();
            textureData.pSysMem     = gc.AddrOfPinnedObject();
            textureData.SysMemPitch = 20 * 4; // 4 bytes per pixel
            gc.Free();

            var texture = d3D11Device.CreateTexture2D <ID3D11Texture2D>(textureDesc, textureData);
            _shaderResourceView = d3D11Device.CreateShaderResourceView(texture);
        }
コード例 #8
0
ファイル: Program.cs プロジェクト: videolan/libvlcsharp
        static bool UpdateOuput(IntPtr opaque, RenderConfig *config, ref OutputConfig output)
        {
            ReleaseTextures();

            var renderFormat = DXGI_FORMAT_R8G8B8A8_UNORM;

            var texDesc = new D3D11_TEXTURE2D_DESC
            {
                MipLevels  = 1,
                SampleDesc = new DXGI_SAMPLE_DESC {
                    Count = 1
                },
                BindFlags      = (uint)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
                Usage          = D3D11_USAGE_DEFAULT,
                CPUAccessFlags = 0,
                ArraySize      = 1,
                Format         = renderFormat,
                Height         = config->Height,
                Width          = config->Width,
                MiscFlags      = (uint)(D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
            };

            fixed(ID3D11Texture2D **texture = &_texture)
            ThrowIfFailed(_d3dDevice->CreateTexture2D(&texDesc, null, texture));

            IDXGIResource1 *sharedResource = null;
            var             iid            = IID_IDXGIResource1;

            _texture->QueryInterface(&iid, (void **)&sharedResource);

            fixed(void *handle = &_sharedHandle)
            ThrowIfFailed(sharedResource->CreateSharedHandle(null, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, null, (IntPtr *)handle));

            sharedResource->Release();

            ID3D11Device1 *d3d11VLC1;

            iid = IID_ID3D11Device1;
            _d3deviceVLC->QueryInterface(&iid, (void **)&d3d11VLC1);

            iid = IID_ID3D11Texture2D;

            fixed(ID3D11Texture2D **texture = &_textureVLC)
            ThrowIfFailed(d3d11VLC1->OpenSharedResource1(_sharedHandle, &iid, (void **)texture));

            d3d11VLC1->Release();

            var shaderResourceViewDesc = new D3D11_SHADER_RESOURCE_VIEW_DESC
            {
                ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D,
                Format        = texDesc.Format
            };

            shaderResourceViewDesc.Texture2D.MipLevels = 1;

            ID3D11Resource *res;

            iid = IID_ID3D11Resource;
            _texture->QueryInterface(&iid, (void **)&res);
            fixed(ID3D11ShaderResourceView **tsi = &_textureShaderInput)
            {
                ThrowIfFailed(_d3dDevice->CreateShaderResourceView(res, &shaderResourceViewDesc, tsi));
                res->Release();
                _d3dctx->PSSetShaderResources(0, 1, tsi);
            }

            var renderTargetViewDesc = new D3D11_RENDER_TARGET_VIEW_DESC
            {
                Format        = texDesc.Format,
                ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D
            };

            iid = IID_ID3D11Resource;
            _textureVLC->QueryInterface(&iid, (void **)&res);

            fixed(ID3D11RenderTargetView **trt = &_textureRenderTarget)
            {
                ThrowIfFailed(_d3deviceVLC->CreateRenderTargetView(res, &renderTargetViewDesc, trt));
                res->Release();
                _d3dctxVLC->OMSetRenderTargets(1, trt, null);
            }

            output.Union.DxgiFormat = (int)renderFormat;
            output.FullRange        = true;
            output.ColorSpace       = ColorSpace.BT709;
            output.ColorPrimaries   = ColorPrimaries.BT709;
            output.TransferFunction = TransferFunction.SRGB;

            return(true);
        }
コード例 #9
0
        /// <summary>
        /// 从文件加载贴图数据
        /// </summary>
        /// <param name="subDatas"></param>
        /// <param name="desc"></param>
        /// <param name="section"></param>
        /// <param name="path"></param>
        public static void LoadTextureDataFromFile(D3D11_SUBRESOURCE_DATA[] subDatas, D3D11_TEXTURE2D_DESC desc, Section section, string path)
        {
            FREE_IMAGE_FORMAT fiFormat = default;

            string ext = Path.GetExtension(path).ToLower();

            if (ext == ".bmp")
            {
                fiFormat = FREE_IMAGE_FORMAT.FIF_BMP;
            }
            else if (ext == ".tga")
            {
                fiFormat = FREE_IMAGE_FORMAT.FIF_TARGA;
            }
            else
            {
                Console.WriteLine($"unsupported format {ext}");
                return;
            }

            FIBITMAP bmp = FreeImage.Load(fiFormat, path, FREE_IMAGE_LOAD_FLAGS.DEFAULT);

            if (bmp == null || bmp.IsNull)
            {
                Console.WriteLine($"加载图片文件失败 {path}");
                return;
            }

            try
            {
                DXGI_FORMAT format = desc.Format;
                if (Common.IsBlockFormat(format)) // 暂时不支持压缩格式
                {
                    return;
                }

                uint fiBpp  = FreeImage.GetBPP(bmp) / 8;
                uint width  = FreeImage.GetWidth(bmp);
                uint height = FreeImage.GetHeight(bmp);

                if (width != desc.Width || height != desc.Height)
                {
                    Console.WriteLine($"size unmatch of file {path}, should be {desc.Width}*{desc.Height}");
                    return;
                }

                if (format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_SNORM ||
                    format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_TYPELESS ||
                    format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)    // 4通道保存成tga以方便编辑A通道
                {
                    Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height);

                    fixed(void *p = &section.uncompressedData[subDatas[0].sysMemDataOffset])
                    {
                        byte *rawData = (byte *)p;

                        for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反
                        {
                            byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h);
                            for (int w = 0; w < desc.Width; w++)
                            {
                                rawData[w * 4]     = *scanLine++;
                                rawData[w * 4 + 1] = *scanLine++;
                                rawData[w * 4 + 2] = *scanLine++;
                                rawData[w * 4 + 3] = *scanLine++;
                            }

                            rawData += subDatas[0].SysMemPitch;
                        }
                    }
                }
                else if (format == DXGI_FORMAT.DXGI_FORMAT_R8_SNORM ||
                         format == DXGI_FORMAT.DXGI_FORMAT_R8_TYPELESS ||
                         format == DXGI_FORMAT.DXGI_FORMAT_R8_UNORM ||
                         format == DXGI_FORMAT.DXGI_FORMAT_A8_UNORM) // 经过测试单通道无论指定哪个通道数据都只存了一个通道, 单通道保存成png24
                {
                    Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height);

                    fixed(void *p = &section.uncompressedData[subDatas[0].sysMemDataOffset])
                    {
                        byte *rawData = (byte *)p;

                        for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反
                        {
                            byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h);
                            for (int w = 0; w < desc.Width; w++)
                            {
                                rawData[w] = *scanLine;
                                scanLine  += fiBpp;
                            }

                            rawData += subDatas[0].SysMemPitch;
                        }
                    }
                }
            }
            finally
            {
                FreeImage.Unload(bmp);
            }
        }
コード例 #10
0
        /// <summary>
        /// 保存贴图到文件,适用于 Chunk_CreateTexture2D 及 Chunk_CreateSwapBuffer
        /// </summary>
        /// <param name="subDatas"></param>
        /// <param name="desc"></param>
        /// <param name="section"></param>
        public static void SaveTextureToFile(D3D11_SUBRESOURCE_DATA[] subDatas, D3D11_TEXTURE2D_DESC desc, Section section, string path)
        {
            DXGI_FORMAT format = desc.Format;

            if (Common.IsBlockFormat(format)) // 暂时不支持导出压缩格式
            {
                return;
            }

            if (format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_SNORM ||
                format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_TYPELESS ||
                format == DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)    // 4通道保存成tga以方便编辑A通道
            {
                FIBITMAP bmp = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_BITMAP, (int)desc.Width, (int)desc.Height, 32);

                Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height * 4); // sysMemLength 是对齐的,因此可能大于真实数据大小

                fixed(void *p = &section.uncompressedData[subDatas[0].sysMemDataOffset])
                {
                    byte *rawData = (byte *)p;

                    for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反
                    {
                        byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h);
                        for (int w = 0; w < desc.Width; w++)
                        {
                            *scanLine++ = rawData[w * 4];
                            *scanLine++ = rawData[w * 4 + 1];
                            *scanLine++ = rawData[w * 4 + 2];
                            *scanLine++ = rawData[w * 4 + 3];
                        }

                        rawData += subDatas[0].SysMemPitch;
                    }
                }

                path = $"{path}.tga";
                File.Delete(path);
                FreeImage.Save(FREE_IMAGE_FORMAT.FIF_TARGA, bmp, path, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
                FreeImage.Unload(bmp);
            }
            else if (format == DXGI_FORMAT.DXGI_FORMAT_R8_SNORM ||
                     format == DXGI_FORMAT.DXGI_FORMAT_R8_TYPELESS ||
                     format == DXGI_FORMAT.DXGI_FORMAT_R8_UNORM ||
                     format == DXGI_FORMAT.DXGI_FORMAT_A8_UNORM) // 经过测试单通道无论指定哪个通道数据都只存了一个通道, 单通道保存成png24
            {
                FIBITMAP bmp = FreeImage.AllocateT(FREE_IMAGE_TYPE.FIT_BITMAP, (int)desc.Width, (int)desc.Height, 24);
                Debug.Assert(subDatas[0].sysMemLength >= desc.Width * desc.Height);
                fixed(void *p = &section.uncompressedData[subDatas[0].sysMemDataOffset])
                {
                    byte *rawData = (byte *)p;

                    for (int h = (int)(desc.Height - 1); h >= 0; h--) // bitmap 存储方向与 dx 相反
                    {
                        byte *scanLine = (byte *)FreeImage.GetScanLine(bmp, h);
                        for (int w = 0; w < desc.Width; w++)
                        {
                            byte val        = rawData[w];
                            *    scanLine++ = val;
                            *    scanLine++ = val;
                            *    scanLine++ = val;
                        }

                        rawData += subDatas[0].SysMemPitch;
                    }
                }

                path = $"{path}.bmp";
                File.Delete(path);
                FreeImage.Save(FREE_IMAGE_FORMAT.FIF_BMP, bmp, path, FREE_IMAGE_SAVE_FLAGS.BMP_SAVE_RLE);
                FreeImage.Unload(bmp);
            }
        }