public void UpdateTransferFunctionTexture() { // TODO: This code is identical with TF loading in the LoadAssets method. // Could be extracted to common helper class, perhaps also including // volume texture loading. We call nearly-identical code three times in this file. // TODO: I suspect the might be another, minor, memory leak here. // Load transfer function var transferFunctionTextureDesc = ResourceDescription.Texture1D(Format.R8G8B8A8_UNorm, TransferFunctionWidth, 1); transferFunctionTexture = device.CreateCommittedResource(new HeapProperties( HeapType.Default), HeapFlags.None, transferFunctionTextureDesc, ResourceStates.CopyDestination); long transferFunctionUploadBufferSize = GetRequiredIntermediateSize(this.transferFunctionTexture, 0, 1); // Create the GPU upload buffer. transferFunctionTextureUploadHeap = device.CreateCommittedResource(new HeapProperties( CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, ResourceDescription.Texture1D(Format.R8G8B8A8_UNorm, TransferFunctionWidth, 1), ResourceStates.GenericRead); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture1D. byte[] transferFunctionTextureData = GenerateTransferFunctionTextureData(); var transferFunctionHandle = GCHandle.Alloc(transferFunctionTextureData, GCHandleType.Pinned); var transferFunctionPtr = Marshal.UnsafeAddrOfPinnedArrayElement(transferFunctionTextureData, 0); transferFunctionTextureUploadHeap.WriteToSubresource(0, null, transferFunctionPtr, TransferFunctionWidth, TransferFunctionWidth); transferFunctionHandle.Free(); commandList.CopyTextureRegion(new TextureCopyLocation(transferFunctionTexture, 0), 0, 0, 0, new TextureCopyLocation(transferFunctionTextureUploadHeap, 0), null); commandList.ResourceBarrierTransition(this.transferFunctionTexture, ResourceStates.CopyDestination, ResourceStates.PixelShaderResource); // Describe and create a SRV for the transfer function texture. var transferFunctionSrvDesc = new ShaderResourceViewDescription { Shader4ComponentMapping = D3DXUtilities.DefaultComponentMapping(), Format = transferFunctionTextureDesc.Format, Dimension = ShaderResourceViewDimension.Texture1D, Texture1D = { MipLevels = 1 }, }; var handleIncrement = device.GetDescriptorHandleIncrementSize(DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView); CpuDescriptorHandle locationDesctiptor = shaderRenderViewHeap.CPUDescriptorHandleForHeapStart + handleIncrement; device.CreateShaderResourceView(this.transferFunctionTexture, transferFunctionSrvDesc, locationDesctiptor); // End load transfer function data }
private void LoadAssets() { // Create the root signature description. var rootSignatureDesc = new RootSignatureDescription(RootSignatureFlags.AllowInputAssemblerInputLayout, // Root Parameters new[] { new RootParameter(ShaderVisibility.Pixel, new DescriptorRange() { RangeType = DescriptorRangeType.ShaderResourceView, DescriptorCount = 3, OffsetInDescriptorsFromTableStart = int.MinValue, BaseShaderRegister = 0 }), new RootParameter(ShaderVisibility.Pixel, new DescriptorRange() { RangeType = DescriptorRangeType.ConstantBufferView, DescriptorCount = 1, BaseShaderRegister = 0, OffsetInDescriptorsFromTableStart = int.MinValue, }) }, // Samplers new[] { new StaticSamplerDescription(ShaderVisibility.Pixel, 0, 0) { //Filter = Filter.MinimumMinMagMipPoint, Filter = Filter.ComparisonMinLinearMagPointMipLinear, AddressUVW = TextureAddressMode.Border, } }); rootSignature = device.CreateRootSignature(0, rootSignatureDesc.Serialize()); // Create the pipeline state, which includes compiling and loading shaders. var vertexShaderPath = Utils.GetVertexShaderPath(); var pixelShaderPath = Utils.GetPixelShaderForRenderingMode(VolViz.Configuration.RenderingMode.Dvr); #if DEBUG var vertexShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile(vertexShaderPath, "VSMain", "vs_5_0", SharpDX.D3DCompiler.ShaderFlags.Debug)); #else var vertexShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile(vertexShaderPath, "VSMain", "vs_5_0")); #endif #if DEBUG var pixelShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile(pixelShaderPath, "PSMain", "ps_5_0", SharpDX.D3DCompiler.ShaderFlags.Debug)); #else var pixelShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile(pixelShaderPath, "PSMain", "ps_5_0")); #endif // Define the vertex input layout. var inputElementDescs = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0), new InputElement("TEXCOORD", 0, Format.R32G32_Float, 12, 0) }; // Describe and create the graphics pipeline state object (PSO). var psoDesc = new GraphicsPipelineStateDescription() { InputLayout = new InputLayoutDescription(inputElementDescs), RootSignature = rootSignature, VertexShader = vertexShader, PixelShader = pixelShader, RasterizerState = RasterizerStateDescription.Default(), BlendState = BlendStateDescription.Default(), DepthStencilFormat = SharpDX.DXGI.Format.D32_Float, DepthStencilState = new DepthStencilStateDescription() { IsDepthEnabled = false, IsStencilEnabled = false }, SampleMask = int.MaxValue, PrimitiveTopologyType = PrimitiveTopologyType.Triangle, RenderTargetCount = 1, Flags = PipelineStateFlags.None, SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0), StreamOutput = new StreamOutputDescription() }; psoDesc.RenderTargetFormats[0] = SharpDX.DXGI.Format.R8G8B8A8_UNorm; pipelineState = device.CreateGraphicsPipelineState(psoDesc); // Create the command list. commandList = device.CreateCommandList(CommandListType.Direct, commandAllocator, pipelineState); // Define the geometry for a square consisting of two triangles. var squareVertexes = new[] { new Vertex() { Position = new Vector3(-1.0f, 1.0f, 0.0f), TexCoord = new Vector2(0.0f, 0.0f) }, new Vertex() { Position = new Vector3(1.0f, 1.0f, 0.0f), TexCoord = new Vector2(1.0f, 0.0f) }, new Vertex() { Position = new Vector3(-1.0f, -1.0f, 0.0f), TexCoord = new Vector2(0.0f, 1.0f) }, new Vertex() { Position = new Vector3(1.0f, 1.0f, 0.0f), TexCoord = new Vector2(1.0f, 0.0f) }, new Vertex() { Position = new Vector3(1.0f, -1.0f, 0.0f), TexCoord = new Vector2(1.0f, 1.0f) }, new Vertex() { Position = new Vector3(-1.0f, -1.0f, 0.0f), TexCoord = new Vector2(0.0f, 1.0f) }, }; // Create the vertex buffer. int vertexBufferSize = Utilities.SizeOf(squareVertexes); // Note: using upload heaps to transfer static data like vert buffers is not // recommended. Every time the GPU needs it, the upload heap will be marshalled // over. Please read up on Default Heap usage. An upload heap is used here for // code simplicity and because there are very few verts to actually transfer. vertexBuffer = device.CreateCommittedResource(new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(vertexBufferSize), ResourceStates.GenericRead); // Copy the triangle data to the vertex buffer. var pVertexDataBegin = vertexBuffer.Map(0); Utilities.Write(pVertexDataBegin, squareVertexes, 0, squareVertexes.Length); vertexBuffer.Unmap(0); // Initialize the vertex buffer view. vertexBufferView = new VertexBufferView(); vertexBufferView.BufferLocation = vertexBuffer.GPUVirtualAddress; vertexBufferView.StrideInBytes = Utilities.SizeOf <Vertex>(); vertexBufferView.SizeInBytes = vertexBufferSize; // Load volume data var volumeTextureDesc = ResourceDescription.Texture3D(Format.R8G8B8A8_UNorm, VolumeTextureWidth, VolumeTextureHeight, VolumeTextureDepth, 1); volumeTexture = device.CreateCommittedResource(new HeapProperties( HeapType.Default), HeapFlags.None, volumeTextureDesc, ResourceStates.CopyDestination); long volumeUploadBufferSize = GetRequiredIntermediateSize(this.volumeTexture, 0, 1); // Create the GPU upload buffer. var volumeTextureUploadHeap = device.CreateCommittedResource(new HeapProperties( CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, ResourceDescription.Texture3D(Format.R8G8B8A8_UNorm, VolumeTextureWidth, VolumeTextureHeight, VolumeTextureDepth, 1), ResourceStates.GenericRead); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture3D. byte[] volumeTextureData = GenerateVolumeTextureData(); var volumeHandle = GCHandle.Alloc(volumeTextureData, GCHandleType.Pinned); var volumePtr = Marshal.UnsafeAddrOfPinnedArrayElement(volumeTextureData, 0); volumeTextureUploadHeap.WriteToSubresource(0, null, volumePtr, TexturePixelSize * VolumeTextureWidth, TexturePixelSize * VolumeTextureWidth * VolumeTextureHeight); volumeHandle.Free(); commandList.CopyTextureRegion(new TextureCopyLocation(volumeTexture, 0), 0, 0, 0, new TextureCopyLocation(volumeTextureUploadHeap, 0), null); commandList.ResourceBarrierTransition(this.volumeTexture, ResourceStates.CopyDestination, ResourceStates.PixelShaderResource); // Describe and create a SRV for the volume texture. var volumeSrvDesc = new ShaderResourceViewDescription { Shader4ComponentMapping = D3DXUtilities.DefaultComponentMapping(), Format = volumeTextureDesc.Format, Dimension = ShaderResourceViewDimension.Texture3D, Texture3D = { MipLevels = 1 }, }; device.CreateShaderResourceView(this.volumeTexture, volumeSrvDesc, shaderRenderViewHeap.CPUDescriptorHandleForHeapStart); // End load volume data // Load transfer function var transferFunctionTextureDesc = ResourceDescription.Texture1D(Format.R8G8B8A8_UNorm, TransferFunctionWidth, 1); transferFunctionTexture = device.CreateCommittedResource(new HeapProperties( HeapType.Default), HeapFlags.None, transferFunctionTextureDesc, ResourceStates.CopyDestination); long transferFunctionUploadBufferSize = GetRequiredIntermediateSize(this.transferFunctionTexture, 0, 1); // Create the GPU upload buffer. var transferFunctionTextureUploadHeap = device.CreateCommittedResource(new HeapProperties( CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, ResourceDescription.Texture1D(Format.R8G8B8A8_UNorm, TransferFunctionWidth, 1), ResourceStates.GenericRead); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture1D. byte[] transferFunctionTextureData = GenerateTransferFunctionTextureData(); var transferFunctionHandle = GCHandle.Alloc(transferFunctionTextureData, GCHandleType.Pinned); var transferFunctionPtr = Marshal.UnsafeAddrOfPinnedArrayElement(transferFunctionTextureData, 0); transferFunctionTextureUploadHeap.WriteToSubresource(0, null, transferFunctionPtr, TransferFunctionWidth, TransferFunctionWidth); transferFunctionHandle.Free(); commandList.CopyTextureRegion(new TextureCopyLocation(transferFunctionTexture, 0), 0, 0, 0, new TextureCopyLocation(transferFunctionTextureUploadHeap, 0), null); commandList.ResourceBarrierTransition(this.transferFunctionTexture, ResourceStates.CopyDestination, ResourceStates.PixelShaderResource); // Describe and create a SRV for the transfer function texture. var transferFunctionSrvDesc = new ShaderResourceViewDescription { Shader4ComponentMapping = D3DXUtilities.DefaultComponentMapping(), Format = transferFunctionTextureDesc.Format, Dimension = ShaderResourceViewDimension.Texture1D, Texture1D = { MipLevels = 1 }, }; var transferFunctionHandleIncrement = device.GetDescriptorHandleIncrementSize(DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView); CpuDescriptorHandle transferFunctionLocationDesctiptor = shaderRenderViewHeap.CPUDescriptorHandleForHeapStart + transferFunctionHandleIncrement; device.CreateShaderResourceView(this.transferFunctionTexture, transferFunctionSrvDesc, transferFunctionLocationDesctiptor); // End load transfer function data // Load gradients data var gradientsTextureDesc = ResourceDescription.Texture3D(Format.R8G8B8A8_UNorm, VolumeTextureWidth, VolumeTextureHeight, VolumeTextureDepth, 1); gradientsTexture = device.CreateCommittedResource(new HeapProperties( HeapType.Default), HeapFlags.None, gradientsTextureDesc, ResourceStates.CopyDestination); long gradientsUploadBufferSize = GetRequiredIntermediateSize(this.gradientsTexture, 0, 1); // Create the GPU upload buffer. var gradientsTextureUploadHeap = device.CreateCommittedResource(new HeapProperties( CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, ResourceDescription.Texture3D(Format.R8G8B8A8_UNorm, VolumeTextureWidth, VolumeTextureHeight, VolumeTextureDepth, 1), ResourceStates.GenericRead); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture3D. byte[] gradientsTextureData = GenerateGradientsTextureData(); var gradientsHandle = GCHandle.Alloc(gradientsTextureData, GCHandleType.Pinned); var gradientsPtr = Marshal.UnsafeAddrOfPinnedArrayElement(gradientsTextureData, 0); gradientsTextureUploadHeap.WriteToSubresource(0, null, gradientsPtr, TexturePixelSize * VolumeTextureWidth, TexturePixelSize * VolumeTextureWidth * VolumeTextureHeight); gradientsHandle.Free(); commandList.CopyTextureRegion(new TextureCopyLocation(gradientsTexture, 0), 0, 0, 0, new TextureCopyLocation(gradientsTextureUploadHeap, 0), null); commandList.ResourceBarrierTransition(this.gradientsTexture, ResourceStates.CopyDestination, ResourceStates.PixelShaderResource); // Describe and create a SRV for the gradients texture. var gradientsSrvDesc = new ShaderResourceViewDescription { Shader4ComponentMapping = D3DXUtilities.DefaultComponentMapping(), Format = gradientsTextureDesc.Format, Dimension = ShaderResourceViewDimension.Texture3D, Texture3D = { MipLevels = 1 }, }; var gradientsHandleIncrement = device.GetDescriptorHandleIncrementSize(DescriptorHeapType.ConstantBufferViewShaderResourceViewUnorderedAccessView); CpuDescriptorHandle gradientsLocationDesctiptor = shaderRenderViewHeap.CPUDescriptorHandleForHeapStart + gradientsHandleIncrement * 2; device.CreateShaderResourceView(this.gradientsTexture, gradientsSrvDesc, gradientsLocationDesctiptor); // End load gradients data // Command lists are created in the recording state, but there is nothing // to record yet. The main loop expects it to be closed, so close it now. commandList.Close(); constantBuffer = device.CreateCommittedResource(new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(1024 * 64), ResourceStates.GenericRead); //// Describe and create a constant buffer view. var cbvDesc = new ConstantBufferViewDescription { BufferLocation = constantBuffer.GPUVirtualAddress, SizeInBytes = (Utilities.SizeOf <ConstantBuffer>() + 255) & ~255 }; device.CreateConstantBufferView(cbvDesc, constantBufferViewHeap.CPUDescriptorHandleForHeapStart); // Initialize and map the constant buffers. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. constantBufferPointer = constantBuffer.Map(0); Utilities.Write(constantBufferPointer, ref constantBufferData); commandQueue.ExecuteCommandList(commandList); // Create synchronization objects. fence = device.CreateFence(0, FenceFlags.None); fenceValue = 1; // Create an event handle to use for frame synchronization. fenceEvent = new AutoResetEvent(false); WaitForPreviousFrame(); //release temp texture volumeTextureUploadHeap.Dispose(); transferFunctionTextureUploadHeap.Dispose(); gradientsTextureUploadHeap.Dispose(); }