Constant Buffer: GPU 셰이더에 자주 바뀌는 데이터를 빠르고 효율적으로 전달하기 위한 구조체 기반 메모리 블록.
[Constant Buffer 사용 X]
deviceContext->VSSetShaderConstantF(0, world.m, 4); // world matrix
deviceContext->VSSetShaderConstantF(4, view.m, 4); // view matrix
deviceContext->VSSetShaderConstantF(8, projection.m, 4); // projection matrix
: 매 프레임마다 셰이더에 개별 데이터(행렬, float 등) 전달, API 호출이 많아지고, CPU와 GPU 사이의 통신 비용이 높아짐
[Constant Buffer 사용]
struct Transform
{
Matrix world;
Matrix view;
Matrix projection;
};
Transform transform;
transform.world = ...;
transform.view = ...;
transform.projection = ...;
context->UpdateSubresource(_constantBuffer.Get(), 0, nullptr, &transform, 0, 0);
context->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
: Transform 구조체 하나에 세 개의 행렬을 묶어서 한 번에 전송. CPU → GPU 전송을 최소화하면서도 셰이더는 자주 접근 가능
[Struct.h]
/* Constant Buffer, 16Byte 정렬 필요 */
struct TransformData
{
Vec3 offset; // offset 0, size = 3 * sizeof(float) = 12Byte;
float dummy; // offset 12, size = 1 * sizeof(float) = 4Byte;
};
[DefaultVertexShader.hlsl]
cbuffer TransformData : register(b0)
{
float4 offset;
}
// IA - VS - RS(VS_main에서 자동 처리) - PS - OM
// VS_main은 정점 단위로 실행, 위치 관련 처리
VS_OUTPUT VS_main(VS_INPUT input)
{
VS_OUTPUT output;
output.position = input.position + offset;
output.uv = input.uv;
return output;
}
[Game.h]
// Game.h
private:
/* Constant Buffer 생성 */
void CreateConstantBuffer();
private:
/* Constant Buffer */
TransformData _transformData;
ComPtr<ID3D11Buffer> _constantBuffer;
[Game.cpp]
// Game.cpp
void Game::Update()
{
_transformData.offset.x += 0.003f;
_transformData.offset.y += 0.003f;
D3D11_MAPPED_SUBRESOURCE subResource;
ZeroMemory(&subResource, sizeof(subResource));
// GPU의 Constant Buffer를 CPU에서 쓰기 위한 접근 요청
_deviceContext->Map(
_constantBuffer.Get(), // 업데이트할 Constant Buffer
0, // 서브리소스 인덱스 (일반적으로 0)
D3D11_MAP_WRITE_DISCARD, // 이전 내용은 버리고 새로 쓰기 (가장 일반적인 방식)
0, // Reserved (항상 0)
&subResource // 매핑 결과를 받을 구조체 (CPU가 접근 가능한 포인터 제공됨)
);
// CPU에서 GPU 버퍼에 데이터 복사 (_transformData → Constant Buffer에 업로드)
::memcpy(subResource.pData, &_transformData, sizeof(_transformData));
// 맵핑 해제 → GPU에서 읽을 수 있도록 다시 연결
_deviceContext->Unmap(_constantBuffer.Get(), 0);
}
void Game::Render()
{
/* 랜더링 시작 */
RenderBegin();
/* IA - VS - RS - PS - OM */
{
// IA (Input Assembler) : 정점의 정보 전달
// VS (Vertex Shader) : 정점의 위치/색상 등 가공
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());
// RS (Rasterizer) : 정점 → 픽셀로 삼각형 그리기
// PS (Pixel Shader) : 픽셀 단위 색상 처리
// OM (Output Merger) : 최종 픽셀을 렌더 타겟에 출력
}
/* 랜더링 끝, 화면에 출력 */
RenderEnd();
}
void Game::CreateConstantBuffer()
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
// CPU 쓰기 가능, GPU 읽기 가능 (매 프레임마다 CPU에서 업데이트 할 경우)
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.ByteWidth = sizeof(TransformData);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
// 설정된 desc를 기반으로 GPU에 Constant Buffer 생성 후 _constantBuffer에 저장
HRESULT hResult = _device->CreateBuffer(&desc, nullptr, _constantBuffer.GetAddressOf());
CHECK(hResult);
}
'게임개발 > Graphics' 카테고리의 다른 글
[Graphics] 행렬 (0) | 2025.04.21 |
---|---|
[Graphics] RasterizerState, SampleState, BlendState (0) | 2025.04.10 |
[Graphics] 텍스처와 UV (0) | 2025.04.07 |
[Graphics] 삼각형 띄우기 (0) | 2025.04.07 |
[Graphics] 초기화 (0) | 2025.04.06 |