// vim:fileencoding=utf-8:foldmethod=marker
//
// Vulkan backend declarations — concrete implementations of the RHI.
// Backend .c files include this header directly (never the umbrella pr_rhi.h)
// to avoid the #define aliases.

#ifndef PR_RHI_VK_H
#define PR_RHI_VK_H

#include "../pr_rhi_types.h"

// ============================================================================
// Opaque struct definitions — visible only to the backend implementation.
// ============================================================================

struct PrRhiInstance {
	void       *handle;  // VkInstance
	void       *debug_messenger;  // VkDebugUtilsMessengerEXT
};

struct PrRhiPhysicalDevice {
	void             *handle;  // VkPhysicalDevice
	PrRhiInstance    *instance;
};

struct PrRhiDevice {
	void   *handle;  // VkDevice
	void   *queue;   // VkQueue
	u32     queue_family_index;
	u32     present_mode;  // VkPresentModeKHR
	void   *physical_device;  // VkPhysicalDevice
	void   *allocator;  // VmaAllocator
};

struct PrRhiSurface {
	void *handle;  // VkSurfaceKHR
};

struct PrRhiSwapchain {
	PrRhiDevice    *device;
	void           *handle;  // VkSwapchainKHR
	void           *surface;  // PrRhiSurface *
	u32             image_count;
	PrRhiTexture  **images;
	PrRhiTexture   *depth;
	u32             format;  // VkFormat
	u32             width;
	u32             height;
	u32             current_image_index;
};

struct PrRhiBuffer {
	void *handle;  // VkBuffer
	void *allocation;  // VmaAllocation
	u64   device_address;
	u64   size;
	void *mapped_data;
};

struct PrRhiTexture {
	void *image;  // VkImage
	void *view;   // VkImageView
	void *allocation;  // VmaAllocation
	u32   width;
	u32   height;
	u32   format;  // VkFormat
};

struct PrRhiSampler {
	void *handle;  // VkSampler
};

struct PrRhiShader {
	void *handle;  // VkShaderModule
};

struct PrRhiPipelineLayout {
	void *handle;  // VkPipelineLayout
};

struct PrRhiPipeline {
	void *handle;  // VkPipeline
};

struct PrRhiDescriptorSetLayout {
	void *handle;  // VkDescriptorSetLayout
};

struct PrRhiDescriptorPool {
	void *handle;  // VkDescriptorPool
};

struct PrRhiDescriptorSet {
	void *handle;  // VkDescriptorSet
};

struct PrRhiCommandPool {
	void *handle;  // VkCommandPool
};

struct PrRhiCommandBuffer {
	void *handle;  // VkCommandBuffer
};

struct PrRhiFence {
	void *handle;  // VkFence
};

struct PrRhiSemaphore {
	void *handle;  // VkSemaphore
};

// ============================================================================
// Function declarations
// ============================================================================

PrRhiInstance *prRhiCreateInstanceVk(PrRhiInstanceDesc desc, WpAllocator *alloc);
void           prRhiDestroyInstanceVk(PrRhiInstance *inst, WpAllocator *alloc);

PrRhiPhysicalDeviceArray prRhiGetPhysicalDevicesVk(PrRhiInstance *inst, const WpAllocator *scratch);
void prRhiGetPhysicalDeviceNameVk(PrRhiPhysicalDevice *pdev, WpStr8 *out);
void prRhiGetPhysicalDeviceDriverInfoVk(PrRhiPhysicalDevice *pdev, WpStr8 *out);

PrRhiSurface *prRhiCreateSurfaceVk(PrRhiInstance *inst, void *window_handle, WpAllocator *alloc);
void          prRhiDestroySurfaceVk(PrRhiInstance *inst, PrRhiSurface *surface, WpAllocator *alloc);

PrRhiSurfaceCapabilities prRhiGetSurfaceCapabilitiesVk(PrRhiPhysicalDevice *pdev,
                                                        PrRhiSurface *surface);

PrRhiDevice *prRhiCreateDeviceVk(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface,
                                  PrRhiDeviceDesc desc, WpAllocator *alloc);
void         prRhiDestroyDeviceVk(PrRhiDevice *device, WpAllocator *alloc);
void         prRhiDeviceWaitIdleVk(PrRhiDevice *device);

PrRhiSwapchain *prRhiCreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchainDesc desc,
                                        WpAllocator *alloc);
void            prRhiDestroySwapchainVk(PrRhiDevice *device, PrRhiSwapchain *swapchain,
                                         WpAllocator *alloc);
