// Load the sample assets. private void LoadAssets() { Guid iid; ID3DBlob *signature = null; ID3DBlob *error = null; ID3DBlob *vertexShader = null; ID3DBlob *pixelShader = null; try { // Create a root signature consisting of a descriptor table with a single CBV. { var featureData = new D3D12_FEATURE_DATA_ROOT_SIGNATURE { // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1 }; if (FAILED(_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, (uint)sizeof(D3D12_FEATURE_DATA_ROOT_SIGNATURE)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } const int RangesCount = 1; var ranges = stackalloc D3D12_DESCRIPTOR_RANGE1[RangesCount]; const int RootParametersCount = 1; var rootParameters = stackalloc D3D12_ROOT_PARAMETER1[RootParametersCount]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); rootParameters[0].InitAsDescriptorTable(RangesCount, ranges, D3D12_SHADER_VISIBILITY_VERTEX); // Allow input layout and deny unnecessary access to certain pipeline stages. var rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; var rootSignatureDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC(); rootSignatureDesc.Init_1_1(RootParametersCount, rootParameters, 0, null, rootSignatureFlags); ThrowIfFailed(nameof(D3D12SerializeRootSignature), D3D12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error)); fixed(ID3D12RootSignature **rootSignature = &_rootSignature) { iid = IID_ID3D12RootSignature; ThrowIfFailed(nameof(ID3D12Device.CreateRootSignature), _device->CreateRootSignature(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\HelloConstBuffer.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 the constant buffer. { fixed(ID3D12Resource **pConstantBuffer = &_constantBuffer) { var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); var bufferDesc = D3D12_RESOURCE_DESC.Buffer(1024 * 64); iid = IID_ID3D12Resource; ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource( &heapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, pOptimizedClearValue: null, &iid, (void **)pConstantBuffer)); } // Describe and create a constant buffer view. var cbvDesc = new D3D12_CONSTANT_BUFFER_VIEW_DESC { BufferLocation = _constantBuffer->GetGPUVirtualAddress(), SizeInBytes = (uint)((sizeof(SceneConstantBuffer) + 255) & ~255) // CB size is required to be 256-byte aligned. }; _device->CreateConstantBufferView(&cbvDesc, _cbvHeap->GetCPUDescriptorHandleForHeapStart()); // Map and initialize the constant buffer. We don't unmap this until the // app closes. Keeping things mapped for the lifetime of the resource is okay. var readRange = new D3D12_RANGE(); // We do not intend to read from this resource on the CPU. fixed(byte **ppCbvDataBegin = &_pCbvDataBegin) { ThrowIfFailed(nameof(ID3D12Resource.Map), _constantBuffer->Map(Subresource: 0, &readRange, (void **)ppCbvDataBegin)); Unsafe.CopyBlock(ref _pCbvDataBegin[0], ref Unsafe.As <SceneConstantBuffer, byte>(ref _constantBufferData), (uint)sizeof(SceneConstantBuffer)); } // 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(); } } }
// 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 = _msaaDesc, }; psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_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 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(); } } }
protected unsafe GraphicsShader CompileShader(GraphicsDevice graphicsDevice, GraphicsShaderKind kind, string shaderName, string entryPointName) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _compositionAssemblies.Contains(Program.s_graphicsProviderD3D12)) { var assetName = $"{shaderName}{kind}.hlsl"; fixed(char *assetPath = GetAssetFullPath("Shaders", assetName)) fixed(sbyte *entryPoint = MarshalStringToUtf8(entryPointName)) { var compileFlags = 0u; #if DEBUG // Enable better shader debugging with the graphics debugging tools. compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #endif ID3DBlob *d3dShaderBlob = null; try { var result = D3DCompileFromFile((ushort *)assetPath, pDefines: null, (ID3DInclude *)D3D_COMPILE_STANDARD_FILE_INCLUDE, entryPoint, GetD3D12CompileTarget(kind).AsPointer(), compileFlags, Flags2: 0, &d3dShaderBlob, ppErrorMsgs: null); if (FAILED(result)) { ThrowExternalException(nameof(D3DCompileFromFile), result); } var shaderBytecode = new ReadOnlySpan <byte>(d3dShaderBlob->GetBufferPointer(), (int)d3dShaderBlob->GetBufferSize()); return(graphicsDevice.CreateGraphicsShader(kind, shaderBytecode, entryPointName)); } finally { if (d3dShaderBlob != null) { d3dShaderBlob->Release(); } } } } else { var assetName = $"{shaderName}{kind}.glsl"; var assetPath = GetAssetFullPath("Shaders", assetName); var assetOutput = Path.ChangeExtension(assetPath, "spirv"); var additionalArgs = string.Empty; #if DEBUG // Enable better shader debugging with the graphics debugging tools. additionalArgs += $" -g -O0"; #endif var glslcProcessStartInfo = new ProcessStartInfo { Arguments = $"-fshader-stage={GetVulkanShaderStage(kind)} -o \"{assetOutput}\" -std=450core --target-env=vulkan1.0 --target-spv=spv1.0 -x glsl{additionalArgs} {assetPath}", FileName = "glslc.exe", WorkingDirectory = Path.GetDirectoryName(assetPath) !, }; Process.Start(glslcProcessStartInfo) !.WaitForExit(); using var fileReader = File.OpenRead(assetOutput); var bytecode = new byte[fileReader.Length]; _ = fileReader.Read(bytecode); return(graphicsDevice.CreateGraphicsShader(kind, bytecode, entryPointName)); }
private static unsafe void CopyBytesToBlob(out ID3DBlob *blob, UIntPtr size, byte[] bytes) { Span <byte> span = CreateBlob(out blob, size); bytes.CopyTo(span); }
public static extern int D3DWriteBlobToFile(ID3DBlob *pBlob, [NativeTypeName("LPCWSTR")] ushort *pFileName, [NativeTypeName("BOOL")] int bOverwrite);
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); }
public D3D12_SHADER_BYTECODE(ID3DBlob *pShaderBlob) { pShaderBytecode = pShaderBlob->GetBufferPointer(); BytecodeLength = pShaderBlob->GetBufferSize(); }
/// <summary> /// Embeds the bytecode for an exported shader as private data into another shader bytecode. /// </summary> /// <param name="shaderBlob">The bytecode produced by <see cref="CompileD2DFullShader(ReadOnlySpan{char}, D2D1ShaderProfile)"/>.</param> /// <param name="exportBlob">The bytecode produced by <see cref="CompileD2DFunction(ReadOnlySpan{char}, D2D1ShaderProfile)"/>.</param> /// <returns>An <see cref="ID3DBlob"/> instance with the combined data of <paramref name="shaderBlob"/> and <paramref name="exportBlob"/>.</returns> private static ComPtr <ID3DBlob> EmbedD2DFunctionPrivateData(ID3DBlob *shaderBlob, ID3DBlob *exportBlob) { void *shaderPtr = shaderBlob->GetBufferPointer(); nuint shaderSize = shaderBlob->GetBufferSize(); void *exportPtr = exportBlob->GetBufferPointer(); nuint exportSize = exportBlob->GetBufferSize(); using ComPtr <ID3DBlob> resultBlob = default; DirectX.D3DSetBlobPart( pSrcData: shaderPtr, SrcDataSize: shaderSize, Part: D3D_BLOB_PART.D3D_BLOB_PRIVATE_DATA, Flags: 0, pPart: exportPtr, PartSize: exportSize, ppNewShader: resultBlob.GetAddressOf()).Assert(); return(resultBlob.Move()); }
// Load the sample assets. private void LoadAssets() { Guid iid; ID3DBlob *signature = null; ID3DBlob *error = null; ID3DBlob *vertexShader = null; ID3DBlob *pixelShader = null; try { // Create the root signature. { var featureData = new D3D12_FEATURE_DATA_ROOT_SIGNATURE { // This is the highest version the sample supports. If CheckFeatureSupport succeeds, the HighestVersion returned will not be greater than this. HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1 }; if (FAILED(_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, (uint)sizeof(D3D12_FEATURE)))) { featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0; } const int RangesCount = 1; var ranges = stackalloc D3D12_DESCRIPTOR_RANGE1[RangesCount]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); const int RootParametersCount = 1; var rootParameters = stackalloc D3D12_ROOT_PARAMETER1[RootParametersCount]; rootParameters[0].InitAsDescriptorTable(1, ranges, D3D12_SHADER_VISIBILITY_PIXEL); var sampler = new D3D12_STATIC_SAMPLER_DESC { Filter = D3D12_FILTER.D3D12_FILTER_MIN_MAG_MIP_POINT, AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER, AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER, AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER, MipLODBias = 0, MaxAnisotropy = 0, ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER, BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, MinLOD = 0.0f, MaxLOD = D3D12_FLOAT32_MAX, ShaderRegister = 0, RegisterSpace = 0, ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL, }; var rootSignatureDesc = new D3D12_VERSIONED_ROOT_SIGNATURE_DESC(); rootSignatureDesc.Init_1_1(RootParametersCount, rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT); ThrowIfFailed(nameof(D3D12SerializeVersionedRootSignature), D3D12SerializeVersionedRootSignature( &rootSignatureDesc, featureData.HighestVersion, &signature, &error)); fixed(ID3D12RootSignature **rootSignature = &_rootSignature) { iid = IID_ID3D12RootSignature; ThrowIfFailed(nameof(ID3D12Device.CreateRootSignature), _device->CreateRootSignature(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\HelloTexture.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[2] { 0x44524F4F43584554, // TEXCOORD 0x0000000000000000, }; 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_R32G32_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 = new D3D12_DEPTH_STENCIL_DESC { DepthEnable = FALSE, StencilEnable = FALSE, }, SampleMask = uint.MaxValue, PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, NumRenderTargets = 1, SampleDesc = new DXGI_SAMPLE_DESC(count: 1, quality: 0), }; 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)); } // 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), UV = new Vector2(0.5f, 0.0f) }, new Vertex { Position = new Vector3(0.25f, -0.25f * AspectRatio, 0.0f), UV = new Vector2(1.0f, 1.0f) }, new Vertex { Position = new Vector3(-0.25f, -0.25f * AspectRatio, 0.0f), UV = new Vector2(0.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; } // Note: textureUploadHeap needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. ID3D12Resource *textureUploadHeap; // Create the texture. { // Describe and create a Texture2D. var textureDesc = new D3D12_RESOURCE_DESC { MipLevels = 1, Format = DXGI_FORMAT_R8G8B8A8_UNORM, Width = TextureWidth, Height = TextureHeight, Flags = D3D12_RESOURCE_FLAG_NONE, DepthOrArraySize = 1, SampleDesc = new DXGI_SAMPLE_DESC { Count = 1, Quality = 0, }, Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D, }; fixed(ID3D12Resource **pTexture = &_texture) { var heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); iid = IID_ID3D12Resource; ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource( &heapProperties, D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, pOptimizedClearValue: null, &iid, (void **)pTexture )); var uploadBufferSize = GetRequiredIntermediateSize(_texture, 0, 1); // Create the GPU upload buffer. heapProperties = new D3D12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); var bufferDesc = D3D12_RESOURCE_DESC.Buffer(uploadBufferSize); ThrowIfFailed(nameof(ID3D12Device.CreateCommittedResource), _device->CreateCommittedResource( &heapProperties, D3D12_HEAP_FLAG_NONE, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, pOptimizedClearValue: null, &iid, (void **)&textureUploadHeap )); } // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the Texture2D. var texture = GenerateTextureData(); var rowPitch = TextureWidth * TexturePixelSize; var slicePitch = rowPitch * TextureHeight; D3D12_SUBRESOURCE_DATA textureData; fixed(byte *pTexture = &texture[0]) { textureData = new D3D12_SUBRESOURCE_DATA { pData = (void *)pTexture, RowPitch = (nint)rowPitch, SlicePitch = (nint)slicePitch, }; } UpdateSubresources(_commandList, _texture, textureUploadHeap, 0, 0, 1, &textureData); var barrier = D3D12_RESOURCE_BARRIER.InitTransition(_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); _commandList->ResourceBarrier(1, &barrier); // Describe and create a SRV for the texture. var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC { Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, Format = textureDesc.Format, ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D, }; srvDesc.Anonymous.Texture2D.MipLevels = 1; _device->CreateShaderResourceView(_texture, &srvDesc, _srvHeap->GetCPUDescriptorHandleForHeapStart()); } // Close the command list and execute it to begin the initial GPU setup. ThrowIfFailed(nameof(ID3D12GraphicsCommandList.Close), _commandList->Close()); const int CommandListsCount = 1; var ppCommandLists = stackalloc ID3D12CommandList *[CommandListsCount] { (ID3D12CommandList *)_commandList, }; _commandQueue->ExecuteCommandLists(CommandListsCount, ppCommandLists); // 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(); } } }
public override void OnInit() { Guid iid; IDXGIFactory1 * factory = null; IDXGIAdapter * adapter = null; ID3D11Texture2D *backBuffer = null; ID3DBlob * vertexShaderBlob = null; ID3DBlob * pixelShaderBlob = null; try { iid = IID_IDXGIFactory1; ThrowIfFailed(nameof(CreateDXGIFactory1), CreateDXGIFactory1(&iid, (void **)&factory)); if (UseWarpDevice) { throw new NotImplementedException("WARP Device not supported for D3D11."); } else { adapter = GetHardwareAdapter(factory); } fixed(ID3D11Device **device = &_device) fixed(ID3D11DeviceContext **immediateContext = &_immediateContext) { var featureLevel = D3D_FEATURE_LEVEL_11_0; ThrowIfFailed(nameof(D3D11CreateDevice), D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_HARDWARE, Software: IntPtr.Zero, Flags: 0, &featureLevel, FeatureLevels: 1, D3D11_SDK_VERSION, device, pFeatureLevel: null, immediateContext)); } // Describe and create the swap chain. var swapChainDesc = new DXGI_SWAP_CHAIN_DESC { BufferDesc = new DXGI_MODE_DESC { Width = Width, Height = Height, Format = DXGI_FORMAT_R8G8B8A8_UNORM, }, SampleDesc = new DXGI_SAMPLE_DESC { Count = 1 }, BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT, BufferCount = FrameCount, OutputWindow = Win32Application.Hwnd, Windowed = TRUE, SwapEffect = DXGI_SWAP_EFFECT_DISCARD, }; fixed(IDXGISwapChain **swapChain = &_swapChain) { ThrowIfFailed(nameof(IDXGIFactory1.CreateSwapChain), factory->CreateSwapChain( (IUnknown *)_device, &swapChainDesc, swapChain )); } // This sample does not support fullscreen transitions. ThrowIfFailed(nameof(IDXGIFactory.MakeWindowAssociation), factory->MakeWindowAssociation(Win32Application.Hwnd, DXGI_MWA_NO_ALT_ENTER)); fixed(ID3D11RenderTargetView **renderTarget = &_renderTarget) { iid = IID_ID3D11Texture2D; ThrowIfFailed(nameof(IDXGISwapChain.GetBuffer), _swapChain->GetBuffer(0, &iid, (void **)&backBuffer)); ThrowIfFailed(nameof(ID3D11Device.CreateRenderTargetView), _device->CreateRenderTargetView((ID3D11Resource *)backBuffer, null, renderTarget)); _immediateContext->OMSetRenderTargets(1, renderTarget, pDepthStencilView: null); } var vp = new D3D11_VIEWPORT { Width = Width, Height = Height, MinDepth = 0.0f, MaxDepth = 1.0f, TopLeftX = 0, TopLeftY = 0, }; _immediateContext->RSSetViewports(1, &vp); var compileFlags = 0u; fixed(char *fileName = GetAssetFullPath(@"D3D11\Assets\Shaders\HelloTriangle.hlsl")) fixed(ID3D11VertexShader **vertexShader = &_vertexShader) fixed(ID3D11PixelShader **pixelShader = &_pixelShader) { var entryPoint = 0x00006E69614D5356; // VSMain var target = 0x0000305F345F7376; // vs_4_0 ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, null, null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, 0, &vertexShaderBlob, null)); ThrowIfFailed(nameof(ID3D11Device.CreateVertexShader), _device->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), pClassLinkage: null, vertexShader)); entryPoint = 0x00006E69614D5350; // PSMain target = 0x0000305F345F7370; // ps_4_0 ThrowIfFailed(nameof(D3DCompileFromFile), D3DCompileFromFile((ushort *)fileName, null, null, (sbyte *)&entryPoint, (sbyte *)&target, compileFlags, 0, &pixelShaderBlob, null)); ThrowIfFailed(nameof(ID3D11Device.CreatePixelShader), _device->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), pClassLinkage: null, pixelShader)); } var inputElementDescs = stackalloc D3D11_INPUT_ELEMENT_DESC[2]; { var semanticName0 = stackalloc sbyte[9]; { ((ulong *)semanticName0)[0] = 0x4E4F495449534F50; // POSITION } inputElementDescs[0] = new D3D11_INPUT_ELEMENT_DESC { SemanticName = semanticName0, SemanticIndex = 0, Format = DXGI_FORMAT_R32G32B32_FLOAT, InputSlot = 0, AlignedByteOffset = 0, InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate = 0 }; var semanticName1 = 0x000000524F4C4F43; // COLOR inputElementDescs[1] = new D3D11_INPUT_ELEMENT_DESC { SemanticName = (sbyte *)&semanticName1, SemanticIndex = 0, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0, AlignedByteOffset = 12, InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate = 0 }; } fixed(ID3D11InputLayout **inputLayout = &_inputLayout) { ThrowIfFailed(nameof(ID3D11Device.CreateInputLayout), _device->CreateInputLayout(inputElementDescs, NumElements: 2, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), inputLayout)); } _immediateContext->IASetInputLayout(_inputLayout); var triangleVertices = stackalloc Vertex[3]; { triangleVertices[0] = new Vertex { Position = new Vector3(0.0f, 0.25f * AspectRatio, 0.0f), Color = new Vector4(1.0f, 0.0f, 0.0f, 1.0f) }; triangleVertices[1] = new Vertex { Position = new Vector3(0.25f, -0.25f * AspectRatio, 0.0f), Color = new Vector4(0.0f, 1.0f, 0.0f, 1.0f) }; triangleVertices[2] = 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) * 3; var vertexBufferDesc = new D3D11_BUFFER_DESC { ByteWidth = vertexBufferSize, Usage = D3D11_USAGE_DEFAULT, BindFlags = (uint)D3D11_BIND_VERTEX_BUFFER }; var vertexBufferData = new D3D11_SUBRESOURCE_DATA { pSysMem = triangleVertices }; fixed(ID3D11Buffer **vertexBuffer = &_vertexBuffer) { ThrowIfFailed(nameof(ID3D11Device.CreateBuffer), _device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, vertexBuffer)); var stride = (uint)sizeof(Vertex); var offset = 0u; _immediateContext->IASetVertexBuffers(0, 1, vertexBuffer, &stride, &offset); } _immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); } finally { if (pixelShaderBlob != null) { _ = pixelShaderBlob->Release(); } if (vertexShaderBlob != null) { _ = vertexShaderBlob->Release(); } if (backBuffer != null) { _ = backBuffer->Release(); } if (adapter != null) { _ = adapter->Release(); } if (factory != null) { _ = factory->Release(); } } }
protected unsafe GraphicsShader CompileShader(GraphicsDevice graphicsDevice, GraphicsShaderKind kind, string shaderName, string entryPointName) { var assetName = $"{shaderName}{kind}.hlsl"; fixed(char *assetPath = GetAssetFullPath("Shaders", shaderName, assetName)) fixed(sbyte *entryPoint = entryPointName.GetUtf8Span()) { var compileFlags = 0u; if (GraphicsService.EnableDebugMode) { // Enable better shader debugging with the graphics debugging tools. compileFlags |= D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; } else { compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; } ID3DBlob *d3dShaderBlob = null; ID3DBlob *d3dShaderErrorBlob = null; try { var result = D3DCompileFromFile((ushort *)assetPath, pDefines: null, D3D_COMPILE_STANDARD_FILE_INCLUDE, entryPoint, GetD3D12CompileTarget(kind).GetPointer(), compileFlags, Flags2: 0, &d3dShaderBlob, ppErrorMsgs: &d3dShaderErrorBlob); if (FAILED(result)) { // todo: var span = TerraFX.Utilities.InteropUtilities.MarshalUtf8ToReadOnlySpan((sbyte*)pError->GetBufferPointer(), (int)pError->GetBufferSize()); var errorMsg = System.Text.Encoding.UTF8.GetString((byte *)d3dShaderErrorBlob->GetBufferPointer(), (int)d3dShaderErrorBlob->GetBufferSize()); Console.WriteLine(errorMsg); ExceptionUtilities.ThrowExternalException(nameof(D3DCompileFromFile), result); } var bytecode = new UnmanagedArray <byte>(d3dShaderBlob->GetBufferSize()); new UnmanagedReadOnlySpan <byte>((byte *)d3dShaderBlob->GetBufferPointer(), bytecode.Length).CopyTo(bytecode); switch (kind) { case GraphicsShaderKind.Pixel: { return(graphicsDevice.CreatePixelShader(bytecode, entryPointName)); } case GraphicsShaderKind.Vertex: { return(graphicsDevice.CreateVertexShader(bytecode, entryPointName)); } default: { ThrowForInvalidKind(kind); return(null !); } } } finally { if (d3dShaderBlob != null) { _ = d3dShaderBlob->Release(); } if (d3dShaderErrorBlob != null) { _ = d3dShaderErrorBlob->Release(); } } }
public static extern HRESULT D3DWriteBlobToFile(ID3DBlob *pBlob, [NativeTypeName("LPCWSTR")] ushort *pFileName, BOOL bOverwrite);
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); }