이제 자주 사용할 StructureBuffer를 만들어보자
StructureBuffer는 정해진 구조체를 통해서 배열을 만들어 관리하는 버퍼를 통해 더 쉽게 작업 가능하다.
구현과 작동은 RawBuffer와 유사하다.
#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;
};
#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);
}
struct InputDesc
{
matrix input;
};
struct OutputDesc
{
matrix result;
};
StructuredBuffer<InputDesc> Input;
RWStructuredBuffer<OutputDesc> Output;
[numthreads(500, 1, 1)]
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()));
}
};
#include "pch.h"
#include "StructuredBufferDemo.h"
#include "RawBuffer.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));
_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(){}