PrRhiSwapchainResult prRhiAcquireNextImageVk(PrRhiDevice *device, PrRhiSwapchain *swapchain,
                                              PrRhiSemaphore *signal_semaphore, u32 *out_image_index);
PrRhiSwapchainResult prRhiPresentVk(PrRhiDevice *device, PrRhiSwapchain *swapchain,
                                     PrRhiSemaphore *wait_semaphore);
void prRhiRecreateSwapchainVk(PrRhiDevice *device, PrRhiSwapchain **swapchain,
                               u32 width, u32 height, WpAllocator *alloc);
PrRhiTexture *prRhiGetSwapchainTextureVk(PrRhiSwapchain *swapchain, u32 image_index);
PrRhiTexture *prRhiGetSwapchainDepthTextureVk(PrRhiSwapchain *swapchain);

PrRhiBuffer *prRhiCreateBufferVk(PrRhiDevice *device, PrRhiBufferDesc desc,
                                  WpAllocator *alloc);
void         prRhiDestroyBufferVk(PrRhiDevice *device, PrRhiBuffer *buffer, WpAllocator *alloc);
void        *prRhiBufferMapVk(PrRhiDevice *device, PrRhiBuffer *buffer);
void         prRhiBufferUnmapVk(PrRhiDevice *device, PrRhiBuffer *buffer);
PrRhiDeviceAddress prRhiGetBufferDeviceAddressVk(PrRhiDevice *device, PrRhiBuffer *buffer);

PrRhiTexture *prRhiCreateTextureVk(PrRhiDevice *device, PrRhiTextureDesc desc,
                                    WpAllocator *alloc);
void          prRhiDestroyTextureVk(PrRhiDevice *device, PrRhiTexture *texture,
                                     WpAllocator *alloc);

PrRhiSampler *prRhiCreateSamplerVk(PrRhiDevice *device, PrRhiSamplerDesc desc,
                                    WpAllocator *alloc);
void          prRhiDestroySamplerVk(PrRhiDevice *device, PrRhiSampler *sampler,
                                     WpAllocator *alloc);

PrRhiShader *prRhiCreateShaderVk(PrRhiDevice *device, PrRhiShaderDesc desc,
                                  WpAllocator *alloc);
void         prRhiDestroyShaderVk(PrRhiDevice *device, PrRhiShader *shader, WpAllocator *alloc);

PrRhiPipelineLayout *prRhiCreatePipelineLayoutVk(PrRhiDevice *device,
                                                  PrRhiPipelineLayoutDesc desc,
                                                  WpAllocator *alloc);
void                 prRhiDestroyPipelineLayoutVk(PrRhiDevice *device,
                                                   PrRhiPipelineLayout *layout,
                                                   WpAllocator *alloc);

PrRhiPipeline *prRhiCreateGraphicsPipelineVk(PrRhiDevice *device,
                                              PrRhiGraphicsPipelineDesc desc,
                                              WpAllocator *alloc);
PrRhiPipeline *prRhiCreateComputePipelineVk(PrRhiDevice *device,
                                             PrRhiComputePipelineDesc desc,
                                             WpAllocator *alloc);
void           prRhiDestroyPipelineVk(PrRhiDevice *device, PrRhiPipeline *pipeline,
                                       WpAllocator *alloc);

PrRhiDescriptorSetLayout *prRhiCreateDescriptorSetLayoutVk(PrRhiDevice *device,
                                                            PrRhiDescriptorSetLayoutDesc desc,
                                                            WpAllocator *alloc);
void                      prRhiDestroyDescriptorSetLayoutVk(PrRhiDevice *device,
                                                             PrRhiDescriptorSetLayout *layout,
                                                             WpAllocator *alloc);

PrRhiDescriptorPool *prRhiCreateDescriptorPoolVk(PrRhiDevice *device,
                                                  PrRhiDescriptorPoolDesc desc,
                                                  WpAllocator *alloc);
void                 prRhiDestroyDescriptorPoolVk(PrRhiDevice *device,
                                                   PrRhiDescriptorPool *pool,
                                                   WpAllocator *alloc);

PrRhiDescriptorSet *prRhiAllocateDescriptorSetVk(PrRhiDevice *device,
                                                  PrRhiDescriptorPool *pool,
                                                  PrRhiDescriptorSetLayout *layout,
                                                  u32 variable_count, WpAllocator *alloc);
