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))
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 } }