C++でDirectX12を使用して三角形の色を変更しよう

DirectX12で定数バッファに関しての覚書


C++でDirectX12を使って三角形を描画しよう
https://qiita.com/sanoh/items/75917a0375bc1d1cc01c

■Setp1：ピクセルシェーダの変更
---
![2018-12-10 (4).png](https://qiita-image-store.s3.amazonaws.com/0/122121/3b7a8689-77f0-1b16-ac27-dd5185749a2b.png)
色を後から指定して、それで三角形を塗りつぶします。

```:PixelShader.hlsl
float4 Color;

float4 main() : SV_TARGET
{
	return Color;
}
```
■Step2：DX12Rendererの修正
---

```c++:DX12Renderer.cpp
#include <fstream>
#include "DX12Renderer.h"

DX12Renderer::DX12Renderer(HWND hwnd, int window_width, int window_height) :
	_window_hwnd(hwnd),
	_window_width(window_width),
	_window_height(window_height) {

	UINT flagsDXGI = 0;
	ID3D12Debug* debug = nullptr;
	HRESULT hr;
#if _DEBUG
	D3D12GetDebugInterface(IID_PPV_ARGS(&debug));
	if (debug) {
		debug->EnableDebugLayer();
		debug->Release();
	}
	flagsDXGI |= DXGI_CREATE_FACTORY_DEBUG;
#endif
	hr = CreateDXGIFactory2(flagsDXGI, IID_PPV_ARGS(_factory.ReleaseAndGetAddressOf()));
	if (FAILED(hr)) {
		return;
	}
	ComPtr<IDXGIAdapter> adapter;
	hr = _factory->EnumAdapters(0, adapter.GetAddressOf());
	if (FAILED(hr)) {
		return;
	}
	// デバイス生成.
	// D3D12は 最低でも D3D_FEATURE_LEVEL_11_0 を要求するようだ.
	hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(_device.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}
	// コマンドアロケータを生成.
	hr = _device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(_command_allocator.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}
	// コマンドキューを生成.
	D3D12_COMMAND_QUEUE_DESC desc_command_queue;
	ZeroMemory(&desc_command_queue, sizeof(desc_command_queue));
	desc_command_queue.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
	desc_command_queue.Priority = 0;
	desc_command_queue.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
	hr = _device->CreateCommandQueue(&desc_command_queue, IID_PPV_ARGS(_command_queue.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}
	// コマンドキュー用のフェンスを準備.
	_fence_event = CreateEvent(NULL, FALSE, FALSE, NULL);
	hr = _device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(_queue_fence.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}

	// スワップチェインを生成.
	DXGI_SWAP_CHAIN_DESC desc_swap_chain;
	ZeroMemory(&desc_swap_chain, sizeof(desc_swap_chain));
	desc_swap_chain.BufferCount = 2;
	desc_swap_chain.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc_swap_chain.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	desc_swap_chain.OutputWindow = _window_hwnd;
	desc_swap_chain.SampleDesc.Count = 1;
	desc_swap_chain.Windowed = TRUE;
	desc_swap_chain.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
	desc_swap_chain.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
	hr = _factory->CreateSwapChain(_command_queue.Get(), &desc_swap_chain, (IDXGISwapChain**)_swap_chain.GetAddressOf());
	if (FAILED(hr)) {
		return;
	}
	// コマンドリストの作成.
	hr = _device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _command_allocator.Get(), nullptr, IID_PPV_ARGS(_command_list.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}

	// ディスクリプタヒープ(RenderTarget用)の作成.
	D3D12_DESCRIPTOR_HEAP_DESC desc_heap;
	ZeroMemory(&desc_heap, sizeof(desc_heap));
	desc_heap.NumDescriptors = 2;
	desc_heap.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
	desc_heap.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	hr = _device->CreateDescriptorHeap(&desc_heap, IID_PPV_ARGS(_descriptor_heap.GetAddressOf()));
	if (FAILED(hr)) {
		return;
	}

	// レンダーターゲット(プライマリ用)の作成.
	UINT stride_handle_bytes = _device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	for (UINT i = 0; i < desc_swap_chain.BufferCount; ++i) {
		hr = _swap_chain->GetBuffer(i, IID_PPV_ARGS(_render_target[i].GetAddressOf()));
		if (FAILED(hr)) {
			return;
		}
		_rtv_handle[i] = _descriptor_heap->GetCPUDescriptorHandleForHeapStart();
		_rtv_handle[i].ptr += i * stride_handle_bytes;
		_device->CreateRenderTargetView(_render_target[i].Get(), nullptr, _rtv_handle[i]);
	}
	//	リソースの初期化
	ResourceSetup();
}

DX12Renderer::~DX12Renderer() {
	if (_g_vertex_shader.binaryPtr) {
		free(_g_vertex_shader.binaryPtr);
	}
	if (_g_pixel_shader.binaryPtr) {
		free(_g_pixel_shader.binaryPtr);
	}
	CloseHandle(_fence_event);
}

BOOL	DX12Renderer::ResourceSetup() {
	HRESULT hr;
	//	頂点情報
	MyVertex vertices_array[] = {
		{ 0.0f, 1.0f, 0.0f },
		{ -1.0f,-1.0f, 0.0 },
		{ +1.0f,-1.0f, 0.0 },
	};
	// PipelineStateのための RootSignature の作成.
	D3D12_ROOT_SIGNATURE_DESC desc_root_signature;
	ZeroMemory(&desc_root_signature, sizeof(desc_root_signature));
	desc_root_signature.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
	D3D12_ROOT_PARAMETER rootParameters[1];	//	固定バッファがあるよ＜新規＞
	rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
	rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
	rootParameters[0].Descriptor.ShaderRegister = 0;
	rootParameters[0].Descriptor.RegisterSpace = 0;
	desc_root_signature.NumParameters = 1;
	desc_root_signature.pParameters = rootParameters;
	ComPtr<ID3DBlob> root_sig_blob, error_blob;
	hr = D3D12SerializeRootSignature(&desc_root_signature, D3D_ROOT_SIGNATURE_VERSION_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf());
	hr = _device->CreateRootSignature(0, root_sig_blob->GetBufferPointer(), root_sig_blob->GetBufferSize(), IID_PPV_ARGS(_root_signature.GetAddressOf()));
	if (FAILED(hr)) {
		return FALSE;
	}

	// コンパイル済みシェーダーの読み込み.
	FILE* fpVS = nullptr;
	fopen_s(&fpVS, "VertexShader.cso", "rb");
	if (!fpVS) {
		return FALSE;
	}
	fseek(fpVS, 0, SEEK_END);
	_g_vertex_shader.size = ftell(fpVS);
	rewind(fpVS);
	_g_vertex_shader.binaryPtr = malloc(_g_vertex_shader.size);
	fread(_g_vertex_shader.binaryPtr, 1, _g_vertex_shader.size, fpVS);
	fclose(fpVS);
	fpVS = nullptr;
	FILE* fpPS = nullptr;
	fopen_s(&fpPS, "PixelShader.cso", "rb");
	if (!fpPS) {
		return FALSE;
	}
	fseek(fpPS, 0, SEEK_END);
	_g_pixel_shader.size = ftell(fpPS);
	rewind(fpPS);
	_g_pixel_shader.binaryPtr = malloc(_g_pixel_shader.size);
	fread(_g_pixel_shader.binaryPtr, 1, _g_pixel_shader.size, fpPS);
	fclose(fpPS);
	fpPS = nullptr;

	// 今回のための頂点レイアウト.
	D3D12_INPUT_ELEMENT_DESC desc_input_elements[] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
	};
	// PipelineStateオブジェクトの作成.
	D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_pipeline_state;
	D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_state;
	ZeroMemory(&desc_pipeline_state, sizeof(desc_pipeline_state));
	desc_pipeline_state.VS.pShaderBytecode = _g_vertex_shader.binaryPtr;
	desc_pipeline_state.VS.BytecodeLength = _g_vertex_shader.size;
	desc_pipeline_state.PS.pShaderBytecode = _g_pixel_shader.binaryPtr;
	desc_pipeline_state.PS.BytecodeLength = _g_pixel_shader.size;
	desc_pipeline_state.SampleDesc.Count = 1;
	desc_pipeline_state.SampleMask = UINT_MAX;
	desc_pipeline_state.InputLayout.pInputElementDescs = desc_input_elements;
	desc_pipeline_state.InputLayout.NumElements = _countof(desc_input_elements);
	desc_pipeline_state.pRootSignature = _root_signature.Get();
	desc_pipeline_state.NumRenderTargets = 1;
	desc_pipeline_state.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc_pipeline_state.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
	desc_pipeline_state.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
	desc_pipeline_state.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
	desc_pipeline_state.RasterizerState.DepthClipEnable = TRUE;
	desc_pipeline_state.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
	for (int i = 0; i < _countof(desc_state.BlendState.RenderTarget); ++i) {
		desc_pipeline_state.BlendState.RenderTarget[i].BlendEnable = FALSE;
		desc_pipeline_state.BlendState.RenderTarget[i].SrcBlend = D3D12_BLEND_ONE;
		desc_pipeline_state.BlendState.RenderTarget[i].DestBlend = D3D12_BLEND_ZERO;
		desc_pipeline_state.BlendState.RenderTarget[i].BlendOp = D3D12_BLEND_OP_ADD;
		desc_pipeline_state.BlendState.RenderTarget[i].SrcBlendAlpha = D3D12_BLEND_ONE;
		desc_pipeline_state.BlendState.RenderTarget[i].DestBlendAlpha = D3D12_BLEND_ZERO;
		desc_pipeline_state.BlendState.RenderTarget[i].BlendOpAlpha = D3D12_BLEND_OP_ADD;
		desc_pipeline_state.BlendState.RenderTarget[i].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
	}
	desc_pipeline_state.DepthStencilState.DepthEnable = FALSE;

	hr = _device->CreateGraphicsPipelineState(&desc_pipeline_state, IID_PPV_ARGS(_pipeline_state.GetAddressOf()));
	if (FAILED(hr)) {
		return FALSE;
	}

	// 頂点データの作成.
	D3D12_HEAP_PROPERTIES heap_props;
	D3D12_RESOURCE_DESC   desc_resource;
	ZeroMemory(&heap_props, sizeof(heap_props));
	ZeroMemory(&desc_resource, sizeof(desc_resource));
	heap_props.Type = D3D12_HEAP_TYPE_UPLOAD;
	heap_props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	heap_props.CreationNodeMask = 0;
	heap_props.VisibleNodeMask = 0;
	desc_resource.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
	desc_resource.Width = sizeof(vertices_array);
	desc_resource.Height = 1;
	desc_resource.DepthOrArraySize = 1;
	desc_resource.MipLevels = 1;
	desc_resource.Format = DXGI_FORMAT_UNKNOWN;
	desc_resource.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
	desc_resource.SampleDesc.Count = 1;

	hr = _device->CreateCommittedResource(
		&heap_props,
		D3D12_HEAP_FLAG_NONE,
		&desc_resource,
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(_vertex_buffer.GetAddressOf())
	);
	if (FAILED(hr)) {
		return FALSE;
	}
	if (!_vertex_buffer) {
		return FALSE;
	}
	// 頂点データの書き込み
	void* mapped = nullptr;
	hr = _vertex_buffer->Map(0, nullptr, &mapped);
	if (FAILED(hr)) {
		return FALSE;
	}
	memcpy(mapped, vertices_array, sizeof(vertices_array));
	_vertex_buffer->Unmap(0, nullptr);
	_buffer_position.BufferLocation = _vertex_buffer->GetGPUVirtualAddress();
	_buffer_position.StrideInBytes = sizeof(MyVertex);
	_buffer_position.SizeInBytes = sizeof(vertices_array);

	// 定数バッファ Float4 分で確保.＜新規＞
	D3D12_HEAP_PROPERTIES heapProps;
	D3D12_RESOURCE_DESC   descResourceVB;
	ZeroMemory(&heapProps, sizeof(heapProps));
	ZeroMemory(&descResourceVB, sizeof(descResourceVB));
	heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
	heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	heapProps.CreationNodeMask = 0;
	heapProps.VisibleNodeMask = 0;
	descResourceVB.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
	descResourceVB.Width = sizeof(XMFLOAT4);
	descResourceVB.Height = 1;
	descResourceVB.DepthOrArraySize = 1;
	descResourceVB.MipLevels = 1;
	descResourceVB.Format = DXGI_FORMAT_UNKNOWN;
	descResourceVB.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
	descResourceVB.SampleDesc.Count = 1;

	hr = _device->CreateCommittedResource(
		&heapProps,
		D3D12_HEAP_FLAG_NONE,
		&descResourceVB,
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(_constant_buffer.GetAddressOf())
	);
	if (FAILED(hr)) {
		return FALSE;
	}

	hr = _constant_buffer->Map(0, nullptr, &mapped);
	if (FAILED(hr)) {
		return FALSE;
	}
	XMFLOAT4 mtx;
	XMVECTOR draw_color = XMVectorSet(1.0f, 1.0f, 0.0f, 1.0f);
	XMStoreFloat4(&mtx, draw_color);

	memcpy(mapped, &mtx, sizeof(mtx));
	_constant_buffer->Unmap(0, nullptr);

	return TRUE;
}

void DX12Renderer::SetResourceBarrier(ID3D12GraphicsCommandList* in_command_list, ID3D12Resource* in_resource, D3D12_RESOURCE_STATES in_before, D3D12_RESOURCE_STATES in_after)
{
	D3D12_RESOURCE_BARRIER desc_barrier;
	ZeroMemory(&desc_barrier, sizeof(desc_barrier));
	desc_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
	desc_barrier.Transition.pResource = in_resource;
	desc_barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
	desc_barrier.Transition.StateBefore = in_before;
	desc_barrier.Transition.StateAfter = in_after;
	in_command_list->ResourceBarrier(1, &desc_barrier);
}

void DX12Renderer::WaitForCommandQueue(ID3D12CommandQueue* in_command_queue) {
	static UINT64 frames = 0;
	_queue_fence->SetEventOnCompletion(frames, _fence_event);
	in_command_queue->Signal(_queue_fence.Get(), frames);
	WaitForSingleObject(_fence_event, INFINITE);
	frames++;
}

//  描画
HRESULT DX12Renderer::Render() {
	// まずはターゲットのクリア処理
	float clearColor[4] = { 1.0f,0.0f,0.0f,0.0f };
	D3D12_VIEWPORT viewport;
	viewport.TopLeftX	= 0; viewport.TopLeftY = 0;
	viewport.Width		= (FLOAT)_window_width;
	viewport.Height		= (FLOAT)_window_height;
	viewport.MinDepth	= 0;
	viewport.MaxDepth	= 1;

	//	定数バッファに色の設定＜新規＞
	XMVECTOR draw_color = XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f);	//青
	void* pCB;
	_constant_buffer->Map(0, nullptr, &pCB);
	if (pCB) {
		XMStoreFloat4((XMFLOAT4*)pCB, draw_color);
		_constant_buffer->Unmap(0, nullptr);
	}

	int target_index = _swap_chain->GetCurrentBackBufferIndex();
	SetResourceBarrier(
		_command_list.Get(),
		_render_target[target_index].Get(),
		D3D12_RESOURCE_STATE_PRESENT,
		D3D12_RESOURCE_STATE_RENDER_TARGET);

	// レンダーターゲットのクリア処理.
	_command_list->RSSetViewports(1, &viewport);
	_command_list->ClearRenderTargetView(_rtv_handle[target_index], clearColor, 0, nullptr);
	//-------------------------------------------
	//	
	D3D12_RECT rect = { 0, 0, _window_width, _window_height };
	_command_list->RSSetScissorRects(1, &rect);
	_command_list->OMSetRenderTargets(1, &_rtv_handle[target_index], TRUE, nullptr);

	// 頂点データをセット.
	_command_list->SetGraphicsRootSignature(_root_signature.Get());

	//	定数バッファ設定＜新規＞
	_command_list->SetGraphicsRootConstantBufferView(0, _constant_buffer->GetGPUVirtualAddress());

	//	シェーダー設定
	_command_list->SetPipelineState(_pipeline_state.Get());
	//
	_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	_command_list->IASetVertexBuffers(0, 1, &_buffer_position);
	_command_list->DrawInstanced(3, 1, 0, 0);
	//-------------------------------------------
	// Presentする前の準備.
	SetResourceBarrier(
		_command_list.Get(),
		_render_target[target_index].Get(),
		D3D12_RESOURCE_STATE_RENDER_TARGET,
		D3D12_RESOURCE_STATE_PRESENT);
	//-------------------------------------------
	_command_list->Close();

	// 上記で積んだコマンドを実行する.
	ID3D12CommandList* pCommandList = _command_list.Get();
	_command_queue->ExecuteCommandLists(1, &pCommandList);
	_swap_chain->Present(1, 0);

	WaitForCommandQueue(_command_queue.Get());
	_command_allocator->Reset();
	_command_list->Reset(_command_allocator.Get(), nullptr);
	return S_OK;
}
```

■Step3：実行
---
青くなりました。
![2018-12-10 (5).png](https://qiita-image-store.s3.amazonaws.com/0/122121/6bc4720c-8bf8-f4f8-8a68-a1cc772a98bc.png)