Files
IAEngine/Src/IAEngine/imp/cpp/Rendering/GPUBuffer.cpp
Isuru Samarathunga ece65b18da Restructure
2025-09-20 10:03:52 +05:30

131 lines
4.3 KiB
C++

// IAEngine: 2D Game Engine by IA
// Copyright (C) 2025 IAS (ias@iasoft.dev)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <IAEngine/Rendering/GPUBuffer.hpp>
#include <SDL3/SDL_gpu.h>
namespace ia::iae
{
EXTERN SDL_GPUDevice *g_gpuDevice;
UINT32 g_stagingBufferSize = 4096;
SDL_GPUTransferBuffer *g_stagingBuffer{};
RefPtr<GPUBuffer> GPUBuffer::Create(IN Usage usage, IN PCVOID data, IN UINT32 dataSize)
{
const auto res = MakeRefPtr<GPUBuffer>();
SDL_GPUBufferUsageFlags _usage{};
switch (usage)
{
case Usage::VERTEX:
_usage = SDL_GPU_BUFFERUSAGE_VERTEX;
break;
case Usage::INDEX:
_usage = SDL_GPU_BUFFERUSAGE_INDEX;
break;
case Usage::STORAGE:
_usage = SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ;
break;
default:
THROW_INVALID_DATA("Invalid usage value for GPUBuffer");
break;
}
res->m_usage = usage;
SDL_GPUBufferCreateInfo createInfo{.usage = _usage, .size = dataSize};
SDL_GPUBuffer *handle{};
if (!(handle = SDL_CreateGPUBuffer(g_gpuDevice, &createInfo)))
{
IAE_LOG_ERROR("Couldn't create a SDL3 GPU Buffer: ", SDL_GetError());
return nullptr;
}
if (data && dataSize)
{
if (!EnsureStagingBufferSize((UINT32) dataSize))
return nullptr;
res->m_size = dataSize;
const auto mappedPtr = SDL_MapGPUTransferBuffer(g_gpuDevice, g_stagingBuffer, false);
memcpy(mappedPtr, data, dataSize);
SDL_UnmapGPUTransferBuffer(g_gpuDevice, g_stagingBuffer);
const auto cmdBuffer = SDL_AcquireGPUCommandBuffer(g_gpuDevice);
const auto copyPass = SDL_BeginGPUCopyPass(cmdBuffer);
SDL_GPUTransferBufferLocation src{.transfer_buffer = g_stagingBuffer, .offset = 0};
SDL_GPUBufferRegion dst{.buffer = handle, .offset = 0, .size = dataSize};
SDL_UploadToGPUBuffer(copyPass, &src, &dst, false);
SDL_EndGPUCopyPass(copyPass);
SDL_SubmitGPUCommandBuffer(cmdBuffer);
SDL_WaitForGPUIdle(g_gpuDevice);
}
res->m_handle = (Handle) handle;
return res;
}
GPUBuffer::~GPUBuffer()
{
if (m_handle)
SDL_ReleaseGPUBuffer(g_gpuDevice, (SDL_GPUBuffer *) m_handle);
}
BOOL GPUBuffer::InitializeStagingBuffer()
{
SDL_GPUTransferBufferCreateInfo createInfo{.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
.size = g_stagingBufferSize};
if (!(g_stagingBuffer = SDL_CreateGPUTransferBuffer(g_gpuDevice, &createInfo)))
{
IAE_LOG_ERROR("Couldn't create a SDL3 GPU Staging Buffer: ", SDL_GetError());
return false;
}
return true;
}
VOID GPUBuffer::TerminateStagingBuffer()
{
if (!g_stagingBuffer)
return;
SDL_ReleaseGPUTransferBuffer(g_gpuDevice, g_stagingBuffer);
}
BOOL GPUBuffer::EnsureStagingBufferSize(IN UINT32 size)
{
if (!g_stagingBuffer)
return false;
if (size <= g_stagingBufferSize)
return true;
SDL_ReleaseGPUTransferBuffer(g_gpuDevice, g_stagingBuffer);
SDL_GPUTransferBufferCreateInfo createInfo{.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
.size = (g_stagingBufferSize = size)};
if (!(g_stagingBuffer = SDL_CreateGPUTransferBuffer(g_gpuDevice, &createInfo)))
{
IAE_LOG_ERROR("Couldn't create a SDL3 GPU Staging Buffer: ", SDL_GetError());
return false;
}
return true;
}
} // namespace ia::iae