#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). // 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* 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); SDL_GPUGraphicsPipeline* sprite_pipeline_ = nullptr; SDL_GPUGraphicsPipeline* postfx_pipeline_ = nullptr; };