๐ Constant Buffer(CBV)
Constant Buffer๋? ( ์์ ๋ฒํผ )
Root Signature์ ํ๋์ ์๋ช
๋ฐฉ๋ฒ์ผ๋ก, ์๋์ ์์ ๋ ์์๋ฅผ ๋ค๋ฃฐ ๋์ ๋ฒํผ๋ฅผ ๋ณด์ฌ์ค๋ค.
root constant๋ก ๊ฐ์ ์์๋ฅผ ๋ค๋ฃฌ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
Root Signatrue๋ฅผ ํตํด์ ๋ ์ง์คํฐ ๊ณต๊ฐ์ ํ ๋นํ๋ ๊ฒ๊ณผ ๊ทธ ๊ณต๊ฐ์ CmdList์ ์ถ๊ฐํ๋ ๊ฒ์ ๋ณ๊ฐ์ ๋จ๊ณ๋ก ๊ตฌ์ฑ๋๋ค.
/*---------------------------------------
CmdList์ ConstantBuffer๋ฅผ ์ถ๊ฐํ๋ ๋ฉ์๋
----------------------------------------*/
pCmdList->SetComputeRoot32BitConstant(0,seed);
// 0 is the parameter index, seed is used by the shaders
/*------------------------------------------------------------
Root Signature์ Init : Root Signature์ ๋๊ฐ์ CBV๋ฅผ ์ถ๊ฐํ ์ฝ๋
-------------------------------------------------------------*/
CD3DX12_ROOT_PARAMETER param[2];
param[0].InitAsConstantBufferView(0); // 0๋ฒ - > b0 - > CBV
param[1].InitAsConstantBufferView(1); // 1๋ฒ - > b1 -> CBV
D3D12_ROOT_SIGNATURE_DESC sigDesc =CD3DX12_ROOT_SIGNATURE_DESC(2, param);
/*-----------------------------------------------------------
CommandQueue์ RenderBegin์ Root Signature์ ์๋ช
์ ํด์ฃผ๋ ๋ฉ์๋
-----------------------------------------------------------*/
_cmdList->SetGraphicsRootSignature(ROOT_SIGNATURE.Get());
๐ Device์ CmdList ์์ ์ ์ฐจ์ด
์์ ์์๋ฅผ ์ ๋ณผ ์ ์๋ ๋ถ๋ถ์ด Mesh.cpp ๋ถ๋ถ์ด๋ค.
void Mesh::Init(vector<Vertex>& vec)
{
_vertexCount = static_cast<uint32>(vec.size());
uint32 bufferSize = _vertexCount * sizeof(Vertex);
D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);
DEVICE->CreateCommittedResource(
&heapProperty,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&_vertexBuffer));
// Copy the triangle data to the vertex buffer.
void* vertexDataBuffer = nullptr;
CD3DX12_RANGE readRange(0, 0); // We do not intend to read from this resource on the CPU.
_vertexBuffer->Map(0, &readRange, &vertexDataBuffer);
::memcpy(vertexDataBuffer, &vec[0], bufferSize);
_vertexBuffer->Unmap(0, nullptr);
// Initialize the vertex buffer view.
_vertexBufferView.BufferLocation = _vertexBuffer->GetGPUVirtualAddress();
_vertexBufferView.StrideInBytes = sizeof(Vertex); // ์ ์ 1๊ฐ ํฌ๊ธฐ
_vertexBufferView.SizeInBytes = bufferSize; // ๋ฒํผ์ ํฌ๊ธฐ
}
void Mesh::Render()
{
CMD_LIST->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CMD_LIST->IASetVertexBuffers(0, 1, &_vertexBufferView); // Slot: (0~15)
CMD_LIST->DrawInstanced(_vertexCount, 1, 0, 0);
}
์์ ์ฝ๋๊ฐ ํ๋ ์ผ์ ๋ง๋ก ํ๋ฉด,
1) Init ๋ฉ์๋๋ฅผ ํตํด์ CPU์์ GPU์ ๋ฉ๋ชจ๋ฆฌ์ ๋ฒํผ๋ฅผ ์์ฑํ๋ค.
2) ์์ฑ๋ ๋ฒํผ์๋ ๋ฆฌ์์ค์ ๋ํ ์ค๋ช
๋ค์ด ์์ฑ๋์ด ์์ ๊ฒ์ด๋ค.
3) ์ด๋ ๊ฒ ์์ฑ๋ ๋ฒํผ์ ๋ํ ์ฃผ์๋ฅผ GPU์ ๋ ์ง์คํฐ์ ์ ์ฅ์ ํด์ผํ๋ค.
4) ๊ทธ๋ฌ๊ธฐ ์ํด์ Render ๋ฉ์๋๋ฅผ ํตํด CmdList์ ์ถ๊ฐ๋ฅผ ํ๋ค. ( ํ์ฌ ์์
์ ์คํ X )
5) ๊ทธ ํ CmdList์ ์ถ๊ฐ๋ ์์
๋ค์ด ์คํ๋ ๋, GPU์ ๋ฒํผ์ ๋ํ ๋๋ ์ฃผ์ ๊ฐ์ ๋ ์ง์คํฐ์ ์ ์ฅ์ ํ๊ฒ ๋๊ณ , Resource์ ๊ฐ์ ์ฐธ์กฐ ํ ์ ์๊ฒ๋๋ค.
์ฃผ์์ฌํญ : ์ด๋ ๋ฏ Device๋ฅผ ํตํด์ ์์ ์ ํ๋ ๊ฒ์ ์ฆ์ ์ผ์ด๋๊ณ , CmdList๋ฅผ ์ด์ฉ์ ํ๋ฉด ํ์ ์์ ์ด ๋ฐ์ํ๋ค. ์ด ์ํฉ์์ ์ฃผ์ํ ์ ์ด ์๋๋ฐ, ๊ทธ๊ฒ์ Device๋ฅผ ํตํด์ ๊ฐ์ ๋ฒํผ๋ฅผ ๋๋ฒ ์ด๊ธฐํ๋ฅผ ํ๊ฒ ๋๋ฉด, CmdList ์์ ์ ํ๊ฒ ๋ ๋ ์ด๋ฅผ ๋ฐ์ํ์ง ๋ชปํ๋ค๋ ์ ์ ์ฃผ์ํด์ผ ํ๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ค.
๋จ์ํ GPU ๋ฉ๋ชจ๋ฆฌ์ ๋ฐฐ์ด๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ก ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํ์ฌ ๊ฐ ์ธ๋ฑ์ค์ ๊ฐ์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
ConstantBuffer ํค๋
#pragma once
class ConstantBuffer
{
public:
ConstantBuffer();
~ConstantBuffer();
void Init(uint32 size, uint32 count);
void Clear();
void PushData(int32 rootParamIndex, void* buffer, uint32 size);
D3D12_GPU_VIRTUAL_ADDRESS GetGpuVirtualAddress(uint32 index);
private:
void CreateBuffer();
private:
ComPtr<ID3D12Resource> _cbvBuffer;
BYTE* _mappedBuffer = nullptr;
uint32 _elementSize = 0;
uint32 _elementCount = 0;
uint32 _currentIndex = 0;
};
ConstantBuffer cpp
#include "pch.h"
#include "ConstantBuffer.h"
#include "Engine.h"
ConstantBuffer::ConstantBuffer()
{
}
ConstantBuffer::~ConstantBuffer()
{
if (_cbvBuffer)
{
if (_cbvBuffer != nullptr)
_cbvBuffer->Unmap(0, nullptr);
_cbvBuffer = nullptr;
}
}
void ConstantBuffer::Init(uint32 size, uint32 count)
{
// ์์ ๋ฒํผ๋ 256 ๋ฐ์ดํธ ๋ฐฐ์๋ก ๋ง๋ค์ด์ผ ํ๋ค
// 0 256 512 768
_elementSize = (size + 255) & ~255;
_elementCount = count;
CreateBuffer();
}
void ConstantBuffer::CreateBuffer()
{
uint32 bufferSize = _elementSize * _elementCount;
D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);
DEVICE->CreateCommittedResource(
&heapProperty,
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&_cbvBuffer));
_cbvBuffer->Map(0, nullptr, reinterpret_cast<void**>(&_mappedBuffer));
}
void ConstantBuffer::Clear()
{
_currentIndex = 0;
}
void ConstantBuffer::PushData(int32 rootParamIndex, void* buffer, uint32 size)
{
assert(_currentIndex < _elementSize);
::memcpy(&_mappedBuffer[_currentIndex * _elementSize], buffer, size);
D3D12_GPU_VIRTUAL_ADDRESS address = GetGpuVirtualAddress(_currentIndex);
CMD_LIST->SetGraphicsRootConstantBufferView(rootParamIndex, address);
_currentIndex++;
}
D3D12_GPU_VIRTUAL_ADDRESS ConstantBuffer::GetGpuVirtualAddress(uint32 index)
{
D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = _cbvBuffer->GetGPUVirtualAddress();
objCBAddress += index * _elementSize;
return objCBAddress;
}
์์ ์์ค์ฝ๋๋ฅผ ํตํด์ ConstantBuffer์ ๊ฐ์ ์ฌ๋ฌ๊ฐ ์ ์ฅ ํ ์ ์๋ ๋ฐฐ์ด์ ๋ง๋ค๊ฒ ๋๋ค.
์ด ๋ฐฐ์ด์ GPU ๋ฉ๋ชจ๋ฆฌ์ ์์ผ๋ฉด์ ํ์ฌ์ index๊ฐ์ ์ถ์ ํ๋ฉด์ ํด๋น ๊ฐ์ buffer๊ฐ์ GPU์ ๋ ์ง์คํฐ๋ก ์ฎ๊ฒจ์ฃผ๋ ์ญํ ์ ํ๋ค.
ํฌ์ธํฐ์ฒ๋ผ ๋ฆฌ์์ค๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์๋ ๊ฒ
๋ ์ง์คํฐ์ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ด๊ฒ ๋ค ํ๋ ๊ณ์ฝ์์ ๊ฐ์ ๊ฒ
Root Signature๋ ๋ฌดํ์ ์ฌ์ด์ฆ๋ฅผ ๋๋ฆด ์ ์๋ ๊ทธ๋ฌํ ๊ณต๊ฐ์ด ์๋๋ค.
๋ฐ๋ผ์ ์ด ๊ณต๊ฐ์ ๋ ๋ํ์ ์ฌ์ฉํ๊ธฐ ์ํด์ table์ ์ด์ฉ ํ ๋ฟ ์๋๋ผ,
์ด ๊ณต๊ฐ์ ๋๋ฌด ๋ง์ ๋ด์ฉ์ ์์ฑ ํ๊ฒ๋๋ฉด ์ฑ๋ฅ์ด ๋จ์ด์ง๊ธฐ ๋๋ฌธ์ table์ ์ด์ฉํ๋ค.