private static void CreateTextureFromDDS(
            D3D11Device device,
            D3D11DeviceContext context,
            DdsFile dds,
            byte[] bitData,
            int maxSize,
            D3D11Usage usage,
            D3D11BindOptions bindOptions,
            D3D11CpuAccessOptions cpuAccessOptions,
            D3D11ResourceMiscOptions miscOptions,
            bool forceSRGB,
            out D3D11Resource texture,
            out D3D11ShaderResourceView textureView)
        {
            int width  = dds.Width;
            int height = dds.Height;
            int depth  = dds.Depth;

            D3D11ResourceDimension resDim = (D3D11ResourceDimension)dds.ResourceDimension;
            int        arraySize          = Math.Max(1, dds.ArraySize);
            DxgiFormat format             = (DxgiFormat)dds.Format;
            bool       isCubeMap          = false;

            if (dds.Format == DdsFormat.Unknown)
            {
                if (dds.PixelFormat.RgbBitCount == 32)
                {
                    if (IsBitMask(dds.PixelFormat, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000))
                    {
                        format = DxgiFormat.B8G8R8X8UNorm;
                        int length = bitData.Length / 4;
                        var bytes  = new byte[length * 4];

                        for (int i = 0; i < length; i++)
                        {
                            bytes[i * 4 + 0] = bitData[i * 4 + 2];
                            bytes[i * 4 + 1] = bitData[i * 4 + 1];
                            bytes[i * 4 + 2] = bitData[i * 4 + 0];
                        }

                        bitData = bytes;
                    }
                }
                else if (dds.PixelFormat.RgbBitCount == 24)
                {
                    if (IsBitMask(dds.PixelFormat, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
                    {
                        format = DxgiFormat.B8G8R8X8UNorm;
                        int length = bitData.Length / 3;
                        var bytes  = new byte[length * 4];

                        for (int i = 0; i < length; i++)
                        {
                            bytes[i * 4 + 0] = bitData[i * 3 + 0];
                            bytes[i * 4 + 1] = bitData[i * 3 + 1];
                            bytes[i * 4 + 2] = bitData[i * 3 + 2];
                        }

                        bitData = bytes;
                    }
                }
            }

            int mipCount = Math.Max(1, dds.MipmapCount);

            switch (format)
            {
            case DxgiFormat.AI44:
            case DxgiFormat.IA44:
            case DxgiFormat.P8:
            case DxgiFormat.A8P8:
                throw new NotSupportedException(format.ToString() + " format is not supported.");

            default:
                if (DdsHelpers.GetBitsPerPixel((DdsFormat)format) == 0)
                {
                    throw new NotSupportedException(format.ToString() + " format is not supported.");
                }

                break;
            }

            switch (resDim)
            {
            case D3D11ResourceDimension.Texture1D:
                // D3DX writes 1D textures with a fixed Height of 1
                if ((dds.Options & DdsOptions.Height) != 0 && height != 1)
                {
                    throw new InvalidDataException();
                }

                height = 1;
                depth  = 1;
                break;

            case D3D11ResourceDimension.Texture2D:
                if ((dds.ResourceMiscOptions & DdsResourceMiscOptions.TextureCube) != 0)
                {
                    arraySize *= 6;
                    isCubeMap  = true;
                }

                depth = 1;
                break;

            case D3D11ResourceDimension.Texture3D:
                if ((dds.Options & DdsOptions.Depth) == 0)
                {
                    throw new InvalidDataException();
                }

                if (arraySize > 1)
                {
                    throw new NotSupportedException();
                }
                break;

            default:
                if ((dds.Options & DdsOptions.Depth) != 0)
                {
                    resDim = D3D11ResourceDimension.Texture3D;
                }
                else
                {
                    if ((dds.Caps2 & DdsAdditionalCaps.CubeMap) != 0)
                    {
                        // We require all six faces to be defined
                        if ((dds.Caps2 & DdsAdditionalCaps.CubeMapAllFaces) != DdsAdditionalCaps.CubeMapAllFaces)
                        {
                            throw new NotSupportedException();
                        }

                        arraySize = 6;
                        isCubeMap = true;
                    }

                    depth  = 1;
                    resDim = D3D11ResourceDimension.Texture2D;

                    // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
                }

                break;
            }

            if ((miscOptions & D3D11ResourceMiscOptions.TextureCube) != 0 &&
                resDim == D3D11ResourceDimension.Texture2D &&
                (arraySize % 6 == 0))
            {
                isCubeMap = true;
            }

            // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 11.x hardware requirements)
            if (mipCount > D3D11Constants.ReqMipLevels)
            {
                throw new NotSupportedException();
            }

            switch (resDim)
            {
            case D3D11ResourceDimension.Texture1D:
                if (arraySize > D3D11Constants.ReqTexture1DArrayAxisDimension ||
                    width > D3D11Constants.ReqTexture1DDimension)
                {
                    throw new NotSupportedException();
                }

                break;

            case D3D11ResourceDimension.Texture2D:
                if (isCubeMap)
                {
                    // This is the right bound because we set arraySize to (NumCubes*6) above
                    if (arraySize > D3D11Constants.ReqTexture2DArrayAxisDimension ||
                        width > D3D11Constants.ReqTextureCubeDimension ||
                        height > D3D11Constants.ReqTextureCubeDimension)
                    {
                        throw new NotSupportedException();
                    }
                }
                else if (arraySize > D3D11Constants.ReqTexture2DArrayAxisDimension ||
                         width > D3D11Constants.ReqTexture2DDimension ||
                         height > D3D11Constants.ReqTexture2DDimension)
                {
                    throw new NotSupportedException();
                }

                break;

            case D3D11ResourceDimension.Texture3D:
                if (arraySize > 1 ||
                    width > D3D11Constants.ReqTexture3DDimension ||
                    height > D3D11Constants.ReqTexture3DDimension ||
                    depth > D3D11Constants.ReqTexture3DDimension)
                {
                    throw new NotSupportedException();
                }

                break;

            default:
                throw new NotSupportedException();
            }

            bool autogen = false;

            if (mipCount == 1)
            {
                // See if format is supported for auto-gen mipmaps (varies by feature level)
                if (!device.CheckFormatSupport(format, out D3D11FormatSupport fmtSupport) &&
                    (fmtSupport & D3D11FormatSupport.MipAutogen) != 0)
                {
                    // 10level9 feature levels do not support auto-gen mipgen for volume textures
                    if (resDim != D3D11ResourceDimension.Texture3D ||
                        device.FeatureLevel >= D3D11FeatureLevel.FeatureLevel100)
                    {
                        autogen = true;
                    }
                }
            }

            if (autogen)
            {
                // Create texture with auto-generated mipmaps
                CreateD3DResources(
                    device,
                    resDim,
                    width,
                    height,
                    depth,
                    0,
                    arraySize,
                    format,
                    usage,
                    bindOptions | D3D11BindOptions.RenderTarget,
                    cpuAccessOptions,
                    miscOptions | D3D11ResourceMiscOptions.GenerateMips,
                    forceSRGB,
                    isCubeMap,
                    null,
                    out texture,
                    out textureView);

                try
                {
                    DdsHelpers.GetSurfaceInfo(width, height, (DdsFormat)format, out int numBytes, out int rowBytes, out int numRows);

                    if (numBytes > bitData.Length)
                    {
                        throw new EndOfStreamException();
                    }

                    D3D11ShaderResourceViewDesc desc = textureView.Description;
                    uint mipLevels = 1;

                    switch (desc.ViewDimension)
                    {
                    case D3D11SrvDimension.Texture1D:
                        mipLevels = desc.Texture1D.MipLevels;
                        break;

                    case D3D11SrvDimension.Texture1DArray:
                        mipLevels = desc.Texture1DArray.MipLevels;
                        break;

                    case D3D11SrvDimension.Texture2D:
                        mipLevels = desc.Texture2D.MipLevels;
                        break;

                    case D3D11SrvDimension.Texture2DArray:
                        mipLevels = desc.Texture2DArray.MipLevels;
                        break;

                    case D3D11SrvDimension.TextureCube:
                        mipLevels = desc.TextureCube.MipLevels;
                        break;

                    case D3D11SrvDimension.TextureCubeArray:
                        mipLevels = desc.TextureCubeArray.MipLevels;
                        break;

                    case D3D11SrvDimension.Texture3D:
                        mipLevels = desc.Texture3D.MipLevels;
                        break;

                    default:
                        throw new InvalidDataException();
                    }

                    if (arraySize > 1)
                    {
                        int pSrcBits = 0;

                        for (uint item = 0; item < (uint)arraySize; item++)
                        {
                            if (pSrcBits + numBytes > bitData.Length)
                            {
                                throw new EndOfStreamException();
                            }

                            var data = new byte[numBytes];
                            Array.Copy(bitData, pSrcBits, data, 0, numBytes);

                            uint res = D3D11Utils.CalcSubresource(0, item, mipLevels);
                            context.UpdateSubresource(texture, res, null, data, (uint)rowBytes, (uint)numBytes);

                            pSrcBits += numBytes;
                        }
                    }
                    else
                    {
                        context.UpdateSubresource(texture, 0, null, bitData, (uint)rowBytes, (uint)numBytes);
                    }

                    context.GenerateMips(textureView);
                }
                catch
                {
                    D3D11Utils.DisposeAndNull(ref textureView);
                    D3D11Utils.DisposeAndNull(ref texture);
                    throw;
                }
            }
            else
            {
                // Create the texture

                if (!FillInitData(
                        width,
                        height,
                        depth,
                        mipCount,
                        arraySize,
                        format,
                        maxSize,
                        bitData,
                        out int twidth,
                        out int theight,
                        out int tdepth,
                        out int skipMip,
                        out D3D11SubResourceData[] initData))
Exemplo n.º 2
0
        public void PerEdgeTessellation(
            XMMatrix matWVP,
            ref D3D11Buffer ppTessedVerticesBuf,
            ref D3D11Buffer ppTessedIndicesBuf,
            out uint num_tessed_vertices,
            out uint num_tessed_indices)
        {
            var d3dDevice  = this.deviceResources.D3DDevice;
            var d3dContext = this.deviceResources.D3DContext;

            // Update per-edge tessellation factors
            {
                EdgeFactorConstantBuffer cbCS = default;
                cbCS.MatWVP = matWVP;
                cbCS.TessEdgeLengthScale = this.m_tess_edge_len_scale;
                cbCS.NumTriangles        = this.m_nVertices / 3;

                d3dContext.UpdateSubresource(
                    this.s_pEdgeFactorCSCB,
                    D3D11Utils.CalcSubresource(0, 0, 1),
                    null,
                    cbCS,
                    EdgeFactorConstantBuffer.Size,
                    EdgeFactorConstantBuffer.Size);

                this.RunComputeShader(
                    this.s_pEdgeFactorCS,
                    new[] { this.m_pBaseVBSRV },
                    null,
                    this.s_pEdgeFactorCSCB,
                    this.m_pEdgeFactorBufUAV,
                    (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f),
                    1U,
                    1U);
            }

            // How many vertices/indices are needed for the tessellated mesh?
            {
                uint[] cbCS = new uint[] { this.m_nVertices / 3, 0, 0, 0 };

                d3dContext.UpdateSubresource(
                    this.s_pCSCB,
                    D3D11Utils.CalcSubresource(0, 0, 1),
                    null,
                    cbCS,
                    4 * 4,
                    4 * 4);

                this.RunComputeShader(
                    this.s_pNumVerticesIndicesCSs[(int)this.PartitioningMode],
                    new[] { this.m_pEdgeFactorBufSRV },
                    this.s_pLookupTableCSCB,
                    this.s_pCSCB,
                    this.m_pScanBuf0UAV,
                    (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f),
                    1U,
                    1U);

                this.s_ScanCS.Scan(d3dContext, this.m_nVertices / 3, this.m_pScanBuf0SRV, this.m_pScanBuf0UAV, this.m_pScanBuf1SRV, this.m_pScanBuf1UAV);

                // read back the number of vertices/indices for tessellation output
                D3D11Box box = default;
                box.Left   = 4 * 2 * this.m_nVertices / 3 - 4 * 2;
                box.Right  = 4 * 2 * this.m_nVertices / 3;
                box.Top    = 0;
                box.Bottom = 1;
                box.Front  = 0;
                box.Back   = 1;

                d3dContext.CopySubresourceRegion(this.s_pCSReadBackBuf, 0, 0, 0, 0, this.m_pScanBuf0, 0, box);

                D3D11MappedSubResource mappedResource = d3dContext.Map(this.s_pCSReadBackBuf, 0, D3D11MapCpuPermission.Read, D3D11MapOptions.None);

                try
                {
                    num_tessed_vertices = (uint)Marshal.ReadInt32(mappedResource.Data + 4 * 0);
                    num_tessed_indices  = (uint)Marshal.ReadInt32(mappedResource.Data + 4 * 1);
                }
                finally
                {
                    d3dContext.Unmap(this.s_pCSReadBackBuf, 0);
                }
            }

            if (num_tessed_vertices == 0 || num_tessed_indices == 0)
            {
                return;
            }

            // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to m_pScanBuf0
            if (DebugEnabled)
            {
#pragma warning disable IDE0059 // Assignation inutile d'une valeur
                var p = this.CreateAndCopyToDebugBuf <(uint v, uint t)>(this.m_pScanBuf0);
#pragma warning restore IDE0059 // Assignation inutile d'une valeur
            }

            // Generate buffers for scattering TriID and IndexID for both vertex data and index data,
            // also generate buffers for output tessellated vertex data and index data
            {
                if (this.m_pScatterVertexBuf == null || this.m_nCachedTessedVertices < num_tessed_vertices || this.m_nCachedTessedVertices > num_tessed_vertices * 2)
                {
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBuf);
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBufSRV);
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterVertexBufUAV);

                    D3D11Utils.DisposeAndNull(ref ppTessedVerticesBuf);
                    D3D11Utils.DisposeAndNull(ref this.m_pTessedVerticesBufUAV);
                    D3D11Utils.DisposeAndNull(ref this.m_pTessedVerticesBufSRV);

                    this.m_pScatterVertexBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc
                    {
                        BindOptions         = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess,
                        ByteWidth           = 4 * 2 * num_tessed_vertices,
                        StructureByteStride = 4 * 2,
                        MiscOptions         = D3D11ResourceMiscOptions.BufferStructured,
                        Usage = D3D11Usage.Default
                    });

                    this.m_pScatterVertexBufSRV = d3dDevice.CreateShaderResourceView(this.m_pScatterVertexBuf, new D3D11ShaderResourceViewDesc
                    {
                        ViewDimension = D3D11SrvDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferSrv
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_vertices
                        }
                    });

                    this.m_pScatterVertexBufUAV = d3dDevice.CreateUnorderedAccessView(this.m_pScatterVertexBuf, new D3D11UnorderedAccessViewDesc
                    {
                        ViewDimension = D3D11UavDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferUav
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_vertices
                        }
                    });

                    // generate the output tessellated vertices buffer
                    ppTessedVerticesBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc
                    {
                        BindOptions         = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess,
                        ByteWidth           = 4 * 3 * num_tessed_vertices,
                        StructureByteStride = 4 * 3,
                        MiscOptions         = D3D11ResourceMiscOptions.BufferStructured,
                        Usage = D3D11Usage.Default
                    });

                    this.m_pTessedVerticesBufUAV = d3dDevice.CreateUnorderedAccessView(ppTessedVerticesBuf, new D3D11UnorderedAccessViewDesc
                    {
                        ViewDimension = D3D11UavDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferUav
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_vertices
                        }
                    });

                    this.m_pTessedVerticesBufSRV = d3dDevice.CreateShaderResourceView(ppTessedVerticesBuf, new D3D11ShaderResourceViewDesc
                    {
                        ViewDimension = D3D11SrvDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferSrv
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_vertices
                        }
                    });

                    this.m_nCachedTessedVertices = num_tessed_vertices;
                }

                if (this.m_pScatterIndexBuf == null || this.m_nCachedTessedIndices < num_tessed_indices)
                {
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBuf);
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBufSRV);
                    D3D11Utils.DisposeAndNull(ref this.m_pScatterIndexBufUAV);

                    D3D11Utils.DisposeAndNull(ref ppTessedIndicesBuf);
                    D3D11Utils.DisposeAndNull(ref this.m_pTessedIndicesBufUAV);

                    this.m_pScatterIndexBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc
                    {
                        BindOptions         = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess,
                        ByteWidth           = 4 * 2 * num_tessed_indices,
                        StructureByteStride = 4 * 2,
                        MiscOptions         = D3D11ResourceMiscOptions.BufferStructured,
                        Usage = D3D11Usage.Default
                    });

                    this.m_pScatterIndexBufSRV = d3dDevice.CreateShaderResourceView(this.m_pScatterIndexBuf, new D3D11ShaderResourceViewDesc
                    {
                        ViewDimension = D3D11SrvDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferSrv
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_indices
                        }
                    });

                    this.m_pScatterIndexBufUAV = d3dDevice.CreateUnorderedAccessView(this.m_pScatterIndexBuf, new D3D11UnorderedAccessViewDesc
                    {
                        ViewDimension = D3D11UavDimension.Buffer,
                        Format        = DxgiFormat.Unknown,
                        Buffer        = new D3D11BufferUav
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_indices
                        }
                    });

                    // generate the output tessellated indices buffer
                    ppTessedIndicesBuf = d3dDevice.CreateBuffer(new D3D11BufferDesc
                    {
                        BindOptions = D3D11BindOptions.ShaderResource | D3D11BindOptions.UnorderedAccess | D3D11BindOptions.IndexBuffer,
                        ByteWidth   = 4 * num_tessed_indices,
                        MiscOptions = D3D11ResourceMiscOptions.BufferAllowRawViews,
                        Usage       = D3D11Usage.Default
                    });

                    this.m_pTessedIndicesBufUAV = d3dDevice.CreateUnorderedAccessView(ppTessedIndicesBuf, new D3D11UnorderedAccessViewDesc
                    {
                        ViewDimension = D3D11UavDimension.Buffer,
                        Format        = DxgiFormat.R32Typeless,
                        Buffer        = new D3D11BufferUav
                        {
                            FirstElement = 0,
                            NumElements  = num_tessed_indices,
                            Options      = D3D11BufferUavOptions.Raw
                        }
                    });

                    this.m_nCachedTessedIndices = num_tessed_indices;
                }
            }

            // Scatter TriID, IndexID
            {
                uint[] cbCS = new uint[] { this.m_nVertices / 3, 0, 0, 0 };
                D3D11ShaderResourceView[] aRViews = new[] { this.m_pScanBuf0SRV };

                d3dContext.UpdateSubresource(
                    this.s_pCSCB,
                    D3D11Utils.CalcSubresource(0, 0, 1),
                    null,
                    cbCS,
                    4 * 4,
                    4 * 4);

                // Scatter vertex TriID, IndexID
                this.RunComputeShader(
                    this.s_pScatterVertexTriIDIndexIDCS,
                    aRViews,
                    null,
                    this.s_pCSCB,
                    this.m_pScatterVertexBufUAV,
                    (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f),
                    1U,
                    1U);

                // Scatter index TriID, IndexID
                this.RunComputeShader(
                    this.s_pScatterIndexTriIDIndexIDCS,
                    aRViews,
                    null,
                    this.s_pCSCB,
                    this.m_pScatterIndexBufUAV,
                    (uint)Math.Ceiling(this.m_nVertices / 3 / 128.0f),
                    1U,
                    1U);
            }

            // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to m_pScatterVertexBuf
            if (DebugEnabled)
            {
#pragma warning disable IDE0059 // Assignation inutile d'une valeur
                var p = this.CreateAndCopyToDebugBuf <(uint v, uint t)>(this.m_pScatterVertexBuf);
#pragma warning restore IDE0059 // Assignation inutile d'une valeur
            }

            // Tessellate vertex
            {
                uint[] cbCS = new uint[] { num_tessed_vertices, 0, 0, 0 };

                d3dContext.UpdateSubresource(
                    this.s_pCSCB,
                    D3D11Utils.CalcSubresource(0, 0, 1),
                    null,
                    cbCS,
                    4 * 4,
                    4 * 4);

                this.RunComputeShader(
                    this.s_pTessVerticesCSs[(int)this.PartitioningMode],
                    new[] { this.m_pScatterVertexBufSRV, this.m_pEdgeFactorBufSRV },
                    this.s_pLookupTableCSCB,
                    this.s_pCSCB,
                    this.m_pTessedVerticesBufUAV,
                    (uint)Math.Ceiling(num_tessed_vertices / 128.0f),
                    1U,
                    1U);
            }

            // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to *ppTessedVerticesBuf
            if (DebugEnabled)
            {
#pragma warning disable IDE0059 // Assignation inutile d'une valeur
                var p = this.CreateAndCopyToDebugBuf <(uint id, float u, float v)>(ppTessedVerticesBuf);
#pragma warning restore IDE0059 // Assignation inutile d'une valeur
            }

            // Tessellate indices
            {
                uint[] cbCS = new uint[] { num_tessed_indices, 0, 0, 0 };

                d3dContext.UpdateSubresource(
                    this.s_pCSCB,
                    D3D11Utils.CalcSubresource(0, 0, 1),
                    null,
                    cbCS,
                    4 * 4,
                    4 * 4);

                this.RunComputeShader(
                    this.s_pTessIndicesCSs[(int)this.PartitioningMode],
                    new[] { this.m_pScatterIndexBufSRV, this.m_pEdgeFactorBufSRV, this.m_pScanBuf0SRV },
                    this.s_pLookupTableCSCB,
                    this.s_pCSCB,
                    this.m_pTessedIndicesBufUAV,
                    (uint)Math.Ceiling(num_tessed_indices / 128.0f),
                    1U,
                    1U);
            }

            // Turn on this and set a breakpoint on the line beginning with "p = " and see what has been written to *ppTessedIndicesBuf
            if (DebugEnabled)
            {
#pragma warning disable IDE0059 // Assignation inutile d'une valeur
                var p = this.CreateAndCopyToDebugBuf <int>(ppTessedIndicesBuf);
#pragma warning restore IDE0059 // Assignation inutile d'une valeur
            }
        }