feat(gpu): afegir suport SPIRV (Vulkan) per Linux/Windows
- Nou: shaders/sprite.vert|frag, postfx.vert|frag, ball.vert (GLSL) - Nou: cmake/spv_to_header.cmake — converteix .spv → uint8_t C header - CMakeLists.txt: bloc non-Apple troba glslc, compila GLSL → SPIRV en build-time i genera headers embeguts a build/generated_shaders/ - gpu_context.cpp: MSL|METALLIB en Apple, SPIRV en la resta - gpu_pipeline.cpp: createShaderSPIRV() + branques #ifdef __APPLE__ per sprite/ball/postfx pipelines - Corregeix crash a engine.cpp:821 (Windows/Linux) causat per pipelines null quan init() fallava en no trobar suport MSL Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,10 +6,12 @@
|
||||
bool GpuContext::init(SDL_Window* window) {
|
||||
window_ = window;
|
||||
|
||||
// Create GPU device — prefer Metal on macOS, Vulkan elsewhere
|
||||
SDL_GPUShaderFormat preferred = SDL_GPU_SHADERFORMAT_MSL
|
||||
| SDL_GPU_SHADERFORMAT_METALLIB
|
||||
| SDL_GPU_SHADERFORMAT_SPIRV;
|
||||
// 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;
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
#include <cstddef> // offsetof
|
||||
#include <cstring> // strlen
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Generated at build time by CMake + glslc (see cmake/spv_to_header.cmake)
|
||||
#include "sprite_vert_spv.h"
|
||||
#include "sprite_frag_spv.h"
|
||||
#include "postfx_vert_spv.h"
|
||||
#include "postfx_frag_spv.h"
|
||||
#include "ball_vert_spv.h"
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// MSL Shaders (Metal Shading Language, macOS)
|
||||
// ============================================================================
|
||||
@@ -197,18 +206,32 @@ bool GpuPipeline::init(SDL_GPUDevice* device,
|
||||
SDL_GPUTextureFormat target_format,
|
||||
SDL_GPUTextureFormat offscreen_format) {
|
||||
SDL_GPUShaderFormat supported = SDL_GetGPUShaderFormats(device);
|
||||
#ifdef __APPLE__
|
||||
if (!(supported & SDL_GPU_SHADERFORMAT_MSL)) {
|
||||
SDL_Log("GpuPipeline: device does not support MSL shaders (format mask=%u)", supported);
|
||||
SDL_Log("GpuPipeline: MSL not supported (format mask=%u)", supported);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (!(supported & SDL_GPU_SHADERFORMAT_SPIRV)) {
|
||||
SDL_Log("GpuPipeline: SPIRV not supported (format mask=%u)", supported);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Sprite pipeline
|
||||
// ----------------------------------------------------------------
|
||||
#ifdef __APPLE__
|
||||
SDL_GPUShader* sprite_vert = createShader(device, kSpriteVertMSL, "sprite_vs",
|
||||
SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* sprite_frag = createShader(device, kSpriteFragMSL, "sprite_fs",
|
||||
SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
|
||||
#else
|
||||
SDL_GPUShader* sprite_vert = createShaderSPIRV(device, ksprite_vert_spv, ksprite_vert_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* sprite_frag = createShaderSPIRV(device, ksprite_frag_spv, ksprite_frag_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
|
||||
#endif
|
||||
if (!sprite_vert || !sprite_frag) {
|
||||
SDL_Log("GpuPipeline: failed to create sprite shaders");
|
||||
if (sprite_vert) SDL_ReleaseGPUShader(device, sprite_vert);
|
||||
@@ -284,10 +307,17 @@ bool GpuPipeline::init(SDL_GPUDevice* device,
|
||||
// Fragment: sprite_fs (same texture+color blend as sprite pipeline)
|
||||
// Targets: offscreen (same as sprite pipeline)
|
||||
// ----------------------------------------------------------------
|
||||
#ifdef __APPLE__
|
||||
SDL_GPUShader* ball_vert = createShader(device, kBallInstancedVertMSL, "ball_instanced_vs",
|
||||
SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* ball_frag = createShader(device, kSpriteFragMSL, "sprite_fs",
|
||||
SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
|
||||
#else
|
||||
SDL_GPUShader* ball_vert = createShaderSPIRV(device, kball_vert_spv, kball_vert_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* ball_frag = createShaderSPIRV(device, ksprite_frag_spv, ksprite_frag_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
|
||||
#endif
|
||||
if (!ball_vert || !ball_frag) {
|
||||
SDL_Log("GpuPipeline: failed to create ball instanced shaders");
|
||||
if (ball_vert) SDL_ReleaseGPUShader(device, ball_vert);
|
||||
@@ -356,10 +386,17 @@ bool GpuPipeline::init(SDL_GPUDevice* device,
|
||||
// ----------------------------------------------------------------
|
||||
// PostFX pipeline
|
||||
// ----------------------------------------------------------------
|
||||
#ifdef __APPLE__
|
||||
SDL_GPUShader* postfx_vert = createShader(device, kPostFXVertMSL, "postfx_vs",
|
||||
SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* postfx_frag = createShader(device, kPostFXFragMSL, "postfx_fs",
|
||||
SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||
#else
|
||||
SDL_GPUShader* postfx_vert = createShaderSPIRV(device, kpostfx_vert_spv, kpostfx_vert_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||
SDL_GPUShader* postfx_frag = createShaderSPIRV(device, kpostfx_frag_spv, kpostfx_frag_spv_size,
|
||||
"main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||
#endif
|
||||
if (!postfx_vert || !postfx_frag) {
|
||||
SDL_Log("GpuPipeline: failed to create postfx shaders");
|
||||
if (postfx_vert) SDL_ReleaseGPUShader(device, postfx_vert);
|
||||
@@ -406,6 +443,30 @@ void GpuPipeline::destroy(SDL_GPUDevice* device) {
|
||||
if (postfx_pipeline_) { SDL_ReleaseGPUGraphicsPipeline(device, postfx_pipeline_); postfx_pipeline_ = nullptr; }
|
||||
}
|
||||
|
||||
SDL_GPUShader* GpuPipeline::createShaderSPIRV(SDL_GPUDevice* device,
|
||||
const uint8_t* spv_code,
|
||||
size_t spv_size,
|
||||
const char* entrypoint,
|
||||
SDL_GPUShaderStage stage,
|
||||
Uint32 num_samplers,
|
||||
Uint32 num_uniform_buffers,
|
||||
Uint32 num_storage_buffers) {
|
||||
SDL_GPUShaderCreateInfo info = {};
|
||||
info.code = spv_code;
|
||||
info.code_size = spv_size;
|
||||
info.entrypoint = entrypoint;
|
||||
info.format = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||
info.stage = stage;
|
||||
info.num_samplers = num_samplers;
|
||||
info.num_storage_textures = 0;
|
||||
info.num_storage_buffers = num_storage_buffers;
|
||||
info.num_uniform_buffers = num_uniform_buffers;
|
||||
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
||||
if (!shader)
|
||||
SDL_Log("GpuPipeline: SPIRV shader '%s' failed: %s", entrypoint, SDL_GetError());
|
||||
return shader;
|
||||
}
|
||||
|
||||
SDL_GPUShader* GpuPipeline::createShader(SDL_GPUDevice* device,
|
||||
const char* msl_source,
|
||||
const char* entrypoint,
|
||||
|
||||
@@ -48,6 +48,15 @@ private:
|
||||
Uint32 num_uniform_buffers,
|
||||
Uint32 num_storage_buffers = 0);
|
||||
|
||||
SDL_GPUShader* createShaderSPIRV(SDL_GPUDevice* device,
|
||||
const uint8_t* spv_code,
|
||||
size_t spv_size,
|
||||
const char* entrypoint,
|
||||
SDL_GPUShaderStage stage,
|
||||
Uint32 num_samplers,
|
||||
Uint32 num_uniform_buffers,
|
||||
Uint32 num_storage_buffers = 0);
|
||||
|
||||
SDL_GPUGraphicsPipeline* sprite_pipeline_ = nullptr;
|
||||
SDL_GPUGraphicsPipeline* ball_pipeline_ = nullptr;
|
||||
SDL_GPUGraphicsPipeline* postfx_pipeline_ = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user