public static void Init([NativeTypeName("D3D12_ROOT_SIGNATURE_DESC &")] out D3D12_ROOT_SIGNATURE_DESC desc, uint numParameters, [NativeTypeName("const D3D12_ROOT_PARAMETER *")] D3D12_ROOT_PARAMETER *_pParameters, uint numStaticSamplers = 0, [NativeTypeName("const D3D12_STATIC_SAMPLER_DESC *")] D3D12_STATIC_SAMPLER_DESC *_pStaticSamplers = null, D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE) { desc.NumParameters = numParameters; desc.pParameters = _pParameters; desc.NumStaticSamplers = numStaticSamplers; desc.pStaticSamplers = _pStaticSamplers; desc.Flags = flags; }
protected override unsafe ID3D12RootSignature *CreateRootSignature() { using ComPtr <ID3DBlob> signature = null; using ComPtr <ID3DBlob> error = null; var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC { Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT }; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, signature.GetAddressOf(), error.GetAddressOf())); ID3D12RootSignature *rootSignature; ThrowIfFailed(D3DDevice->CreateRootSignature(nodeMask: 0, signature.Get()->GetBufferPointer(), signature.Get()->GetBufferSize(), __uuidof <ID3D12RootSignature>(), (void **)&rootSignature)); return(rootSignature); }
/// <summary> /// Creates a new <see cref="RootSignature"/> /// </summary> /// <param name="device">The <see cref="ID3D12Device"/> used to create the root signature</param> /// <param name="rootParameters">The <see cref="RootParameter"/>s in the signature</param> /// <param name="staticSamplers">The <see cref="StaticSampler"/>s in the signature</param> /// <returns>A new <see cref="RootSignature"/></returns> public static RootSignature Create(ID3D12Device *device, ReadOnlyMemory <RootParameter> rootParameters, ReadOnlyMemory <StaticSampler> staticSamplers) { using var rootParams = RentedArray <D3D12_ROOT_PARAMETER> .Create(rootParameters.Length); using var samplers = RentedArray <D3D12_STATIC_SAMPLER_DESC> .Create(staticSamplers.Length); TranslateStaticSamplers(staticSamplers, samplers.Value); fixed(D3D12_ROOT_PARAMETER *pRootParams = rootParams.Value) fixed(D3D12_STATIC_SAMPLER_DESC * pSamplerDesc = samplers.Value) { var desc = new D3D12_ROOT_SIGNATURE_DESC { NumParameters = (uint)rootParams.Value.Length, pParameters = pRootParams, NumStaticSamplers = (uint)samplers.Value.Length, pStaticSamplers = pSamplerDesc, Flags = D3D12_ROOT_SIGNATURE_FLAGS.D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT // TODO provide finer grained control }; ID3DBlob *pBlob = default; ID3DBlob *pError = default; int hr = Windows.D3D12SerializeRootSignature( &desc, D3D_ROOT_SIGNATURE_VERSION.D3D_ROOT_SIGNATURE_VERSION_1, &pBlob, &pError ); if (Windows.FAILED(hr)) { ThrowHelper.ErrorWithBlob(hr, pError); } using ComPtr <ID3D12RootSignature> rootSig = default; Guard.ThrowIfFailed(device->CreateRootSignature( 0 /* TODO: MULTI-GPU */, pBlob->GetBufferPointer(), pBlob->GetBufferSize(), rootSig.Guid, ComPtr.GetVoidAddressOf(&rootSig) )); return(new RootSignature(rootSig.Move(), rootParameters, staticSamplers)); } }
// Load the sample assets. private void LoadAssets() { Guid iid; ID3DBlob *signature = null; ID3DBlob *error = null; ID3DBlob *vertexShader = null; ID3DBlob *pixelShader = null; try { // Create an empty root signature. { var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC { Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT }; ThrowIfFailed(nameof(D3D12SerializeRootSignature), D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); fixed(ID3D12RootSignature **rootSignature = &_rootSignature) { iid = IID_ID3D12RootSignature; ThrowIfFailed(nameof(ID3D12Device.CreateRootSignature), _device->CreateRootSignature(nodeMask: 0, signature->GetBufferPointer(), signature->GetBufferSize(), &iid, (void **)rootSignature)); } } // Create the pipeline state, which includes compiling and loading shaders. { var compileFlags = 0u; #if DEBUG // Enable better shader debugging with the graphics debugging tools. compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #endif fixed(char *fileName = GetAssetFullPath(@"D3D12\Assets\Shaders\HelloTriangle.hlsl")) { var entryPoint = 0x00006E69614D5356; // VSMain var target = 0x0000305F355F7376; // vs_5_0 ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, pDefines: null, pInclude: null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, Flags2: 0, &vertexShader, ppErrorMsgs: null)); entryPoint = 0x00006E69614D5350; // PSMain target = 0x0000305F355F7370; // ps_5_0 ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, pDefines: null, pInclude: null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, Flags2: 0, &pixelShader, ppErrorMsgs: null)); } // Define the vertex input layout. const int InputElementDescsCount = 2; var semanticName0 = stackalloc ulong[2] { 0x4E4F495449534F50, // POSITION 0x0000000000000000, }; var semanticName1 = stackalloc ulong[1] { 0x000000524F4C4F43, // COLOR }; var inputElementDescs = stackalloc D3D12_INPUT_ELEMENT_DESC[InputElementDescsCount] { new D3D12_INPUT_ELEMENT_DESC { SemanticName = (sbyte *)semanticName0, Format = DXGI_FORMAT_R32G32B32_FLOAT, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, }, new D3D12_INPUT_ELEMENT_DESC { SemanticName = (sbyte *)semanticName1, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, AlignedByteOffset = 12, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, }, }; // Describe and create the graphics pipeline state object (PSO). var psoDesc = new D3D12_GRAPHICS_PIPELINE_STATE_DESC { InputLayout = new D3D12_INPUT_LAYOUT_DESC { pInputElementDescs = inputElementDescs, NumElements = InputElementDescsCount, }, pRootSignature = _rootSignature, VS = new D3D12_SHADER_BYTECODE(vertexShader), PS = new D3D12_SHADER_BYTECODE(pixelShader), RasterizerState = D3D12_RASTERIZER_DESC.DEFAULT, BlendState = D3D12_BLEND_DESC.DEFAULT, DepthStencilState = D3D12_DEPTH_STENCIL_DESC.DEFAULT, SampleMask = uint.MaxValue, PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, NumRenderTargets = 1, SampleDesc = new DXGI_SAMPLE_DESC(count: 1, quality: 0), }; psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; fixed(ID3D12PipelineState **pipelineState = &_pipelineState) { iid = IID_ID3D12PipelineState; ThrowIfFailed(nameof(ID3D12Device.CreateGraphicsPipelineState), _device->CreateGraphicsPipelineState(&psoDesc, &iid, (void **)pipelineState)); } } // Create the command list. fixed(ID3D12GraphicsCommandList **commandList = &_commandList) { iid = IID_ID3D12GraphicsCommandList; ThrowIfFailed(nameof(ID3D12Device.CreateCommandList), _device->CreateCommandList(nodeMask: 0, D3D12_COMMAND_LIST_TYPE_DIRECT, _commandAllocator, _pipelineState, &iid, (void **)commandList)); } // 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. ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close()); // Create the vertex buffer. { // Define the geometry for a triangle. const int TriangleVerticesCount = 3; var triangleVertices = stackalloc Vertex[TriangleVerticesCount] { new Vertex { Position = new Vector3(0.0f, 0.25f * AspectRatio, 0.0f), Color = new Vector4(1.0f, 0.0f, 0.0f, 1.0f) }, new Vertex { Position = new Vector3(0.25f, -0.25f * AspectRatio, 0.0f), Color = new Vector4(0.0f, 1.0f, 0.0f, 1.0f) }, new Vertex { Position = new Vector3(-0.25f, -0.25f * AspectRatio, 0.0f), Color = new Vector4(0.0f, 0.0f, 1.0f, 1.0f) }, }; var vertexBufferSize = (uint)sizeof(Vertex) * TriangleVerticesCount; // 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. fixed(ID3D12Resource **vertexBuffer = &_vertexBuffer) { var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); var bufferDesc = D3D12_RESOURCE_DESC.Buffer(vertexBufferSize); iid = IID_ID3D12Resource; ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource( &heapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, pOptimizedClearValue: null, &iid, (void **)vertexBuffer )); } // Copy the triangle data to the vertex buffer. var readRange = new D3D12_RANGE(); byte *pVertexDataBegin; ThrowIfFailed(nameof(ID3D12Resource.Map), _vertexBuffer->Map(Subresource: 0, &readRange, (void **)&pVertexDataBegin)); Unsafe.CopyBlock(pVertexDataBegin, triangleVertices, vertexBufferSize); _vertexBuffer->Unmap(0, null); // Initialize the vertex buffer view. _vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress(); _vertexBufferView.StrideInBytes = (uint)sizeof(Vertex); _vertexBufferView.SizeInBytes = vertexBufferSize; } // Create and record the bundle. { fixed(ID3D12GraphicsCommandList **ppBundle = &_bundle) { iid = IID_ID3D12GraphicsCommandList; ThrowIfFailed(nameof(ID3D12Device.CreateCommandList), _device->CreateCommandList(nodeMask: 0, D3D12_COMMAND_LIST_TYPE_BUNDLE, _bundleAllocator, _pipelineState, &iid, (void **)ppBundle)); } _bundle->SetGraphicsRootSignature(_rootSignature); _bundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); fixed(D3D12_VERTEX_BUFFER_VIEW *vertexBufferView = &_vertexBufferView) { _bundle->IASetVertexBuffers(StartSlot: 0, 1, vertexBufferView); } _bundle->DrawInstanced(3, 1, 0, 0); ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _bundle->Close()); } // Create synchronization objects and wait until assets have been uploaded to the GPU. { fixed(ID3D12Fence **fence = &_fence) { iid = IID_ID3D12Fence; ThrowIfFailed(nameof(ID3D12Device.CreateFence), _device->CreateFence(0, D3D12_FENCE_FLAG_NONE, &iid, (void **)fence)); _fenceValue = 1; } // Create an event handle to use for frame synchronization. _fenceEvent = CreateEventW(lpEventAttributes: null, bManualReset: FALSE, bInitialState: FALSE, lpName: null); if (_fenceEvent == null) { var hr = Marshal.GetHRForLastWin32Error(); Marshal.ThrowExceptionForHR(hr); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForPreviousFrame(); } } finally { if (signature != null) { signature->Release(); } if (error != null) { error->Release(); } if (vertexShader != null) { vertexShader->Release(); } if (pixelShader != null) { pixelShader->Release(); } } }
private Pointer <ID3D12RootSignature> CreateD3D12RootSignature() { ThrowIfDisposedOrDisposing(_state, nameof(D3D12GraphicsPipelineSignature)); ID3DBlob *rootSignatureBlob = null; ID3DBlob *rootSignatureErrorBlob = null; try { ID3D12RootSignature *d3d12RootSignature; var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC { Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, }; var resources = Resources; var resourcesLength = resources.Length; var rootParametersLength = 0; var staticSamplersLength = 0; var rootParametersIndex = 0; var constantShaderRegister = 0; var textureShaderRegister = 0; var staticSamplersIndex = 0; for (var inputIndex = 0; inputIndex < resourcesLength; inputIndex++) { rootParametersLength++; if (resources[inputIndex].Kind == GraphicsPipelineResourceKind.Texture) { staticSamplersLength++; } } var rootParameters = stackalloc D3D12_ROOT_PARAMETER[rootParametersLength]; var staticSamplers = stackalloc D3D12_STATIC_SAMPLER_DESC[staticSamplersLength]; var descriptorRanges = stackalloc D3D12_DESCRIPTOR_RANGE[staticSamplersLength]; for (var inputIndex = 0; inputIndex < resourcesLength; inputIndex++) { var input = resources[inputIndex]; switch (input.Kind) { case GraphicsPipelineResourceKind.ConstantBuffer: { var shaderVisibility = GetD3D12ShaderVisiblity(input.ShaderVisibility); rootParameters[rootParametersIndex].InitAsConstantBufferView(unchecked ((uint)constantShaderRegister), registerSpace: 0, shaderVisibility); constantShaderRegister++; rootParametersIndex++; break; } case GraphicsPipelineResourceKind.Texture: { descriptorRanges[staticSamplersIndex] = new D3D12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, numDescriptors: 1, baseShaderRegister: unchecked ((uint)textureShaderRegister)); var shaderVisibility = GetD3D12ShaderVisiblity(input.ShaderVisibility); rootParameters[rootParametersIndex].InitAsDescriptorTable(1, &descriptorRanges[staticSamplersIndex], shaderVisibility); staticSamplers[staticSamplersIndex] = new D3D12_STATIC_SAMPLER_DESC( shaderRegister: unchecked ((uint)staticSamplersIndex), shaderVisibility: shaderVisibility ); textureShaderRegister++; rootParametersIndex++; staticSamplersIndex++; break; } default: { break; } } } rootSignatureDesc.NumParameters = unchecked ((uint)rootParametersLength); rootSignatureDesc.pParameters = rootParameters; rootSignatureDesc.NumStaticSamplers = unchecked ((uint)staticSamplersLength); rootSignatureDesc.pStaticSamplers = staticSamplers; ThrowExternalExceptionIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &rootSignatureErrorBlob), nameof(D3D12SerializeRootSignature)); var iid = IID_ID3D12RootSignature; ThrowExternalExceptionIfFailed(Device.D3D12Device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), &iid, (void **)&d3d12RootSignature), nameof(ID3D12Device.CreateRootSignature)); return(d3d12RootSignature); } finally { ReleaseIfNotNull(rootSignatureErrorBlob); ReleaseIfNotNull(rootSignatureBlob); }
private Pointer <ID3D12RootSignature> CreateD3D12RootSignature() { _state.ThrowIfDisposedOrDisposing(); ID3DBlob *rootSignatureBlob = null; ID3DBlob *rootSignatureErrorBlob = null; try { ID3D12RootSignature *d3d12RootSignature; var rootParameters = Array.Empty <D3D12_ROOT_PARAMETER>(); var rootSignatureDesc = new D3D12_ROOT_SIGNATURE_DESC { Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, }; var resources = Resources; var resourcesLength = resources.Length; var rootParametersIndex = 0; var constantShaderRegister = 0; if (resourcesLength != 0) { rootParameters = new D3D12_ROOT_PARAMETER[resourcesLength]; for (var inputIndex = 0; inputIndex < resourcesLength; inputIndex++) { var input = resources[inputIndex]; switch (input.Kind) { case GraphicsPipelineResourceKind.ConstantBuffer: { var shaderVisibility = GetD3D12ShaderVisiblity(input.ShaderVisibility); rootParameters[rootParametersIndex].InitAsConstantBufferView(unchecked ((uint)constantShaderRegister), registerSpace: 0, shaderVisibility); constantShaderRegister++; rootParametersIndex++; break; } default: { break; } } } } fixed(D3D12_ROOT_PARAMETER *pRootParameters = rootParameters) { rootSignatureDesc.NumParameters = unchecked ((uint)rootParameters.Length); rootSignatureDesc.pParameters = pRootParameters; ThrowExternalExceptionIfFailed(nameof(D3D12SerializeRootSignature), D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &rootSignatureErrorBlob)); } var iid = IID_ID3D12RootSignature; ThrowExternalExceptionIfFailed(nameof(ID3D12Device.CreateRootSignature), D3D12GraphicsDevice.D3D12Device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), &iid, (void **)&d3d12RootSignature)); return(d3d12RootSignature); } finally { ReleaseIfNotNull(rootSignatureErrorBlob); ReleaseIfNotNull(rootSignatureBlob); }