// IAEngine: 2D Game Engine by IA
// Copyright (C) 2025 IASoft (PVT) LTD (oss@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 .
#include
#include
namespace ia::iae
{
struct Geometry
{
INT32 IndexCount{};
RDC_DeviceLocalBuffer IndexBuffer;
RDC_DeviceLocalBuffer VertexBuffer;
};
} // namespace ia::iae
namespace ia::iae
{
SDL_GPUDevice *RDC_Device::s_handle{};
SDL_Window *RDC_Device::s_windowHandle{};
VOID RDC_Device::Initialize(IN SDL_Window *windowHandle, IN BOOL isDebugMode)
{
s_windowHandle = windowHandle;
SDL_PropertiesID deviceCreateProps = SDL_CreateProperties();
SDL_SetStringProperty(deviceCreateProps, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, nullptr);
SDL_SetBooleanProperty(deviceCreateProps, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, true);
SDL_SetBooleanProperty(deviceCreateProps, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, isDebugMode);
SDL_SetBooleanProperty(deviceCreateProps, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, false);
if (!(s_handle = SDL_CreateGPUDeviceWithProperties(deviceCreateProps)))
THROW_UNKNOWN("Failed to create the SDL GPU Device: ", SDL_GetError());
SDL_DestroyProperties(deviceCreateProps);
if (!SDL_ClaimWindowForGPUDevice(s_handle, windowHandle))
THROW_UNKNOWN("Failed to initialize SDL GPU for the window: ", SDL_GetError());
SDL_SetGPUSwapchainParameters(s_handle, windowHandle, SDL_GPU_SWAPCHAINCOMPOSITION_SDR,
SDL_GPU_PRESENTMODE_VSYNC);
}
VOID RDC_Device::Terminate()
{
WaitForIdle();
SDL_ReleaseWindowFromGPUDevice(s_handle, s_windowHandle);
SDL_DestroyGPUDevice(s_handle);
}
VOID RDC_Device::WaitForIdle()
{
SDL_WaitForGPUIdle(s_handle);
}
Handle RDC_Device::CreateGeometry(IN CONST Vector &vertices, IN CONST Vector &indices)
{
const auto geometry = new Geometry();
const auto vertexDataSize = static_cast(vertices.size() * sizeof(vertices[0]));
const auto indexDataSize = static_cast(indices.size() * sizeof(indices[0]));
std::construct_at(&geometry->VertexBuffer, RDC_Buffer::EType::VERTEX, vertexDataSize);
std::construct_at(&geometry->IndexBuffer, RDC_Buffer::EType::INDEX, indexDataSize);
const auto stagingBuffer = new RDC_StagingBuffer(ia_max(vertexDataSize, indexDataSize));
stagingBuffer->CopyFrom(vertices.data(), vertexDataSize);
geometry->VertexBuffer.CopyFrom(stagingBuffer, vertexDataSize);
stagingBuffer->CopyFrom(indices.data(), indexDataSize);
geometry->IndexBuffer.CopyFrom(stagingBuffer, indexDataSize);
delete stagingBuffer;
geometry->IndexCount = static_cast(indices.size());
return (Handle) geometry;
}
VOID RDC_Device::DestroyGeometry(IN Handle _geometry)
{
const auto geometry = (Geometry *) _geometry;
delete geometry;
}
VOID RDC_Device::BindGeometry(IN SDL_GPURenderPass* renderPass, IN Handle _geometry)
{
const auto geometry = (Geometry *) _geometry;
SDL_GPUBufferBinding bufferBindings[] = {{.buffer = geometry->VertexBuffer.GetHandle(), .offset = 0},
{.buffer = geometry->IndexBuffer.GetHandle(), .offset = 0}};
SDL_BindGPUVertexBuffers(renderPass, 0, &bufferBindings[0], 1);
SDL_BindGPUIndexBuffer(renderPass, &bufferBindings[1], SDL_GPU_INDEXELEMENTSIZE_32BIT);
}
SDL_GPUTextureFormat RDC_Device::GetSwapchainTextureFormat()
{
return SDL_GetGPUSwapchainTextureFormat(s_handle, s_windowHandle);
}
} // namespace ia::iae