#include "gpu_context.hpp" #include #include bool GpuContext::init(SDL_Window* window) { window_ = window; // Create GPU device: Metal on Apple, Vulkan elsewhere #ifdef __APPLE__ SDL_GPUShaderFormat preferred = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB; #else SDL_GPUShaderFormat preferred = SDL_GPU_SHADERFORMAT_SPIRV; #endif device_ = SDL_CreateGPUDevice(preferred, false, nullptr); if (!device_) { std::cerr << "GpuContext: SDL_CreateGPUDevice failed: " << SDL_GetError() << std::endl; return false; } std::cout << "GpuContext: driver = " << SDL_GetGPUDeviceDriver(device_) << std::endl; // Claim the window so the GPU device owns its swapchain if (!SDL_ClaimWindowForGPUDevice(device_, window_)) { std::cerr << "GpuContext: SDL_ClaimWindowForGPUDevice failed: " << SDL_GetError() << std::endl; SDL_DestroyGPUDevice(device_); device_ = nullptr; return false; } // Query swapchain format (Metal: typically B8G8R8A8_UNORM or R8G8B8A8_UNORM) swapchain_format_ = SDL_GetGPUSwapchainTextureFormat(device_, window_); std::cout << "GpuContext: swapchain format = " << static_cast(swapchain_format_) << std::endl; // Default: VSync ON SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC); return true; } void GpuContext::destroy() { if (device_) { SDL_WaitForGPUIdle(device_); SDL_ReleaseWindowFromGPUDevice(device_, window_); SDL_DestroyGPUDevice(device_); device_ = nullptr; } window_ = nullptr; } SDL_GPUCommandBuffer* GpuContext::acquireCommandBuffer() { SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_); if (!cmd) { SDL_Log("GpuContext: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); } return cmd; } SDL_GPUTexture* GpuContext::acquireSwapchainTexture(SDL_GPUCommandBuffer* cmd_buf, Uint32* out_w, Uint32* out_h) { SDL_GPUTexture* tex = nullptr; if (!SDL_AcquireGPUSwapchainTexture(cmd_buf, window_, &tex, out_w, out_h)) { SDL_Log("GpuContext: SDL_AcquireGPUSwapchainTexture failed: %s", SDL_GetError()); return nullptr; } // tex == nullptr when window is minimized — caller should skip rendering return tex; } void GpuContext::submit(SDL_GPUCommandBuffer* cmd_buf) { SDL_SubmitGPUCommandBuffer(cmd_buf); } bool GpuContext::setVSync(bool enabled) { SDL_GPUPresentMode mode = enabled ? SDL_GPU_PRESENTMODE_VSYNC : SDL_GPU_PRESENTMODE_IMMEDIATE; return SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, mode); }