【DirectX12】2.示例三角形绘制

示例三角形绘制

1.效果

下面只贴出关于dx的代码,有时间再详细说明。

2.标头.h

#pragma once

#include "pch.h"
#include "LVEDebug.h"
#include "LVESystem.h"

#include <d3d12.h>
#include "d3dx12.h"
#include <dxgi1_6.h>
#include <D3DCompiler.h>
#include <DirectXMath.h>
using namespace DirectX;

typedef IDXGIFactory7 _IDXGIFactory;
typedef IDXGIAdapter4 _IDXGIAdapter;
typedef IDXGISwapChain4 _IDXGISwapChain;
namespace LVE
{
	void GetHardwareAdapter(_IDXGIFactory* pFactory, _IDXGIAdapter** ppAdapter);

	const int SWAP_CHAIN_BUFFER_COUNT = 2;//此值不能小于2
	class DirectX
	{
	public:
		//pipeline
		com_ptr<_IDXGIFactory> _factory;
		com_ptr<_IDXGIAdapter> _adapter;
		com_ptr<ID3D12Device> _device;
		com_ptr<ID3D12CommandQueue> _commandQueue;
		com_ptr<_IDXGISwapChain> _swapChain;
		com_ptr<ID3D12DescriptorHeap> _rtvHeap;
		UINT _rtvDescriptorSize;
		com_ptr<ID3D12Resource> _renderTargets[SWAP_CHAIN_BUFFER_COUNT];
		com_ptr<ID3D12CommandAllocator> _commandAllocator;

		//assets
		com_ptr<ID3D12RootSignature> _rootSignature;
		com_ptr<ID3D12PipelineState> _pipelineState;
		com_ptr<ID3D12GraphicsCommandList> _commandList;
		com_ptr<ID3D12Resource> _vertexBuffer;
		D3D12_VERTEX_BUFFER_VIEW _vertexBufferView;

		//Synchronization objects.
		UINT _frameIndex;
		HANDLE _fenceEvent;
		com_ptr<ID3D12Fence> _fence;
		UINT64 _fenceValue;

		D3D12_VIEWPORT _viewport;
		D3D12_RECT _scissorRect;

		void Init();
		void Update();
		void Render();
		void Release();
	private:

		struct Vertex
		{
			XMFLOAT3 position;
			XMFLOAT4 color;
		};

		void _init_pre()
		{
			if (!XMVerifyCPUSupport())
			{
				g_debug.Line(L"DirectXMath does not support the current platform!");
				return;
			}
		}

		void _init_pipeline()
		{
#if defined(_DEBUG)
			_init_debug_layer();
#endif
			_init_dxgi();
			_init_device();
			_init_command_queue();
			_init_swap_chain();
			_init_descriptor_heap();
			_init_render_target_view();
			_init_command_allocator();
		}

		void _init_debug_layer();
		
		void _init_dxgi();

		void _init_device();

		void _init_command_queue();

		void _init_swap_chain();

		void _init_descriptor_heap();

		void _init_render_target_view();

		void _init_command_allocator();

		//
		void _init_assets()
		{
			_init_root_signature();
			_init_graphics_pipeline_state();
			_init_command_list();
			_init_vertex_buffer();
			_init_fence();
		}

		void _init_root_signature();

		void _init_graphics_pipeline_state();

		void _init_command_list();

		void _init_vertex_buffer();

		void _init_fence();


		void WaitForPreviousFrame();

		void PopulateCommandList();
	};

	extern DirectX g_dx;
}

3.源.cpp

#include "LVEDirectX.h"

namespace LVE
{
	DirectX g_dx;

	void DirectX::Init()
	{
		_init_pre();
		//load pipeline
		_init_pipeline();
		//load assets
		_init_assets();

		_viewport.Height = 600;
		_viewport.MaxDepth = 1.0f;
		_viewport.MinDepth = 0;
		_viewport.TopLeftX = 0;
		_viewport.TopLeftY = 0;
		_viewport.Width = 800;

		_scissorRect.bottom = 600;
		_scissorRect.left = 0;
		_scissorRect.right = 800;
		_scissorRect.top = 0;
	}

