VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
vulkanGraphicsDevice.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3//
4// Vulkan implementation of the graphics device.
5//
6#pragma once
7
8#ifdef VISUTWIN_HAS_VULKAN
9
10#include <array>
11#include <vulkan/vulkan.h>
12#include <vk_mem_alloc.h>
13#include <SDL3/SDL.h>
14
17
18namespace visutwin::canvas
19{
20 class VulkanRenderPipeline;
21
22 class VulkanGraphicsDevice : public GraphicsDevice
23 {
24 public:
25 explicit VulkanGraphicsDevice(const GraphicsDeviceOptions& options);
26 ~VulkanGraphicsDevice() override;
27
28 // ── Core rendering ───────────────────────────────────────────────
29 void draw(const Primitive& primitive, const std::shared_ptr<IndexBuffer>& indexBuffer = nullptr,
30 int numInstances = 1, int indirectSlot = -1, bool first = true, bool last = true) override;
31
32 void setTransformUniforms(const Matrix4& viewProjection, const Matrix4& model) override;
33 void setLightingUniforms(const Color& ambientColor, const std::vector<GpuLightData>& lights,
34 const Vector3& cameraPosition, bool enableNormalMaps, float exposure,
35 const FogParams& fogParams = FogParams{}, const ShadowParams& shadowParams = ShadowParams{},
36 int toneMapping = 0) override;
37 void setEnvironmentUniforms(Texture* envAtlas, float skyboxIntensity, float skyboxMip,
38 const Vector3& skyDomeCenter = Vector3(0,0,0), bool isDome = false,
39 Texture* skyboxCubeMap = nullptr) override;
40
41 // ── Shader creation ──────────────────────────────────────────────
42 std::shared_ptr<Shader> createShader(const ShaderDefinition& definition,
43 const std::string& sourceCode = "") override;
44
45 // ── Resource creation ────────────────────────────────────────────
46 std::unique_ptr<gpu::HardwareTexture> createGPUTexture(Texture* texture) override;
47 std::shared_ptr<VertexBuffer> createVertexBuffer(const std::shared_ptr<VertexFormat>& format,
48 int numVertices, const VertexBufferOptions& options = VertexBufferOptions{}) override;
49 std::shared_ptr<IndexBuffer> createIndexBuffer(IndexFormat format, int numIndices,
50 const std::vector<uint8_t>& data = {}) override;
51 std::shared_ptr<RenderTarget> createRenderTarget(const RenderTargetOptions& options) override;
52
53 // ── Render pass lifecycle ────────────────────────────────────────
54 void startRenderPass(RenderPass* renderPass) override;
55 void endRenderPass(RenderPass* renderPass) override;
56
57 // ── Display management ───────────────────────────────────────────
58 void setResolution(int width, int height) override;
59 std::pair<int, int> size() const override;
60
61 // ── Vulkan accessors (for internal use by Vulkan subsystems) ─────
62 [[nodiscard]] VkDevice device() const { return _device; }
63 [[nodiscard]] VkPhysicalDevice physicalDevice() const { return _physicalDevice; }
64 [[nodiscard]] VkQueue graphicsQueue() const { return _graphicsQueue; }
65 [[nodiscard]] uint32_t graphicsQueueFamily() const { return _graphicsQueueFamily; }
66 [[nodiscard]] VmaAllocator vmaAllocator() const { return _vmaAllocator; }
67 [[nodiscard]] VkFormat swapchainFormat() const { return _swapchainFormat; }
68 [[nodiscard]] VkFormat depthFormat() const { return _depthFormat; }
69 [[nodiscard]] VkDescriptorPool descriptorPool() const { return _descriptorPool; }
70
71 // Upload command pool for immediate staging transfers
72 [[nodiscard]] VkCommandPool uploadCommandPool() const { return _uploadCommandPool; }
73 [[nodiscard]] VkFence uploadFence() const { return _uploadFence; }
74
75 private:
76 void onFrameStart() override;
77 void onFrameEnd() override;
78
79 void initInstance(SDL_Window* window);
80 void initDevice();
81 void initSwapchain(int width, int height);
82 void cleanupSwapchain();
83 void createDepthResources();
84 void destroyDepthResources();
85 void createPerFrameResources();
86 void destroyPerFrameResources();
87
88 SDL_Window* _window = nullptr;
89
90 // ── Vulkan core objects ──────────────────────────────────────────
91 VkInstance _instance = VK_NULL_HANDLE;
92 VkDebugUtilsMessengerEXT _debugMessenger = VK_NULL_HANDLE;
93 VkSurfaceKHR _surface = VK_NULL_HANDLE;
94 VkPhysicalDevice _physicalDevice = VK_NULL_HANDLE;
95 VkDevice _device = VK_NULL_HANDLE;
96 VkQueue _graphicsQueue = VK_NULL_HANDLE;
97 uint32_t _graphicsQueueFamily = 0;
98
99 // ── Memory allocator ─────────────────────────────────────────────
100 VmaAllocator _vmaAllocator = VK_NULL_HANDLE;
101
102 // ── Swapchain ────────────────────────────────────────────────────
103 VkSwapchainKHR _swapchain = VK_NULL_HANDLE;
104 VkFormat _swapchainFormat = VK_FORMAT_UNDEFINED;
105 VkExtent2D _swapchainExtent = {0, 0};
106 std::vector<VkImage> _swapchainImages;
107 std::vector<VkImageView> _swapchainImageViews;
108
109 // ── Depth buffer ─────────────────────────────────────────────────
110 VkImage _depthImage = VK_NULL_HANDLE;
111 VmaAllocation _depthAllocation = VK_NULL_HANDLE;
112 VkImageView _depthImageView = VK_NULL_HANDLE;
113 VkFormat _depthFormat = VK_FORMAT_D32_SFLOAT;
114
115 // ── Per-frame resources (double-buffered) ────────────────────────
116 static constexpr uint32_t kMaxFramesInFlight = 2;
117
118 struct PerFrame {
119 VkCommandPool commandPool = VK_NULL_HANDLE;
120 VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
121 VkSemaphore imageAvailable = VK_NULL_HANDLE;
122 VkSemaphore renderFinished = VK_NULL_HANDLE;
123 VkFence inFlightFence = VK_NULL_HANDLE;
124 };
125 std::array<PerFrame, kMaxFramesInFlight> _frames{};
126 uint32_t _frameIndex = 0;
127 uint32_t _swapchainImageIndex = 0;
128
129 // ── Upload resources (for immediate staging transfers) ───────────
130 VkCommandPool _uploadCommandPool = VK_NULL_HANDLE;
131 VkFence _uploadFence = VK_NULL_HANDLE;
132
133 // ── Render pipeline ──────────────────────────────────────────────
134 std::unique_ptr<VulkanRenderPipeline> _renderPipeline;
135 VkPipeline _currentPipeline = VK_NULL_HANDLE;
136 bool _dynamicRenderingActive = false;
137
138 // ── Descriptor pool ──────────────────────────────────────────────
139 VkDescriptorPool _descriptorPool = VK_NULL_HANDLE;
140
141 // ── Push constants ───────────────────────────────────────────────
142 struct PushConstants {
143 float viewProjection[16]{};
144 float model[16]{};
145 };
146 PushConstants _pushConstants{};
147 bool _pushConstantsDirty = false;
148
149 // ── Default resources ────────────────────────────────────────────
150 VkSampler _defaultSampler = VK_NULL_HANDLE;
151 VkImage _whiteImage = VK_NULL_HANDLE;
152 VmaAllocation _whiteAllocation = VK_NULL_HANDLE;
153 VkImageView _whiteImageView = VK_NULL_HANDLE;
154
155 int _width = 0;
156 int _height = 0;
157 };
158}
159
160#endif // VISUTWIN_HAS_VULKAN
Abstract GPU interface for resource creation, state management, and draw submission.
std::shared_ptr< Shader > createShader(GraphicsDevice *graphicsDevice, const ShaderDefinition &definition, const std::string &sourceCode)
Definition shader.cpp:39