이제 Structure 버퍼를 만들어서 사용해보자
Structure Buffer는 정해진 구조체를 통해 배열을 만들어서 관리하는 버퍼를 통해 더 쉽게 이 작업을 해줄 수 있다.
구현과 작동 자체는 RawBuffer와 유사하다.
우선 Buffer 클래스를 만들어주자.
StructuredBuffer.h
#pragma once
class StructuredBuffer
{
public:
StructuredBuffer(void* inputData, uint32 inputStride, uint32 inputCount, uint32 outputStride = 0, uint32 outputCount = 0);
~StructuredBuffer();
public:
void CreateBuffer();
private:
void CreateInput();
void CreateSRV();
void CreateOutput();
void CreateUAV();
void CreateResult();
public:
//데이터개수 * 데이터크기
uint32 GetInputByteWidth() { return _inputStride * _inputCount; }
//데이터개수 * 데이터크기
uint32 GetOutputByteWidth() { return _outputStride * _outputCount; }
void CopyToInput(void* data);
void CopyFromOutput(void* data);
public:
ComPtr<ID3D11ShaderResourceView> GetSRV() { return _srv; }
ComPtr<ID3D11UnorderedAccessView> GetUAV() { return _uav; }
private:
ComPtr<ID3D11Buffer> _input;
ComPtr<ID3D11ShaderResourceView> _srv; // Input
ComPtr<ID3D11Buffer> _output;
ComPtr<ID3D11UnorderedAccessView> _uav; // Output
ComPtr<ID3D11Buffer> _result;
private:
void* _inputData;
uint32 _inputStride = 0;
uint32 _inputCount = 0;
uint32 _outputStride = 0;
uint32 _outputCount = 0;
};
StructuredBuffer.cpp
#include "pch.h"
#include "StructuredBuffer.h"
StructuredBuffer::StructuredBuffer(void* inputData, uint32 inputStride, uint32 inputCount, uint32 outputStride, uint32 outputCount)
: _inputData(inputData), _inputStride(inputStride), _inputCount(inputCount), _outputStride(outputStride), _outputCount(outputCount)
{
if (outputStride == 0 || outputCount == 0)
{
_outputStride = inputStride;
_outputCount = inputCount;
}
CreateBuffer();
}
StructuredBuffer::~StructuredBuffer()
{
}
void StructuredBuffer::CreateBuffer()
{
CreateInput();
CreateSRV();
CreateOutput();
CreateUAV();
CreateResult();
}
void StructuredBuffer::CreateInput()
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.ByteWidth = GetInputByteWidth();
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; //구조체에 맞게
desc.StructureByteStride = _inputStride;
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = _inputData;
if (_inputData != nullptr)
CHECK(DEVICE->CreateBuffer(&desc, &subResource, _input.GetAddressOf()));
else
CHECK(DEVICE->CreateBuffer(&desc, nullptr, _input.GetAddressOf()));
}
void StructuredBuffer::CreateSRV()
{
D3D11_BUFFER_DESC desc;
_input->GetDesc(&desc);
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.NumElements = _inputCount;
CHECK(DEVICE->CreateShaderResourceView(_input.Get(), &srvDesc, _srv.GetAddressOf()));
}
void StructuredBuffer::CreateOutput()
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.ByteWidth = GetOutputByteWidth();
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
desc.StructureByteStride = _outputStride;
CHECK(DEVICE->CreateBuffer(&desc, nullptr, _output.GetAddressOf()));
}
void StructuredBuffer::CreateUAV()
{
D3D11_BUFFER_DESC desc;
_output->GetDesc(&desc);
D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
ZeroMemory(&uavDesc, sizeof(uavDesc));
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.NumElements = _outputCount;
CHECK(DEVICE->CreateUnorderedAccessView(_output.Get(), &uavDesc, _uav.GetAddressOf()));
}
void StructuredBuffer::CreateResult()
{
D3D11_BUFFER_DESC desc;
_output->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.BindFlags = 0;
desc.MiscFlags = 0;
CHECK(DEVICE->CreateBuffer(&desc, NULL, _result.GetAddressOf()));
}
void StructuredBuffer::CopyToInput(void* data)
{
D3D11_MAPPED_SUBRESOURCE subResource;
DC->Map(_input.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
{
memcpy(subResource.pData, data, GetInputByteWidth());
}
DC->Unmap(_input.Get(), 0);
}
void StructuredBuffer::CopyFromOutput(void* data)
{
DC->CopyResource(_result.Get(), _output.Get());
D3D11_MAPPED_SUBRESOURCE subResource;
DC->Map(_result.Get(), 0, D3D11_MAP_READ, 0, &subResource);
{
memcpy(data, subResource.pData, GetOutputByteWidth());
}
DC->Unmap(_result.Get(), 0);
}
쉐이더쪽 코드는 구조체를 통해 입출력 구조를 정해주고 이를 버퍼 변수로 지정해주고 출력에는 RW를 붙여서 Read + Write가 가능하도록 해주자. 그리고 지금은 입력값에 행렬을 받는데 이 행렬에 간단한 연산만 해서 반환하는 식으로 동작하게 해주자
StructuredBufferDemo.fx
struct InputDesc
{
matrix input;
};
struct OutputDesc
{
matrix result;
};
//하나의 배열로 보면된다
StructuredBuffer<InputDesc> Input;
RWStructuredBuffer<OutputDesc> Output;
//thread 개수 x*y*z 총합
[numthreads(500,1,1)] //x만 500개 행렬값
void CS(uint id : SV_GroupIndex)
{
matrix result = Input[id].input * 2;
Output[id].result = result;
}
technique11 T0
{
Pass P0
{
SetVertexShader(NULL);
SetPixelShader(NULL);
//컴퓨트 쉐이더 세팅
SetComputeShader(CompileShader(cs_5_0, CS()));
}
};
이에 맞게 항등 행렬인 Matrix vector를 선언하고 이를 버퍼를 통해 작업할 수 있도록 메인 코드를 만들어주자
StructuredBufferDemo.fx
#include "pch.h"
#include "StructuredBufferDemo.h"
#include "StructuredBuffer.h"
void StructuredBufferDemo::Init()
{
_shader = make_shared<Shader>(L"27. StructuredBufferDemo.fx");
vector<Matrix> inputs(500, Matrix::Identity);
auto buffer = make_shared<StructuredBuffer>(inputs.data(), sizeof(Matrix), 500, sizeof(Matrix), 500);
_shader->GetSRV("Input")->SetResource(buffer->GetSRV().Get());
_shader->GetUAV("Output")->SetUnorderedAccessView(buffer->GetUAV().Get());
_shader->Dispatch(0, 0, 1, 1, 1);
vector<Matrix> outputs(500);
buffer->CopyFromOutput(outputs.data());
}
void StructuredBufferDemo::Update()
{
}
void StructuredBufferDemo::Render()
{
}
이렇게 해주고 코드끝부분에 Break Point를 잡고 실행시켜보면
이렇게 행렬 x부분에 2가 곱해져서 반환되는 것을 볼 수 있다. 이런식으로 RawBuffer를 활용하는 방법보다
인스턴싱에서 매트릭스나 본 행렬 정보와 같은 정해진 구조를 여러개 넣어주는 경우가 많기 때문에 Sturctured Buffer
를 활용하는 방법이 좋을 것이다.
'게임공부 > Directx11' 카테고리의 다른 글
[Directx11][C++][3D]26. ViewPort 이론 (0) | 2024.10.03 |
---|---|
[Directx11][C++][3D]25. RenderManager 분할 (3) | 2024.10.03 |
[Directx11][C++][3D]23. TextureBuffer (3) | 2024.10.02 |
[Directx11][C++][3D]22. RawBuffer (1) | 2024.09.30 |
[Directx11][C++][3D]21. Quaternion (0) | 2024.09.29 |