	void DirectX::Update()
	{

	}

	void DirectX::Render()
	{
		// Record all the commands we need to render the scene into the command list.
		PopulateCommandList();

		// Execute the command list.
		ID3D12CommandList* ppCommandLists[] = { _commandList.get() };
		_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

		// Present the frame.
		HRESULT hr = _swapChain->Present(1, 0);
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to present frame!");
			return;
		}

		WaitForPreviousFrame();
	}

	void DirectX::Release()
	{
		// Wait for the GPU to be done with all resources.
		WaitForPreviousFrame();

		CloseHandle(_fenceEvent);
	}

	void DirectX::_init_debug_layer()
	{
		// Enable the D3D12 debug layer.
		com_ptr<ID3D12Debug> debugController;
		HRESULT hr = D3D12GetDebugInterface(IID_PPV_ARGS(&debugController));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create debug layer!");
			return;
		}
		debugController->EnableDebugLayer();
	}

	void DirectX::_init_dxgi()
	{
		HRESULT hr = CreateDXGIFactory1(__uuidof(_IDXGIFactory), (void**)(&_factory));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create DXGI factory!");
			return;
		}
	}

	void DirectX::_init_device()
	{
		_IDXGIAdapter* adapter;
		GetHardwareAdapter(_factory.get(), &adapter);
		if (adapter == nullptr)
		{
			g_debug.Line(L"Failed to enumerate hardware adapter!");
			return;
		}
		_adapter.attach(adapter);

		HRESULT hr = D3D12CreateDevice(
			_adapter.get(),
			D3D_FEATURE_LEVEL_11_0,
			IID_PPV_ARGS(&_device));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create device!");
			return;
		}
	}

	void DirectX::_init_command_queue()
	{
		D3D12_COMMAND_QUEUE_DESC desc;
		desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
		desc.NodeMask = 0;
		desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
		desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;

		HRESULT hr = _device->CreateCommandQueue(&desc, IID_PPV_ARGS(&_commandQueue));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create command queue!");
			return;
		}
	}

	void DirectX::_init_swap_chain()
	{
		com_ptr<IDXGISwapChain> swapChain;

		DXGI_SWAP_CHAIN_DESC desc;
		desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT;
		desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		desc.BufferDesc.Height = 600;
		desc.BufferDesc.RefreshRate.Denominator = 0;
		desc.BufferDesc.RefreshRate.Numerator = 0;
		desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		desc.BufferDesc.Width = 800;
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		desc.Flags = 0;
		desc.OutputWindow = g_system.GetHwnd();
		desc.SampleDesc.Count = 1;
		desc.SampleDesc.Quality = 0;
		desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		desc.Windowed = TRUE;

		HRESULT hr = _factory->CreateSwapChain(
			_commandQueue.get(),
			&desc,
			swapChain.put()
		);
		
		/*
		DXGI_SWAP_CHAIN_DESC1 desc;
		desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
		desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT;
		desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		desc.Flags = 0;
		desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;	
		desc.Height = 600;
		desc.SampleDesc.Count = 1;
		desc.SampleDesc.Quality = 0;
		desc.Scaling = DXGI_SCALING_NONE;
		desc.Stereo = FALSE;
		desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		desc.Width = 800;

		//DXGI_SWAP_CHAIN_FULLSCREEN_DESC desc_full;

		HRESULT hr = _factory->CreateSwapChainForHwnd(
			_commandQueue.get(),// For Direct3D 12, this is a pointer to a direct command queue, and not to the device.
			g_system.GetHwnd(),
			&desc,
			nullptr,
			nullptr,
			swapChain.put()
		);
		*/
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create swap chain!");
			return;
		}
		swapChain.as(_swapChain);

		
	}

	void DirectX::_init_descriptor_heap()
	{
		D3D12_DESCRIPTOR_HEAP_DESC desc;
		desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
		desc.NodeMask = 0;
		desc.NumDescriptors = SWAP_CHAIN_BUFFER_COUNT;//
		desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;

		HRESULT hr = _device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_rtvHeap));

		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create descriptor heap!");
			return;
		}

		_rtvDescriptorSize = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	}

	void DirectX::_init_render_target_view()
	{
		UINT m_rtvDescriptorSize = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

		// Create frame resources.
		//D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = _rtvHeap->GetCPUDescriptorHandleForHeapStart();
		CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(_rtvHeap->GetCPUDescriptorHandleForHeapStart());

		// Create a RTV for each frame.
		for (UINT n = 0; n < SWAP_CHAIN_BUFFER_COUNT; n++)
		{
			HRESULT hr = _swapChain->GetBuffer(n, IID_PPV_ARGS(&_renderTargets[n]));
			if (FAILED(hr))
			{
				g_debug.Line(L"Failed to get buffer from the swap chain!");
				continue;
			}
			_device->CreateRenderTargetView(_renderTargets[n].get(), nullptr, rtvHandle);
			rtvHandle.Offset(1, m_rtvDescriptorSize);
		}
	}

	void DirectX::_init_command_allocator()
	{
		HRESULT hr = _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&_commandAllocator));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create command allocator!");
			return;
		}
	}

	void DirectX::_init_root_signature()
	{
		CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;
		rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

		ID3DBlob* signature;
		ID3DBlob* error;
		HRESULT hr = D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to serialize root signature!");
			return;
		}
		hr = _device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to serialize root signature!");
			return;
		}
	}

	void DirectX::_init_graphics_pipeline_state()
	{
		com_ptr<ID3DBlob> vertexShader;
		com_ptr<ID3DBlob> pixelShader;

#if defined(_DEBUG)
		// Enable better shader debugging with the graphics debugging tools.
		UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#else
		UINT compileFlags = 0;
#endif
		HRESULT hr = D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, vertexShader.put(), nullptr);
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to compile vertex shader!");
			return;
		}
		hr = D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, pixelShader.put(), nullptr);
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to compile pixel shader!");
			return;
		}

		// Define the vertex input layout.
		D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =
		{
			{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
			{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
		};

		// Describe and create the graphics pipeline state object (PSO).
		D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
		psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) };
		psoDesc.pRootSignature = _rootSignature.get();
		psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), vertexShader->GetBufferSize() };
		psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), pixelShader->GetBufferSize() };
		psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
		psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
		psoDesc.DepthStencilState.DepthEnable = FALSE;
		psoDesc.DepthStencilState.StencilEnable = FALSE;
		psoDesc.SampleMask = UINT_MAX;
		psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
		psoDesc.NumRenderTargets = 1;
		psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
		psoDesc.SampleDesc.Count = 1;

		hr = _device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&_pipelineState));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create graphics pipeline state!");
			return;
		}
	}

	void DirectX::_init_command_list()
	{
		HRESULT hr = _device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _commandAllocator.get(), _pipelineState.get(), IID_PPV_ARGS(&_commandList));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create command list!");
			return;
		}

		_commandList->Close();
	}

	void DirectX::_init_vertex_buffer()
	{
		// Define the geometry for a triangle.
		Vertex triangleVertices[] =
		{
			{ { 0.0f, 0.25f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
			{ { 0.25f, -0.25f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
			{ { -0.25f, -0.25f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
		};

		const UINT vertexBufferSize = sizeof(triangleVertices);

		// 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.
		CD3DX12_HEAP_PROPERTIES heapProps(D3D12_HEAP_TYPE_UPLOAD);
		auto desc = CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize);
		HRESULT hr = _device->CreateCommittedResource(
			&heapProps,
			D3D12_HEAP_FLAG_NONE,
			&desc,
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(&_vertexBuffer));
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to create vertex buffer!");
			return;
		}

		// Copy the triangle data to the vertex buffer.
		UINT8* pVertexDataBegin;
		CD3DX12_RANGE readRange(0, 0);        // We do not intend to read from this resource on the CPU.
		hr = _vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin));
		memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));
		_vertexBuffer->Unmap(0, nullptr);

		// Initialize the vertex buffer view.
		_vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress();
		_vertexBufferView.StrideInBytes = sizeof(Vertex);
		_vertexBufferView.SizeInBytes = vertexBufferSize;
	}

	void DirectX::_init_fence()
	{
		HRESULT hr = _device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&_fence));
		_fenceValue = 1;

		// Create an event handle to use for frame synchronization.
		_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
		if (_fenceEvent == nullptr)
		{
			hr = HRESULT_FROM_WIN32(GetLastError());
			if (FAILED(hr))
			{
				g_debug.Line(L"Failed to create fence!");
				return;
			}
		}

		// 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();
	}

	void DirectX::WaitForPreviousFrame()
	{
		// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
		// This is code implemented as such for simplicity. More advanced samples 
		// illustrate how to use fences for efficient resource usage.

		// Signal and increment the fence value.
		const UINT64 fence = _fenceValue;
		HRESULT hr = _commandQueue->Signal(_fence.get(), fence);
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to signal and increment fence!");
			return;
		}
		_fenceValue++;

		// Wait until the previous frame is finished.
		if (_fence->GetCompletedValue() < fence)
		{
			hr = _fence->SetEventOnCompletion(fence, _fenceEvent);
			if (FAILED(hr))
			{
				g_debug.Line(L"Failed to set event on completion!");
				return;
			}
			WaitForSingleObject(_fenceEvent, INFINITE);
		}

		_frameIndex = _swapChain->GetCurrentBackBufferIndex();
	}

	void DirectX::PopulateCommandList()
	{
		// Command list allocators can only be reset when the associated 
		// command lists have finished execution on the GPU; apps should use 
		// fences to determine GPU execution progress.
		HRESULT hr = _commandAllocator->Reset();
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to reset command allocator!");
			return;
		}
		// However, when ExecuteCommandList() is called on a particular command 
		// list, that command list can then be reset at any time and must be before 
		// re-recording.
		hr = _commandList->Reset(_commandAllocator.get(), _pipelineState.get());
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to reset command list!");
			return;
		}

		// Set necessary state.
		_commandList->SetGraphicsRootSignature(_rootSignature.get());
		_commandList->RSSetViewports(1, &_viewport);
		_commandList->RSSetScissorRects(1, &_scissorRect);

		// Indicate that the back buffer will be used as a render target.
		auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(_renderTargets[_frameIndex].get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
		_commandList->ResourceBarrier(1, &barrier);

		CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(_rtvHeap->GetCPUDescriptorHandleForHeapStart(), _frameIndex, _rtvDescriptorSize);
		_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

		// Record commands.
		const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
		_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
		_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
		_commandList->IASetVertexBuffers(0, 1, &_vertexBufferView);
		_commandList->DrawInstanced(3, 1, 0, 0);

		// Indicate that the back buffer will now be used to present.
		barrier = CD3DX12_RESOURCE_BARRIER::Transition(_renderTargets[_frameIndex].get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
		_commandList->ResourceBarrier(1, &barrier);

		hr = _commandList->Close();
		if (FAILED(hr))
		{
			g_debug.Line(L"Failed to close command list!");
			return;
		}
	}

	void GetHardwareAdapter(_IDXGIFactory* pFactory, _IDXGIAdapter** ppAdapter)
	{
		*ppAdapter = nullptr;
		for (UINT adapterIndex = 0; ; ++adapterIndex)
		{
			_IDXGIAdapter* pAdapter = nullptr;
			if (DXGI_ERROR_NOT_FOUND == pFactory->EnumAdapterByGpuPreference(
				adapterIndex,
				DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, _uuidof(_IDXGIAdapter), (void**)&pAdapter))
			{
				// No more adapters to enumerate.
				break;
			}

			// Check to see if the adapter supports Direct3D 12, but don't create the
			// actual device yet.
			if (SUCCEEDED(D3D12CreateDevice(pAdapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
			{
				*ppAdapter = pAdapter;
				return;
			}
			pAdapter->Release();
		}
	}

}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值