Something went wrong. Try again.
art software for the rest of us
drawing paint image sdl art
Something went wrong. Try again.
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178#include "GPU.h"#include <SDL3/SDL_gpu.h>#include <SDL3/SDL_properties.h>#include <vector>#include <cstdlib>#include <string>
SDL_GPUDevice* GPU::device = nullptr;SDL_GPUTexture* GPU::swapchain = nullptr;SDL_Window* GPU::window = nullptr;std::stack<SDL_GPUCommandBuffer*> GPU::commandbuffers;SDL_GPURenderPass* GPU::renderPass = nullptr;SDL_GPUCopyPass* GPU::copyPass = nullptr;
std::string GPU::GetDetails() { SDL_PropertiesID deviceProps = SDL_GetGPUDeviceProperties(device); const char* name = SDL_GetStringProperty(deviceProps, SDL_PROP_GPU_DEVICE_NAME_STRING, "Unknown Device"); const char* driver = SDL_GetGPUDeviceDriver(device); bool debugMode = SDL_GetBooleanProperty(deviceProps, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, false); std::string details = std::string(name) + " (" + std::string(driver) + (debugMode ? " with validation layers" : "") + ")"; return details;}
bool GPU::Init(){ const char* debugEnv = std::getenv("GRADIEN_GPU_DEBUG"); bool debugMode = (debugEnv != nullptr && std::string(debugEnv) == "1");
SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, debugMode); SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, true);
// maximize compatibility SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, false); SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, false); SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, false); SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, false);
device = SDL_CreateGPUDeviceWithProperties(props); SDL_DestroyProperties(props);
if (!device) { return false; }
SDL_PropertiesID deviceProps = SDL_GetGPUDeviceProperties(device); const char* name = SDL_GetStringProperty(deviceProps, SDL_PROP_GPU_DEVICE_NAME_STRING, "Unknown Device"); std::printf(">>> %s\n", GetDetails().c_str()); // warn on nvidia if (strstr(name, "NVIDIA") != nullptr || strstr(name, "nvidia") != nullptr) { std::printf("Warning: Unsupported configuration. Stuttering may occur. Consider using a different GPU/driver if you encounter frame pacing issues. See: https://github.com/libsdl-org/SDL/issues/15069\n"); } return true;}
void GPU::Shutdown(){ SDL_ReleaseWindowFromGPUDevice(device, window); SDL_DestroyGPUDevice(device); device = nullptr;}
SDL_GPUDevice* GPU::GetDevice(){ return device;}
SDL_Window* GPU::GetWindow(){ return window;}
SDL_GPUCommandBuffer* GPU::GetCommandBuffer(){ return commandbuffers.top();}
SDL_GPURenderPass* GPU::GetRenderPass(){ return renderPass;}
SDL_GPUCopyPass* GPU::GetCopyPass(){ return copyPass;}
bool GPU::ClaimWindow(SDL_Window* window){ GPU::window = window; if (!SDL_ClaimWindowForGPUDevice(device, window)) { return false; } SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC); // TODO: option for mailbox/unlocked (unlocked mode requires better handling of scrollarea since too high and scrolling breaks) return true;}
bool GPU::AquirePushCommandBuffer(){ auto* commandbuffer = SDL_AcquireGPUCommandBuffer(device); if (commandbuffer) { GPU::commandbuffers.push(commandbuffer); } return (commandbuffer) != nullptr;}
bool GPU::WaitAquireSwapchainWithCommandBuffer(){ if (!(commandbuffers.size() > 0)) { if (!AquirePushCommandBuffer()) { return false; } } bool result = SDL_WaitAndAcquireGPUSwapchainTexture(commandbuffers.top(), window, &swapchain, nullptr, nullptr); if (!result) { return false; } if (!swapchain) { SDL_CancelGPUCommandBuffer(commandbuffers.top()); commandbuffers.pop(); return false; } return true;}
SDL_GPUTexture* GPU::GetSwapchain(){ return swapchain;}
SDL_GPUTextureFormat GPU::GetSwapchainFormat(){ return SDL_GetGPUSwapchainTextureFormat(device, window);}
void GPU::BeginRendering(std::list<SDL_GPUColorTargetInfo*> colorTargetInfos, SDL_GPUDepthStencilTargetInfo* depthStencilTargetInfo){ //create array std::vector<SDL_GPUColorTargetInfo> colorTargets; colorTargets.reserve(colorTargetInfos.size());
for (SDL_GPUColorTargetInfo* colorTargetInfo : colorTargetInfos) { colorTargets.push_back(*colorTargetInfo); } renderPass = SDL_BeginGPURenderPass(commandbuffers.top(), colorTargets.data(), colorTargets.size(), depthStencilTargetInfo);}
void GPU::EndRendering(){ SDL_EndGPURenderPass(renderPass); GPU::renderPass = nullptr;}
void GPU::BeginCopying(){ copyPass = SDL_BeginGPUCopyPass(commandbuffers.top());}
void GPU::EndCopying(){ SDL_EndGPUCopyPass(copyPass); GPU::copyPass = nullptr;}
void GPU::SubmitCommandsPopCommandBuffer(){ SDL_SubmitGPUCommandBuffer(commandbuffers.top()); GPU::commandbuffers.pop();}
void GPU::SubmitCommandsPopCommandBufferAwaitFence(){ SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(commandbuffers.top()); GPU::commandbuffers.pop(); SDL_WaitForGPUFences(device, true, &fence, 1); SDL_ReleaseGPUFence(device, fence);}