void                prRhiFreeDescriptorSetVk(PrRhiDevice *device, PrRhiDescriptorPool *pool,
                                              PrRhiDescriptorSet *set, WpAllocator *alloc);
void prRhiUpdateDescriptorSetVk(PrRhiDevice *device, PrRhiWriteDescriptorSetArray writes);

PrRhiFence *prRhiCreateFenceVk(PrRhiDevice *device, PrRhiFenceDesc desc,
                                WpAllocator *alloc);
void        prRhiDestroyFenceVk(PrRhiDevice *device, PrRhiFence *fence, WpAllocator *alloc);

void prRhiWaitForFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count,
                           b8 wait_all, u64 timeout_ns);
void prRhiResetFencesVk(PrRhiDevice *device, PrRhiFenceArray fences, u32 count);

PrRhiSemaphore *prRhiCreateSemaphoreVk(PrRhiDevice *device, WpAllocator *alloc);
void            prRhiDestroySemaphoreVk(PrRhiDevice *device, PrRhiSemaphore *semaphore,
                                         WpAllocator *alloc);

PrRhiCommandPool *prRhiCreateCommandPoolVk(PrRhiDevice *device,
                                            PrRhiCommandPoolDesc desc,
                                            WpAllocator *alloc);
void              prRhiDestroyCommandPoolVk(PrRhiDevice *device, PrRhiCommandPool *pool,
                                             WpAllocator *alloc);
PrRhiCommandBufferArray prRhiAllocateCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool,
                                                       u32 count, WpAllocator *alloc);
void prRhiFreeCommandBuffersVk(PrRhiDevice *device, PrRhiCommandPool *pool,
                                u32 count, PrRhiCommandBufferArray buffers);

void prRhiBeginCommandBufferVk(PrRhiCommandBuffer *cb);
void prRhiEndCommandBufferVk(PrRhiCommandBuffer *cb);
void prRhiResetCommandBufferVk(PrRhiCommandBuffer *cb);

void prRhiCmdPipelineBarrierVk(PrRhiCommandBuffer *cb,
                                PrRhiImageMemoryBarrierArray image_barriers,
                                PrRhiBufferMemoryBarrierArray buffer_barriers);

void prRhiCmdBeginRenderingVk(PrRhiCommandBuffer *cb,
                               PrRhiColorAttachmentArray color_attachments,
                               const PrRhiDepthAttachment *depth_attachment);
void prRhiCmdEndRenderingVk(PrRhiCommandBuffer *cb);

void prRhiCmdSetViewportVk(PrRhiCommandBuffer *cb, f32 x, f32 y, f32 width, f32 height);
void prRhiCmdSetScissorVk(PrRhiCommandBuffer *cb, i32 x, i32 y, u32 width, u32 height);

void prRhiCmdBindPipelineVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint bind_point,
                             PrRhiPipeline *pipeline);
void prRhiCmdBindDescriptorSetsVk(PrRhiCommandBuffer *cb, PrRhiPipelineBindPoint bind_point,
                                    PrRhiPipelineLayout *layout, u32 first_set,
                                    PrRhiDescriptorSetArray sets);
void prRhiCmdPushConstantsVk(PrRhiCommandBuffer *cb, PrRhiPipelineLayout *layout,
                              PrRhiShaderStage stage_flags, u32 offset, u32 size,
                              const void *data);
void prRhiCmdBindVertexBuffersVk(PrRhiCommandBuffer *cb, u32 first_binding,
                                  PrRhiBufferArray buffers, const u64 *offsets, u32 count);
void prRhiCmdBindIndexBufferVk(PrRhiCommandBuffer *cb, PrRhiBuffer *buffer, u64 offset,
                                PrRhiIndexType index_type);

void prRhiCmdDrawVk(PrRhiCommandBuffer *cb, u32 vertex_count, u32 instance_count,
                     u32 first_vertex, u32 first_instance);
void prRhiCmdDrawIndexedVk(PrRhiCommandBuffer *cb, u32 index_count, u32 instance_count,
                            u32 first_index, i32 vertex_offset, u32 first_instance);

void prRhiCmdCopyBufferToImageVk(PrRhiCommandBuffer *cb, PrRhiBuffer *src, PrRhiTexture *dst);

void prRhiQueueSubmitVk(PrRhiDevice *device, PrRhiCommandBuffer *cb,
                         PrRhiSemaphore *wait_semaphore,
                         PrRhiSemaphore *signal_semaphore, PrRhiFence *fence);

#endif
