# Raylib Vulkan Upgrade Plan This document outlines the strategy for integrating Vulkan as a compile-time graphics backend option for raylib. The goal is to maintain the existing raylib API and ease of use while providing an alternative, modern graphics API. ## 1. Define Vulkan API Abstraction Layer (`rlvk`) A new abstraction layer, similar to `rlgl` for OpenGL, will be created for Vulkan. This layer, tentatively named `rlvk`, will reside in `src/rlvk.h` and `src/rlvk.c`. **Key Responsibilities of `rlvk`:** * **Initialization & Deinitialization:** * `rlvkInit()`: * Initialize Vulkan loader. * Create Vulkan instance (`vkCreateInstance`). * Setup debug messenger (if `RLGL_ENABLE_OPENGL_DEBUG_CONTEXT` or a new Vulkan equivalent is defined). * Select a suitable physical device (`vkEnumeratePhysicalDevices`, `vkGetPhysicalDeviceProperties`, `vkGetPhysicalDeviceFeatures`, `vkGetPhysicalDeviceQueueFamilyProperties`). * Create a logical device (`vkCreateDevice`) with necessary queues (graphics, present). * Create a Vulkan surface using the platform layer (e.g., via GLFW's `glfwCreateWindowSurface`). * Create the swapchain (`vkCreateSwapchainKHR`). * Create image views for swapchain images (`vkCreateImageView`). * Create a default render pass (`vkCreateRenderPass`). * Create framebuffers for each swapchain image view, associating them with the render pass (`vkCreateFramebuffer`). * Create a command pool (`vkCreateCommandPool`). * Allocate primary command buffers (`vkAllocateCommandBuffers`). * Create synchronization primitives (semaphores for image available/render finished, fences for command buffer execution) (`vkCreateSemaphore`, `vkCreateFence`). * Initialize default resources (e.g., default white texture, default shaders in SPIR-V). * Setup default pipeline state objects (PSO) for common rendering tasks (e.g., 2D textured quads, 3D models). * `rlvkClose()`: * Wait for device to be idle (`vkDeviceWaitIdle`). * Destroy all Vulkan resources in reverse order of creation (synchronization primitives, command buffers, command pool, framebuffers, render pass, image views, swapchain, logical device, surface, debug messenger, instance). * **Core Rendering Loop Functions:** * `rlvkBeginDrawing()`: * Acquire the next available swapchain image (`vkAcquireNextImageKHR`). * Begin the primary command buffer (`vkBeginCommandBuffer`). * Begin the default render pass (`vkCmdBeginRenderPass`). * Set default viewport and scissor. * `rlvkEndDrawing()`: * End the render pass (`vkCmdEndRenderPass`). * End the command buffer (`vkEndCommandBuffer`). * Submit the command buffer to the graphics queue (`vkQueueSubmit`), waiting on the image available semaphore and signaling the render finished semaphore. * Present the rendered image to the swapchain (`vkQueuePresentKHR`), waiting on the render finished semaphore. * **Matrix Operations:** * Maintain projection and modelview matrix stacks similar to `rlgl`. * `rlvkMatrixMode()`, `rlvkPushMatrix()`, `rlvkPopMatrix()`, `rlvkLoadIdentity()`, `rlvkTranslatef()`, `rlvkRotatef()`, `rlvkScalef()`, `rlvkMultMatrixf()`. * These will update internal matrix state, which will then be passed to shaders via UBOs/push constants. * **Viewport and Clipping:** * `rlvkViewport()`: Set dynamic viewport state (`vkCmdSetViewport`). * `rlvkSetClipPlanes()`: Potentially manage via shader logic or dynamic rasterizer state if available/performant. Vulkan does not have direct equivalents to `gl_ClipDistance` in the same way as OpenGL for user-defined clip planes easily manipulated by `rlFrustum`. * **Vertex Buffer Management (Batching System):** * Adapt or reimplement raylib's batching system (`rlRenderBatch`) for Vulkan. * `rlvkLoadRenderBatch()`: Create Vulkan buffers (vertex, index, staging) for batch data. * `rlvkUnloadRenderBatch()`: Destroy Vulkan buffers. * `rlvkDrawRenderBatch()`: * If batch data has changed, update staging buffers and record commands to copy to device-local buffers (`vkCmdCopyBuffer`). * Bind appropriate pipeline (PSO). * Bind descriptor sets (for UBOs, textures). * Bind vertex and index buffers (`vkCmdBindVertexBuffers`, `vkCmdBindIndexBuffer`). * Issue draw calls (`vkCmdDrawIndexed` or `vkCmdDraw`). * `rlvkSetTexture()`: Manage texture binding for the current batch, potentially requiring different descriptor sets or dynamic descriptor updates. * **Immediate Mode Emulation (`rlBegin`, `rlEnd`, `rlVertex3f`, etc.):** * These functions will populate the CPU-side vertex buffers of the active `rlRenderBatch`. * `rlBegin()` will set the primitive topology for the current batch draw call. * **Texture Management:** * `rlvkLoadTexture()`: * Create Vulkan image (`vkCreateImage`) with appropriate format, extent, mip levels, usage flags. * Allocate device memory (`vkAllocateMemory`, `vkBindImageMemory`). * Create image view (`vkCreateImageView`). * Create a default sampler (`vkCreateSampler`). * Transition image layout to `VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL`. * Upload pixel data using a staging buffer and command buffer operations (`vkCmdCopyBufferToImage`). * `rlvkLoadTextureDepth()`: Create depth/stencil attachment. * `rlvkLoadTextureCubemap()`: Similar to `rlvkLoadTexture` but for cubemaps. * `rlvkUpdateTexture()`: Update a region of an existing texture using staging buffers. * `rlvkGenTextureMipmaps()`: Generate mipmaps using `vkCmdBlitImage` if supported, or require pre-generated mipmaps. * `rlvkUnloadTexture()`: Destroy image, image view, sampler, and free device memory. * **Shader Management:** * `rlvkLoadShaderCode()`: Will expect SPIR-V bytecode. * `rlvkLoadShaderProgram()`: Create `VkShaderModule` from SPIR-V, define pipeline layouts, and potentially create initial `VkPipeline` objects. * `rlvkGetLocationUniform()`, `rlvkGetLocationAttrib()`: Manage mapping of uniform/attribute names to SPIR-V binding points/locations. * `rlvkSetUniform()`: Update UBOs or push constants. * `rlvkSetShader()`: Select the active pipeline and descriptor sets. * **Framebuffer Management:** * `rlvkLoadFramebuffer()`: Create `VkFramebuffer` (distinct from swapchain framebuffers, for render textures). * `rlvkFramebufferAttach()`: Attach textures to custom framebuffers. * `rlvkFramebufferComplete()`: Check framebuffer completeness. * **Render State Management:** * `rlvkEnableColorBlend()`, `rlvkDisableColorBlend()`, `rlvkSetBlendMode()`, `rlvkSetBlendFactors()`: Configure `VkPipelineColorBlendStateCreateInfo`. * `rlvkEnableDepthTest()`, `rlvkDisableDepthTest()`: Configure `VkPipelineDepthStencilStateCreateInfo`. * `rlvkEnableDepthMask()`, `rlvkDisableDepthMask()`: Part of `VkPipelineDepthStencilStateCreateInfo`. * `rlvkEnableBackfaceCulling()`, `rlvkDisableBackfaceCulling()`, `rlvkSetCullFace()`: Configure `VkPipelineRasterizationStateCreateInfo`. * `rlvkEnableScissorTest()`, `rlvkDisableScissorTest()`, `rlvkScissor()`: Set dynamic scissor state (`vkCmdSetScissor`). * `rlvkEnableWireMode()`, `rlvkDisableWireMode()`: Set `polygonMode` in `VkPipelineRasterizationStateCreateInfo`. ## 2. Core Library Integration (`rcore.c`) * **Conditional Compilation:** * Use `#if defined(GRAPHICS_API_VULKAN)` to conditionally include `rlvk.h` and call `rlvk` functions. * Ensure only one graphics API is active (e.g., `#elif defined(GRAPHICS_API_OPENGL_XX)`). * **`InitWindow()` Modifications:** * If `GRAPHICS_API_VULKAN` is defined: * Call `InitPlatform()` (platform layer, e.g., GLFW, will need Vulkan-specific setup). * Call `rlvkInit()` instead of `rlglInit()`. * Set `isGpuReady = true` upon successful Vulkan initialization. * **`CloseWindow()` Modifications:** * If `GRAPHICS_API_VULKAN` is defined: * Call `rlvkClose()` before `ClosePlatform()`. * **Drawing Function Adaption:** * Functions like `ClearBackground()`, `BeginDrawing()`, `EndDrawing()`, `BeginMode2D()`, `EndMode2D()`, `BeginMode3D()`, `EndMode3D()`, `BeginTextureMode()`, `EndTextureMode()`, `BeginShaderMode()`, `EndShaderMode()`, etc., will need to call their `rlvk` counterparts when `GRAPHICS_API_VULKAN` is active. ## 3. Platform Layer Integration (Example: `rcore_desktop_glfw.c`) * **Window Creation:** * When `GRAPHICS_API_VULKAN` is defined: * Call `glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);` before `glfwCreateWindow()`. * **Surface Creation:** * After window creation, if Vulkan is active, call `glfwCreateWindowSurface(vulkanInstance, windowHandle, NULL, &vulkanSurface)` to create the Vulkan rendering surface. This surface handle will be needed by `rlvkInit()`. * **Instance Extensions:** * Query required Vulkan instance extensions from GLFW using `glfwGetRequiredInstanceExtensions()` and pass them to `vkCreateInstance` in `rlvkInit()`. * **Input and Other Callbacks:** * Most input handling and window event callbacks should remain largely unchanged. ## 4. Build System Changes (CMake) * **Add CMake Option:** * In the main `CMakeLists.txt` or a dedicated options file (e.g., `cmake/CMakeOptions.txt` or a new `cmake/GraphicsAPI.cmake`), add an option to select Vulkan. This could be a boolean `SUPPORT_VULKAN` or an enum-style option like `GRAPHICS_BACKEND` with values "OpenGL" and "Vulkan". * Example: `option(SUPPORT_VULKAN "Enable Vulkan graphics backend" OFF)` * **Conditional Compilation Define:** * Based on the CMake option, add a compile definition for `GRAPHICS_API_VULKAN` to `src/config.h` or directly to the target compile definitions. * Ensure mutual exclusivity with OpenGL defines (e.g., `GRAPHICS_API_OPENGL_33`). * Example in `src/config.h` (controlled by CMake): ```c // Select desired graphics API (OpenGL or Vulkan) // #define GRAPHICS_API_OPENGL_11 // #define GRAPHICS_API_OPENGL_21 // #define GRAPHICS_API_OPENGL_33 // #define GRAPHICS_API_OPENGL_43 // #define GRAPHICS_API_OPENGL_ES2 // #define GRAPHICS_API_OPENGL_ES3 // #define GRAPHICS_API_VULKAN // This would be enabled by CMake ``` * **Link Vulkan Libraries:** * When Vulkan is enabled, use `find_package(Vulkan REQUIRED)` to locate the Vulkan SDK. * Link the raylib library against `Vulkan::Vulkan` (for the loader) and potentially `Vulkan::glslang` or `Vulkan::SPIRV-Tools` if shader compilation is handled by CMake. * **Source Files:** * Conditionally compile `src/rlvk.c` when Vulkan is enabled. * **Shader Compilation (SPIR-V):** * If GLSL shaders are to be compiled to SPIR-V at build time: * Integrate a tool like `glslangValidator` as a custom build step. * Define rules to find GLSL shaders (e.g., in `src/shaders/glsl/` or a new `src/shaders/vk/`) and compile them to SPIR-V, placing the output in the build directory for embedding or loading. ## 5. Shader Management for Vulkan * **SPIR-V Requirement:** Vulkan shaders must be in SPIR-V binary format. * **Compilation Strategy:** * **Option A (Build-time compilation):** Use `glslangValidator` (or similar) integrated into the CMake build process to compile GLSL shaders to SPIR-V. These SPIR-V files can then be embedded into the executable or loaded at runtime. * **Option B (Pre-compiled SPIR-V):** Require users or developers to provide pre-compiled SPIR-V shaders. * Raylib's default shaders will need to be converted to GLSL suitable for Vulkan (e.g., using explicit binding locations) and then compiled to SPIR-V. * **`rlvkLoadShaderCode()`:** This function in `rlvk.c` will expect paths to SPIR-V files or raw SPIR-V bytecode if embedded. * **Descriptor Sets and Pipeline Layouts:** * `rlvk` will need to manage `VkDescriptorSetLayout`, `VkPipelineLayout`, `VkDescriptorPool`, and `VkDescriptorSet` for binding UBOs and textures to shaders. This is significantly different from OpenGL's `glGetUniformLocation`. ## 6. Potential Challenges and Considerations * **API Mapping:** Translating raylib's simple, immediate-mode style OpenGL calls to Vulkan's more complex, explicit API requires careful design of the `rlvk` layer to hide Vulkan's verbosity. * **Performance:** While Vulkan offers potential performance benefits, a naive translation might not achieve them. Efficient batching, command buffer usage, and resource management will be crucial. * **Error Handling:** Vulkan's error reporting is robust but requires more explicit checking. * **Driver Differences:** Vulkan driver quality and feature support can vary. * **Development Complexity:** Implementing a Vulkan backend is a substantial undertaking. * **Shader Management:** Handling SPIR-V and descriptor sets is more involved than GLSL uniform locations. * **Maintaining Simplicity:** A core tenet of raylib is its ease of use. The Vulkan backend should ideally not expose Vulkan's complexity to the end-user. This plan provides a high-level roadmap. Each step, especially the design and implementation of `rlvk`, involves many detailed sub-tasks. ## Vulkan Upgrade Plan for raylib This document outlines the necessary modifications to integrate Vulkan support into the raylib library, managed by a compile-time flag `GRAPHICS_API_VULKAN`. ### 1. Build System (CMake) **File: `CMakeLists.txt` (Root)** * **Add CMake Option:** * Introduce an option `SUPPORT_VULKAN` (default OFF) to enable Vulkan backend. ```cmake option(SUPPORT_VULKAN "Enable Vulkan graphics backend" OFF) ``` * **Find Vulkan SDK:** * If `SUPPORT_VULKAN` is ON, use `find_package` to locate the Vulkan SDK. ```cmake if (SUPPORT_VULKAN) find_package(Vulkan REQUIRED) if (NOT Vulkan_FOUND) message(FATAL_ERROR "Vulkan SDK not found, required for SUPPORT_VULKAN option.") else() message(STATUS "Vulkan SDK found: Headers at ${Vulkan_INCLUDE_DIRS}, Libraries at ${Vulkan_LIBRARIES}") endif() endif() ``` **File: `src/CMakeLists.txt`** * **Set Preprocessor Define:** * In `CompileDefinitions.cmake` (or directly in `src/CMakeLists.txt` if more appropriate), add `GRAPHICS_API_VULKAN` if `SUPPORT_VULKAN` is ON and Vulkan is found. ```cmake # Inside CompileDefinitions.cmake or src/CMakeLists.txt if (SUPPORT_VULKAN AND Vulkan_FOUND) target_compile_definitions(raylib PUBLIC GRAPHICS_API_VULKAN) # Potentially link Vulkan libraries # target_link_libraries(raylib PUBLIC Vulkan::Vulkan) # Modern CMake # or target_link_libraries(raylib PUBLIC ${Vulkan_LIBRARIES}) # Older CMake endif() ``` * The exact linking method (`Vulkan::Vulkan` vs `Vulkan_LIBRARIES`) depends on how `FindVulkan.cmake` exports its targets. `Vulkan::Vulkan` is preferred if available. * **Conditionally Compile Vulkan Source Files:** * Add new source files for the Vulkan backend (e.g., `rlgl_vulkan.c`, `rcore_vulkan_glfw.c`) to the `raylib_sources` list conditionally. ```cmake if (SUPPORT_VULKAN AND Vulkan_FOUND) list(APPEND raylib_sources platforms/rcore_vulkan_glfw.c # Or other platform specific Vulkan file rlgl_vulkan.c # Or however rlgl's Vulkan part is named ) # Also ensure Vulkan headers are available target_include_directories(raylib PUBLIC $) endif() ``` * **Link Vulkan Libraries:** * Ensure Vulkan libraries are linked. This might be handled by `LibraryConfigurations.cmake` or directly here. The `target_link_libraries` call mentioned above for preprocessor definitions might already cover this if `Vulkan::Vulkan` is an INTERFACE library that carries its link dependencies. Otherwise, add explicitly: ```cmake if (SUPPORT_VULKAN AND Vulkan_FOUND) # If not handled by an INTERFACE library target like Vulkan::Vulkan target_link_libraries(raylib PUBLIC ${Vulkan_LIBRARIES}) endif() ``` **File: `cmake/LibraryConfigurations.cmake`** * This file likely contains logic for selecting graphics APIs (OpenGL versions). It will need to be extended: * Add checks for `GRAPHICS_API_VULKAN`. * If defined, ensure it sets up any necessary Vulkan-specific library paths or flags, and potentially skips/overrides some OpenGL configurations. ### 2. Configuration Header **File: `src/config.h`** * This file might not need explicit changes if `GRAPHICS_API_VULKAN` is purely controlled by CMake. * However, for consistency or manual override capabilities, a section could be added: ```c // Module: rlgl - Configuration Flags // ... existing flags ... // #define GRAPHICS_API_VULKAN 1 ``` * Code within raylib would then check `#if defined(GRAPHICS_API_VULKAN)` ### 3. Graphics Abstraction Layer (`rlgl`) **File: `src/rlgl.h`** * **Include Vulkan Headers:** ```c #if defined(GRAPHICS_API_VULKAN) #include // May need platform-specific Vulkan extensions for surfaces (e.g., vulkan_win32.h) // These would typically be included in the platform-specific rcore_vulkan_*.c file #endif ``` * **Conditional Function Declarations / Implementations:** * The existing `rlgl` functions (`rlLoadTexture`, `rlLoadShaderCode`, `rlBegin`, `rlEnd`, `rlDrawRenderBatch`, etc.) will need to either: 1. Have internal conditional logic: ```c RLAPI void rlBegin(int mode) { #if defined(GRAPHICS_API_VULKAN) // Vulkan implementation for rlBegin #elif defined(GRAPHICS_API_OPENGL_33) // OpenGL 3.3 implementation #else // GRAPHICS_API_OPENGL_11 // OpenGL 1.1 implementation #endif } ``` 2. Or, more cleanly, `rlgl.h` could define function pointers that are assigned during `rlglInit` to point to either OpenGL or Vulkan implementations. This is a more significant refactor but more extensible. ```c // In rlgl.h // extern void (*rlBeginImpl)(int mode); // #define rlBegin rlBeginImpl // In rlglInit() or a new rlglInitVulkan() // #if defined(GRAPHICS_API_VULKAN) // rlBeginImpl = rlBegin_Vulkan; // #else // rlBeginImpl = rlBegin_OpenGL; // #endif ``` * Given raylib's style, the first approach (internal conditional logic with `#if defined()`) is more likely. **New File: `src/rlgl_vulkan.c` (or integrated into `rlgl.h`)** * This file will contain the Vulkan implementations of `rlgl` functions. * **`rlglInit_Vulkan(VkInstance instance, VkSurfaceKHR surface)` (or similar signature):** * **Physical Device Selection:** Enumerate physical devices, select a suitable one (e.g., discrete GPU with necessary queue families). * **Logical Device Creation:** Create `VkDevice` with required queues (graphics, present). * **Swapchain Setup:** * Query surface capabilities, formats, and present modes. * Choose swapchain format, extent, and present mode. * Create `VkSwapchainKHR`. * Get swapchain images and create `VkImageViews`. * **Command Pools & Buffers:** Create command pools and pre-allocate command buffers. * **Render Passes:** Create a default `VkRenderPass` compatible with the swapchain image format (for clearing and basic drawing). * **Framebuffers:** Create framebuffers for each swapchain image view, associating them with the render pass. * **Pipelines:** * Create a default graphics pipeline (vertex input, shaders, viewport, rasterizer, MSAA, depth/stencil, color blending). This will require a default SPIR-V vertex and fragment shader. * Pipeline layout. * **Synchronization Primitives:** Create semaphores and fences for frame rendering synchronization. * **Default Resources:** * Create a default 1x1 white texture (`VkImage`, `VkDeviceMemory`, `VkImageView`, `VkSampler`). * Load/compile default SPIR-V shaders for basic textured/colored drawing. Store their `VkShaderModule` handles. * Initialize Vulkan-specific parts of `RLGL.State` or a new `RLGL_VK_State` struct. * **`rlglClose_Vulkan()`:** * Call `vkDeviceWaitIdle()`. * Destroy all Vulkan resources in reverse order of creation (pipelines, framebuffers, render passes, swapchain, device, command pools, default textures/shaders, instance, etc.). * **Drawing Functions (`rlBegin`, `rlEnd`, `rlVertex3f`, `rlSetTexture`, etc.):** * These will need to manage a Vulkan-specific render batch system. * `rlBegin` might start a command buffer recording or select a pipeline. * `rlVertex3f` and related functions will populate CPU-side vertex/index buffers. * `rlEnd` or `rlDrawRenderBatch` will: * Copy CPU vertex/index data to Vulkan staging buffers, then to `VkBuffer` (vertex/index buffers). * Acquire next swapchain image. * Begin command buffer recording. * Begin render pass. * Bind pipeline, descriptor sets (for textures, uniforms). * Bind vertex/index buffers. * Set viewport/scissor. * Issue `vkCmdDraw` or `vkCmdDrawIndexed`. * End render pass. * End command buffer. * Submit command buffer to graphics queue. * Present swapchain image. * **Texture Functions (`rlLoadTexture`, `rlUpdateTexture`, `rlUnloadTexture`):** * `rlLoadTexture`: Create `VkImage`, allocate `VkDeviceMemory`, create `VkImageView`, `VkSampler`. Handle data upload via staging buffer. * `rlUpdateTexture`: Update `VkImage` data, potentially via staging buffer. * `rlUnloadTexture`: Destroy Vulkan image resources. * **Shader Functions (`rlLoadShaderFromMemory`, `rlLoadShader`):** * Modify to accept SPIR-V bytecode. * Create `VkShaderModule` from SPIR-V. * Store `VkShaderModule` handles. Pipeline creation will use these. * The existing `Shader` struct in raylib might need to be extended or have a Vulkan-specific counterpart to store `VkPipelineLayout`, `VkPipeline`, and descriptor set layouts/pools if shaders manage their own pipelines. ### 4. Core Layer (`rcore`) **File: `src/rcore.c`** * **`InitWindow()`:** * Modify to conditionally call `InitPlatformVulkan()` if `GRAPHICS_API_VULKAN` is defined. ```c #if defined(GRAPHICS_API_VULKAN) result = InitPlatformVulkan(); // New function in platform layer #else result = InitPlatform(); // Existing function #endif ``` * After platform initialization (which creates Vulkan instance & surface), call `rlglInit_Vulkan(instance, surface)` instead of `rlglInit()`. * **`CloseWindow()`:** * Modify to conditionally call `ClosePlatformVulkan()`. ```c #if defined(GRAPHICS_API_VULKAN) ClosePlatformVulkan(); #else ClosePlatform(); #endif ``` * Call `rlglClose_Vulkan()` instead of `rlglClose()`. ### 5. Platform Layer (`src/platforms/`) **New File: `src/platforms/rcore_vulkan_glfw.c` (example for GLFW)** * This file will handle Vulkan-specific initialization for the GLFW platform. * **`InitPlatformVulkan()`:** * Call `glfwInit()`. * Check for Vulkan support: `glfwVulkanSupported()`. * Get required instance extensions: `glfwGetRequiredInstanceExtensions()`. * Create `VkInstance` using these extensions and potentially validation layers. * Window hints for Vulkan: `glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API)`. * Create GLFW window: `glfwCreateWindow()`. Store window handle in `platform.handle`. * Create Vulkan surface: `glfwCreateWindowSurface(vkInstance, platform.handle, NULL, &vkSurface)`. * Store `vkInstance` and `vkSurface` (perhaps in `PlatformData` struct or pass to `rlglInit_Vulkan`). * Call `rlglInit_Vulkan(vkInstance, vkSurface)`. * Setup GLFW input callbacks (can be reused from `rcore_desktop_glfw.c`). * **`ClosePlatformVulkan()`:** * Call `rlglClose_Vulkan()`. * Destroy `VkSurfaceKHR` (`vkDestroySurfaceKHR(vkInstance, vkSurface, NULL)`). * Destroy `VkInstance` (`vkDestroyInstance(vkInstance, NULL)`). * Call `glfwDestroyWindow(platform.handle)`. * Call `glfwTerminate()`. * **PlatformData Struct:** * The existing `PlatformData` struct (if any, or a new one) might need to store `VkInstance` and `VkSurfaceKHR`. ```c // In rcore_vulkan_glfw.c typedef struct PlatformDataVulkan { GLFWwindow *handle; VkInstance instance; VkSurfaceKHR surface; // Other Vulkan specific platform data if needed } PlatformDataVulkan; ``` ### 6. Shader System and Examples * **SPIR-V Compilation:** * A build step needs to be added to compile GLSL shaders (from `examples/shaders/resources/shaders/glslXXX/`) to SPIR-V. * Tools like `glslangValidator` (from Vulkan SDK) can be used for this. * Example CMake integration: ```cmake # In examples/CMakeLists.txt or similar if (SUPPORT_VULKAN AND Vulkan_FOUND AND GLSLANG_VALIDATOR_EXECUTABLE) # Loop through example shaders and compile them # add_custom_command(...) endif() ``` * **Shader Loading in Examples:** * Examples that load shaders will need to be updated to load the compiled SPIR-V versions when the Vulkan backend is active. * This might involve path changes or conditional loading based on `GRAPHICS_API_VULKAN`. * **Default Shaders in `rlgl`:** * The default shaders used internally by `rlgl` (e.g., for `DrawRectangle`, `DrawTexture`) must also be provided in SPIR-V format and loaded by `rlglInit_Vulkan`. ### 7. Memory Management * Vulkan requires explicit memory management. `rlgl_vulkan.c` will need to handle `VkDeviceMemory` allocations and deallocations for buffers and images. * Consider using a Vulkan Memory Allocator library (e.g., VMA from AMD) for more robust and efficient memory management, though for a first pass, direct Vulkan calls can be used. ### 8. Error Handling * Vulkan API calls return `VkResult`. These should be checked consistently, and errors should be logged using raylib's `TRACELOG`. This plan provides a high-level overview. Each point, especially within `rlgl_vulkan.c`, involves significant implementation detail. The core principle is to abstract Vulkan complexities within `rlgl` and the platform layer, keeping the raylib API consistent for the end-user. ## Review Findings (Task: Double check the plan for errors and make certain the plan will even work) **Review Date:** 2024-07-26 **Reviewer:** Jules (AI Software Engineering Agent) This section summarizes the findings from a review of the "Raylib Vulkan Upgrade Plan." The review aimed to check the plan for errors, assess its feasibility, and ensure its overall viability. **1. Status of Existing Vulkan Implementation in Repository:** * A thorough check of the repository confirmed that **raylib does not currently have an integrated Vulkan rendering backend within its core `src` files.** * Vulkan-related code identified is confined to: * External libraries (`GLFW` via `src/external/glfw/deps/glad/vulkan.h` and `RGFW` via `src/external/RGFW.h`), which provide Vulkan surface creation and instance extension support. This is standard for windowing libraries and does not constitute a raylib rendering backend. * The `vulkan-upgrade-plan` document itself. * Conclusion: The `vulkan-upgrade-plan` is prospective and does not duplicate existing or partially implemented work within raylib's core rendering pipeline. **2. Overall Viability and Strengths of the Plan:** * The `vulkan-upgrade-plan` is **highly viable** and presents a **comprehensive, well-researched strategy** for integrating a Vulkan backend. * **Key Strengths:** * **Clear Abstraction Strategy:** The proposed new abstraction layer (`rlvk` or integrated into `rlgl`) is a sound architectural approach, mirroring the existing `rlgl` layer for OpenGL. * **Detailed Technical Breakdown:** The plan meticulously details responsibilities for Vulkan initialization/deinitialization, the rendering loop, and management of resources like textures, buffers, shaders (SPIR-V), descriptor sets, and pipeline layouts. * **Actionable Implementation Steps:** The file-by-file breakdown for CMake, core raylib files, and platform layers offers a clear roadmap. * **Correct Vulkan Fundamentals:** The plan accurately identifies core Vulkan requirements (SPIR-V, explicit synchronization, descriptor sets, command buffer structure). * **Realistic Challenge Assessment:** The document acknowledges the inherent complexities of Vulkan and the challenges in maintaining raylib's simplicity. **3. Areas for Minor Refinement/Clarification during Detailed Design:** * **Naming and Dispatch Consistency:** * Finalize the naming convention (e.g., `rlvk.c`/`rlvk.h` vs. `rlgl_vulkan.c`). * Clarify the precise dispatch mechanism for raylib API calls to the Vulkan backend (e.g., internal conditional compilation within existing `rlgl` functions is suggested as a clean approach). * **`VkInstance` Creation Responsibility:** * Clearly delineate whether the platform layer or the core Vulkan backend (`rlvkInit`/`rlglInit_Vulkan`) is responsible for `vkCreateInstance` creation (typically the core backend, using extensions provided by the platform layer). * **Advanced Vulkan Considerations (for future robustness/performance):** * **Dynamic States:** Acknowledge the potential use of Vulkan's dynamic states to reduce PSO permutations. * **Render Pass Extensibility:** Consider how the render pass system might evolve for advanced techniques (e.g., deferred rendering, subpasses), though a single default pass is suitable initially. * **Explicit Synchronization:** While implied, ensure detailed planning for `VkImageMemoryBarrier`, `VkBufferMemoryBarrier`, and `VkEvent` usage for all resource transitions and updates. * **Multithreaded Command Buffer Generation:** Note as a potential future optimization. * **Device Feature Enablement:** Explicitly include querying and enabling necessary `VkPhysicalDeviceFeatures` during `VkDevice` creation. * **Swapchain Recreation:** Detail the strategy for robustly handling window resizing and the necessary swapchain recreation, including all dependent resources (image views, framebuffers). **4. Key Challenges and Feasibility:** * **Feasibility:** The project is **technically feasible but highly ambitious.** * **Primary Challenge:** The most significant task is creating an abstraction layer that effectively shields raylib users from Vulkan's inherent complexity, preserving the library's hallmark ease of use and gentle learning curve. * **Resource Intensive:** Requires substantial, dedicated development effort and deep Vulkan expertise. * **Performance:** Achieving performance parity or improvement over optimized OpenGL requires careful Vulkan-specific design, not just a direct translation of concepts. * **Maintenance:** Introducing a second major graphics backend will significantly increase the long-term maintenance load, requiring expertise in both APIs. **5. Conclusion of Review:** * The `vulkan-upgrade-plan` is an **excellent and well-conceived document.** It provides a solid and viable foundation for integrating a Vulkan rendering backend into raylib. * The plan is free of obvious conceptual errors regarding Vulkan or raylib's architecture. The identified areas for refinement are minor and typical for a high-level plan transitioning to detailed design. * The success of this ambitious project will depend on the availability of dedicated resources with strong Vulkan expertise, rigorous testing, and a continued commitment to raylib's core philosophy of simplicity. ---