[D3D] TextureBuffer

vector·2025년 12월 5일

우선 float값의 데이터를 주고 받는게 아닌 텍스처를 주고 받는 형식의 TextureBuffer를 만들어보자

TextureBuffer

  • 텍스처는 2D로 픽셀단위이기에 정보가 많다.
    -> 여러개의 쓰레드가 텍스처를 처리할 수 있도록 분산하자
  • 코드는 RawBuffer와 크게 다르지 않다.(input, output)

TextureBuffer.h

#pragma once
class TextureBuffer
{
public:
	TextureBuffer(ComPtr<ID3D11Texture2D> src);
	~TextureBuffer();

public:
	void CreateBuffer();

private:
	void CreateSRV();
	void CreateOutput();
	void CreateUAV();
	void CreateResult();

public:
	uint32 GetWidth() { return _width; }
	uint32 GetHeight() { return _height; }
	uint32 GetArraySize() { return _arraySize; }

	ComPtr<ID3D11Texture2D> GetOutput() { return (ID3D11Texture2D*)_output.Get(); }
	ComPtr<ID3D11ShaderResourceView> GetOutputSRV() { return _outputSRV; }

public:
	ComPtr<ID3D11ShaderResourceView> GetSRV() { return _srv; }
	ComPtr<ID3D11UnorderedAccessView> GetUAV() { return _uav; }

private:
	ComPtr<ID3D11Texture2D> _input;
	ComPtr<ID3D11ShaderResourceView> _srv; // Input
	ComPtr<ID3D11Texture2D> _output;
	ComPtr<ID3D11UnorderedAccessView> _uav; // Output


	// 이미지와 관련된 여러가지 정보들
private:
	uint32 _width = 0;
	uint32 _height = 0;
	uint32 _arraySize = 0;
	DXGI_FORMAT _format;
	ComPtr<ID3D11ShaderResourceView> _outputSRV;
};

TextureBuffer.cpp

#include "pch.h"
#include "TextureBuffer.h"

TextureBuffer::TextureBuffer(ComPtr<ID3D11Texture2D> src)
{
	D3D11_TEXTURE2D_DESC srcDesc;
	src->GetDesc(&srcDesc);

	_width = srcDesc.Width;
	_height = srcDesc.Height;
	_arraySize = srcDesc.ArraySize;
	_format = srcDesc.Format;

	D3D11_TEXTURE2D_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.Width = _width;
	desc.Height = _height;
	desc.ArraySize = _arraySize;
	desc.Format = _format;
	desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	desc.MipLevels = 1;
	desc.SampleDesc.Count = 1;

	CHECK(DEVICE->CreateTexture2D(&desc, NULL, _input.GetAddressOf()));

	DC->CopyResource(_input.Get(), src.Get());

	CreateBuffer();
}

TextureBuffer::~TextureBuffer() { }

void TextureBuffer::CreateBuffer()
{
	CreateSRV();
	CreateOutput();
	CreateUAV();
	CreateResult();
}

void TextureBuffer::CreateSRV()
{
	D3D11_TEXTURE2D_DESC desc;
	_input->GetDesc(&desc);

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = desc.Format;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
	srvDesc.Texture2DArray.MipLevels = 1;
	srvDesc.Texture2DArray.ArraySize = _arraySize;

	CHECK(DEVICE->CreateShaderResourceView(_input.Get(), &srvDesc, _srv.GetAddressOf()));
}
void TextureBuffer::CreateOutput()
{
	D3D11_TEXTURE2D_DESC desc;
	ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
	desc.Width = _width;
	desc.Height = _height;
	desc.ArraySize = _arraySize;
	desc.Format = _format;
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	desc.MipLevels = 1;
	desc.SampleDesc.Count = 1;

	CHECK(DEVICE->CreateTexture2D(&desc, nullptr, _output.GetAddressOf()));
}

void TextureBuffer::CreateUAV()
{
	D3D11_TEXTURE2D_DESC desc;
	_output->GetDesc(&desc);

	D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
	ZeroMemory(&uavDesc, sizeof(D3D11_UNORDERED_ACCESS_VIEW_DESC));
	uavDesc.Format = DXGI_FORMAT_UNKNOWN;
	uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
	uavDesc.Texture2DArray.ArraySize = _arraySize;

	CHECK(DEVICE->CreateUnorderedAccessView(_output.Get(), &uavDesc, _uav.GetAddressOf()));
}

