#pragma once #include // ============================================================================ // PostFXUniforms — pushed to the fragment stage each frame via // SDL_PushGPUFragmentUniformData(pass, 0, &uniforms, sizeof(PostFXUniforms)) // MSL binding: constant PostFXUniforms& u [[buffer(0)]] // ============================================================================ struct PostFXUniforms { float vignette_strength; // 0 = none, 1.5 = default subtle float chroma_strength; // 0 = off, 1 = full chromatic aberration float scanline_strength; // 0 = off, 1 = full scanlines float time; // accumulated seconds (for future animations) }; // ============================================================================ // GpuPipeline — Creates and owns the graphics pipelines used by the engine. // // sprite_pipeline_ : textured quads, alpha blending. // Vertex layout: GpuVertex (pos float2, uv float2, col float4). // ball_pipeline_ : instanced ball rendering, alpha blending. // Vertex layout: BallGPUData as per-instance data (input_rate=INSTANCE). // 6 procedural vertices per instance (no index buffer). // postfx_pipeline_ : full-screen triangle, no vertex buffer, no blend. // Reads offscreen texture, writes to swapchain. // Accepts PostFXUniforms via fragment uniform buffer slot 0. // ============================================================================ class GpuPipeline { public: // target_format: pass SDL_GetGPUSwapchainTextureFormat() result. // offscreen_format: format of the offscreen render target. bool init(SDL_GPUDevice* device, SDL_GPUTextureFormat target_format, SDL_GPUTextureFormat offscreen_format); void destroy(SDL_GPUDevice* device); SDL_GPUGraphicsPipeline* spritePipeline() const { return sprite_pipeline_; } SDL_GPUGraphicsPipeline* ballPipeline() const { return ball_pipeline_; } SDL_GPUGraphicsPipeline* postfxPipeline() const { return postfx_pipeline_; } private: SDL_GPUShader* createShader(SDL_GPUDevice* device, const char* msl_source, const char* entrypoint, SDL_GPUShaderStage stage, Uint32 num_samplers, 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; };