void TextureBuffer::CreateResult()
{
	D3D11_TEXTURE2D_DESC desc;
	_output->GetDesc(&desc);

	D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
	ZeroMemory(&srvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	srvDesc.Format = desc.Format;
	srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
	srvDesc.Texture2DArray.MipLevels = 1;
	srvDesc.Texture2DArray.ArraySize = _arraySize;

	CHECK(DEVICE->CreateShaderResourceView(_output.Get(), &srvDesc, _outputSRV.GetAddressOf()));
}

Texture

  • 텍스처를 조작할 때 사용할 수 있도록 텍스처 클래스에서 헬퍼함수와 SetSRV()함수 추가

Texture.h

class Texture : public ResourceBase
{
public:	
	ComPtr<ID3D11Texture2D> GetTexture2d();
	void SetSRV(ComPtr<ID3D11ShaderResourceView> srv) { _shaderResourveView = srv; }

}

Texture.cpp

ComPtr<ID3D11Texture2D> Texture::GetTexture2d()
{
	ComPtr<ID3D11Texture2D> texture;
	_shaderResourveView->GetResource((ID3D11Resource**)texture.GetAddressOf());

	return texture;
}

26.TextureBufferDemo.fx

  • 2D Texture를 다루기에 쓰레드를 2차원인 (32, 32, 1)로 설정
  • 고유한 아이디에 해당하는 정보를 가져와서 조작할 수 있도록 쉐이더 코드 수정
Texture2DArray<float4> Input;
RWTexture2DArray<float4> Output;

[numthreads(32, 32, 1)] // 쓰레드의 개수를 의미 ( 10 x 8 x 3 = 240개)
void CS(uint3 id : SV_DispatchThreadID)
{
    float4 color = Input.Load(int4(id, 0)); // 쓰레드 넘버링값에 해당하는 정보 추출

    //Output[id] = color;
    Output[id] = 1.0f - color;                              // 반전
    //Output[id] = (color.r + color.g + color.b) / 3.0f;    // 회색풍
}

technique11 T0
{
    pass P0
    {
        SetVertexShader(NULL);
        SetPixelShader(NULL);
        SetComputeShader(CompileShader(cs_5_0, CS()));
    }
};

TextureBufferDemo

  • 이미지 파일이 쓰레드 개수로 딱 떨어지지 않고 훨씬 클 것이기에 여러 단위로 만들어서 작업
  • 작업을 진행하다보면 남게 되는 데이터도 하나로 처리해주기 위해서 (witdh or height + 쓰레드 수 -1) / 쓰레드 수로 처리해주자
  • 예시로 width가 64라고 가정하면, 64 / 32 = 2로 잘 나눠 떨어지는데 만약 width가 63일 경우 63 / 32 = 1.9.. 로 1이 나오고 나머지가 잘리는 현상이 나온데 이럴 때 32가 아닌 32을 더해서 1.9를 2로 만들어주는 방식이다.
#include "pch.h"
#include "TextureBufferDemo.h"
#include "GeometryHelper.h"
#include "Camera.h"
#include "GameObject.h"
#include "CameraScript.h"
#include "MeshRenderer.h"
#include "Mesh.h"
#include "Material.h"
#include "Model.h"
#include "ModelRenderer.h"
#include "ModelAnimator.h"
#include "Mesh.h"
#include "Transform.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "Light.h"
#include "TextureBuffer.h"

void TextureBufferDemo::Init()
{
	//RESOURCES->Init();

	auto newSrv = MakeComputeShaderTexture();

	_shader = make_shared<Shader>(L"23.RenderDemo.fx");

	// Camera
	{
		auto camera = make_shared<GameObject>();
		camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -5.f });
		camera->AddComponent(make_shared<Camera>());
		camera->AddComponent(make_shared<CameraScript>());
		CUR_SCENE->Add(camera);
	}

	// Light
	{
		auto light = make_shared<GameObject>();
		light->AddComponent(make_shared<Light>());
		LightDesc lightDesc;
		lightDesc.ambient = Vec4(0.4f);
		lightDesc.diffuse = Vec4(1.f);
		lightDesc.specular = Vec4(0.1f);
		lightDesc.direction = Vec3(1.f, 0.f, 1.f);
		light->GetLight()->SetLightDesc(lightDesc);
		CUR_SCENE->Add(light);
	}


	// Mesh
	// Material
	{
		shared_ptr<Material> material = make_shared<Material>();
		material->SetShader(_shader);
		auto texture = make_shared<Texture>();
		texture->SetSRV(newSrv);
		material->SetDiffuseMap(texture);
		MaterialDesc& desc = material->GetMaterialDesc();
		desc.ambient = Vec4(1.f);
		desc.diffuse = Vec4(1.f);
		desc.specular = Vec4(1.f);
		RESOURCES->Add(L"Veigar", material);
	}

	for (int32 i = 0; i < 100; i++)
	{
		auto obj = make_shared<GameObject>();
		obj->GetOrAddTransform()->SetLocalPosition(Vec3(rand() % 100, 0, rand() % 100));
		obj->AddComponent(make_shared<MeshRenderer>());
		{
			obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
		}
		{
			auto mesh = RESOURCES->Get<Mesh>(L"Sphere");
			obj->GetMeshRenderer()->SetMesh(mesh);
			obj->GetMeshRenderer()->SetPass(0);
		}

		CUR_SCENE->Add(obj);
	}

	//RENDER->Init(_shader);
}

void TextureBufferDemo::Update()
{

}

void TextureBufferDemo::Render()
{

}

Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> TextureBufferDemo::MakeComputeShaderTexture()
{
	auto shader = make_shared<Shader>(L"26.TextureBufferDemo.fx");

	auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
	shared_ptr<TextureBuffer> textureBuffer = make_shared<TextureBuffer>(texture->GetTexture2d());

	shader->GetSRV("Input")->SetResource(textureBuffer->GetSRV().Get());
	shader->GetUAV("Output")->SetUnorderedAccessView(textureBuffer->GetUAV().Get());

	uint32 width = textureBuffer->GetWidth();
	uint32 height = textureBuffer->GetHeight();
	uint32 arraySize = textureBuffer->GetArraySize();

	uint32 x = max(1, (width + 31) / 32);
	uint32 y = max(1, (height + 31) / 32);
	shader->Dispatch(0, 0, x, y, arraySize);

	return textureBuffer->GetOutputSRV();
}

결과

  • 쉐이더에서 Color를 반전으로 해둔 상태의 결과값

참고 강의

https://www.inflearn.com/courses/lecture?courseId=329791&tab=curriculum&type=LECTURE&unitId=161165&subtitleLanguage=ko

profile
게임 클라이언트 프로그래머 준비중 (공부 및 기록용)

0개의 댓글