Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
VulkanWindow.cpp
1/*
2Copyright (C) 2017-2021,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#include "VulkanWindow.hpp"
17#include "VulkanRenderer.hpp"
18#include "VulkanPipeline.hpp"
19#include "VulkanMaterial.hpp"
20#include "VulkanUtilities.hpp"
21#include "VulkanMesh.hpp"
22#include <sstream>
23#include <iostream>
24#include <algorithm>
25#include <array>
26#include <utility>
27#include <cstring>
28#include <cassert>
29#include "aeongames/Frustum.hpp"
30#include "aeongames/Material.hpp"
31#include "aeongames/Pipeline.hpp"
32#include "aeongames/Mesh.hpp"
33#include "aeongames/AABB.hpp"
34#include "aeongames/Scene.hpp"
35#include "aeongames/Node.hpp"
36#include "aeongames/Mesh.hpp"
37#include "aeongames/Pipeline.hpp"
38#include "aeongames/Material.hpp"
40#include "aeongames/MemoryPool.hpp"
41
42#if defined(__APPLE__)
43// Helper function to get CAMetalLayer from NSView (implemented in MacOSMetalHelper.mm)
44extern "C" void* GetMetalLayerFromNSView ( void* nsview_ptr );
45#endif
46
47namespace AeonGames
48{
49 VulkanWindow::VulkanWindow ( VulkanRenderer& aVulkanRenderer, void* aWindowId ) :
50 mVulkanRenderer { aVulkanRenderer }, mWindowId{aWindowId},
51 mMemoryPoolBuffer{mVulkanRenderer, 64_kb},
52 mMatrices { aVulkanRenderer }
53 {
54 std::cout << LogLevel::Info << "Creating VulkanWindow." << std::endl;
55 try
56 {
57 Initialize();
58 }
59 catch ( ... )
60 {
61 Finalize();
62 throw;
63 }
64 }
65
67 mVulkanRenderer { aVulkanWindow.mVulkanRenderer },
68 mMemoryPoolBuffer{std::move ( aVulkanWindow.mMemoryPoolBuffer ) },
69 mMatrices{std::move ( aVulkanWindow.mMatrices ) }
70 {
71 std::cout << LogLevel::Debug << "Moving VulkanWindow." << std::endl;
72 std::swap ( mWindowId, aVulkanWindow.mWindowId );
73 std::swap ( mFrustum, aVulkanWindow.mFrustum );
74 std::swap ( mProjectionMatrix, aVulkanWindow.mProjectionMatrix );
75 std::swap ( mViewMatrix, aVulkanWindow.mViewMatrix );
76 std::swap ( mVkSurfaceKHR, aVulkanWindow.mVkSurfaceKHR );
77 std::swap ( mVkSurfaceCapabilitiesKHR, aVulkanWindow.mVkSurfaceCapabilitiesKHR );
78 std::swap ( mSwapchainImageCount, aVulkanWindow.mSwapchainImageCount );
79 std::swap ( mVkSwapchainKHR, aVulkanWindow.mVkSwapchainKHR );
80 std::swap ( mVkDepthStencilImage, aVulkanWindow.mVkDepthStencilImage );
81 std::swap ( mVkDepthStencilImageMemory, aVulkanWindow.mVkDepthStencilImageMemory );
82 std::swap ( mVkDepthStencilImageView, aVulkanWindow.mVkDepthStencilImageView );
83 std::swap ( mHasStencil, aVulkanWindow.mHasStencil );
84 std::swap ( mActiveImageIndex, aVulkanWindow.mActiveImageIndex );
85 std::swap ( mVkViewport, aVulkanWindow.mVkViewport );
86 std::swap ( mVkScissor, aVulkanWindow.mVkScissor );
87 std::swap ( mVkDepthStencilFormat, aVulkanWindow.mVkDepthStencilFormat );
88 std::swap ( mVkSurfaceFormatKHR, aVulkanWindow.mVkSurfaceFormatKHR );
89 std::swap ( mVkRenderPass, aVulkanWindow.mVkRenderPass );
90 std::swap ( mMatricesDescriptorPool, aVulkanWindow.mMatricesDescriptorPool );
91 std::swap ( mMatricesDescriptorSet, aVulkanWindow.mMatricesDescriptorSet );
92 std::swap ( mVkCommandPool, aVulkanWindow.mVkCommandPool );
93 std::swap ( mVkCommandBuffer, aVulkanWindow.mVkCommandBuffer );
94 std::swap ( mVkAcquireSemaphore, aVulkanWindow.mVkAcquireSemaphore );
95 std::swap ( mVkFence, aVulkanWindow.mVkFence );
96 mVkSwapchainImages.swap ( aVulkanWindow.mVkSwapchainImages );
97 mVkSwapchainImageViews.swap ( aVulkanWindow.mVkSwapchainImageViews );
98 mVkFramebuffers.swap ( aVulkanWindow.mVkFramebuffers );
99 mVkSubmitSemaphores.swap ( aVulkanWindow.mVkSubmitSemaphores );
100 }
101
102 VulkanWindow::~VulkanWindow()
103 {
104 std::cout << LogLevel::Info << "Destroying VulkanWindow." << std::endl;
105 Finalize();
106 }
107
108 void VulkanWindow::InitializeSurface()
109 {
110#if defined ( VK_USE_PLATFORM_WIN32_KHR )
111 VkWin32SurfaceCreateInfoKHR win32_surface_create_info_khr {};
112 win32_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
113 win32_surface_create_info_khr.hwnd = reinterpret_cast<HWND> ( mWindowId );
114 win32_surface_create_info_khr.hinstance = reinterpret_cast<HINSTANCE> ( GetWindowLongPtr ( win32_surface_create_info_khr.hwnd, GWLP_HINSTANCE ) );
115 if ( VkResult result = vkCreateWin32SurfaceKHR ( mVulkanRenderer.GetInstance(), &win32_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) )
116 {
117 std::ostringstream stream;
118 stream << "Call to vkCreateWin32SurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )";
119 std::cout << LogLevel::Error << stream.str() << std::endl;
120 throw std::runtime_error ( stream.str().c_str() );
121 }
122#elif defined( VK_USE_PLATFORM_METAL_EXT )
123 VkMetalSurfaceCreateInfoEXT metal_surface_create_info_ext {};
124 metal_surface_create_info_ext.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
125 metal_surface_create_info_ext.pLayer = reinterpret_cast<CAMetalLayer*> ( GetMetalLayerFromNSView ( mWindowId ) );
126 if ( VkResult result = vkCreateMetalSurfaceEXT ( mVulkanRenderer.GetInstance(), &metal_surface_create_info_ext, nullptr, &mVkSurfaceKHR ) )
127 {
128 std::ostringstream stream;
129 stream << "Call to vkCreateMetalSurfaceEXT failed: ( " << GetVulkanResultString ( result ) << " )";
130 std::cout << LogLevel::Error << stream.str() << std::endl;
131 throw std::runtime_error ( stream.str().c_str() );
132 }
133#elif defined( VK_USE_PLATFORM_XLIB_KHR )
134 VkXlibSurfaceCreateInfoKHR xlib_surface_create_info_khr {};
135 xlib_surface_create_info_khr.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
136 xlib_surface_create_info_khr.dpy = mVulkanRenderer.GetDisplay();
137 xlib_surface_create_info_khr.window = reinterpret_cast<::Window> ( mWindowId );
138 if ( VkResult result = vkCreateXlibSurfaceKHR ( mVulkanRenderer.GetInstance(), &xlib_surface_create_info_khr, nullptr, &mVkSurfaceKHR ) )
139 {
140 std::ostringstream stream;
141 stream << "Call to vkCreateXlibSurfaceKHR failed: ( " << GetVulkanResultString ( result ) << " )";
142 std::cout << LogLevel::Error << stream.str() << std::endl;
143 throw std::runtime_error ( stream.str().c_str() );
144 }
145#endif
146 VkBool32 wsi_supported = false;
147 vkGetPhysicalDeviceSurfaceSupportKHR ( mVulkanRenderer.GetPhysicalDevice(), mVulkanRenderer.GetQueueFamilyIndex(), mVkSurfaceKHR, &wsi_supported );
148 if ( !wsi_supported )
149 {
150 std::ostringstream stream;
151 stream << "WSI not supported.";
152 std::cout << LogLevel::Error << stream.str() << std::endl;
153 throw std::runtime_error ( stream.str().c_str() );
154 }
155 }
156
157 void VulkanWindow::InitializeSwapchain()
158 {
159 std::cout << LogLevel::Debug << "Initializing VulkanWindow Swapchain." << std::endl;
160 vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &mVkSurfaceCapabilitiesKHR );
161
162 if ( mVkSurfaceCapabilitiesKHR.currentExtent.width == 0 ||
163 mVkSurfaceCapabilitiesKHR.currentExtent.height == 0 )
164 {
165 std::ostringstream stream;
166 stream << "Cannot create swapchain with zero area. (" << mVkSurfaceCapabilitiesKHR.currentExtent.width << "x" << mVkSurfaceCapabilitiesKHR.currentExtent.height << ")" << std::endl;
167 std::cout << LogLevel::Error << stream.str() << std::endl;
168 throw std::runtime_error ( stream.str().c_str() );
169 }
170
171 if ( mSwapchainImageCount < mVkSurfaceCapabilitiesKHR.minImageCount )
172 {
173 mSwapchainImageCount = mVkSurfaceCapabilitiesKHR.minImageCount;
174 }
175 if ( ( mVkSurfaceCapabilitiesKHR.maxImageCount > 0 ) &&
176 ( mSwapchainImageCount > mVkSurfaceCapabilitiesKHR.maxImageCount ) )
177 {
178 mSwapchainImageCount = mVkSurfaceCapabilitiesKHR.maxImageCount;
179 }
180 VkSwapchainCreateInfoKHR swapchain_create_info{};
181 swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
182 swapchain_create_info.surface = mVkSurfaceKHR;
183 swapchain_create_info.minImageCount = mSwapchainImageCount;
184 swapchain_create_info.imageFormat = mVkSurfaceFormatKHR.format;
185 swapchain_create_info.imageColorSpace = mVkSurfaceFormatKHR.colorSpace;
186 swapchain_create_info.imageExtent.width = mVkSurfaceCapabilitiesKHR.currentExtent.width;
187 swapchain_create_info.imageExtent.height = mVkSurfaceCapabilitiesKHR.currentExtent.height;
188 swapchain_create_info.imageArrayLayers = 1;
189 swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
190 swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
191 swapchain_create_info.queueFamilyIndexCount = 0;
192 swapchain_create_info.pQueueFamilyIndices = nullptr;
193 swapchain_create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
194 swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
195 swapchain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; // This may be reset below.
196 swapchain_create_info.clipped = VK_TRUE;
197 swapchain_create_info.oldSwapchain = mVkSwapchainKHR; // Used for Resizing.
198 {
199 uint32_t present_mode_count = 0;
200 vkGetPhysicalDeviceSurfacePresentModesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &present_mode_count, nullptr );
201 std::vector<VkPresentModeKHR> present_mode_list ( present_mode_count );
202 vkGetPhysicalDeviceSurfacePresentModesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &present_mode_count, present_mode_list.data() );
203 for ( auto& i : present_mode_list )
204 {
205 if ( i == VK_PRESENT_MODE_MAILBOX_KHR )
206 {
207 swapchain_create_info.presentMode = i;
208 break;
209 }
210 }
211 }
212 if ( VkResult result = vkCreateSwapchainKHR ( mVulkanRenderer.GetDevice(), &swapchain_create_info, nullptr, &mVkSwapchainKHR ) )
213 {
214 std::ostringstream stream;
215 stream << "Call to vkCreateSwapchainKHR failed: ( " << GetVulkanResultString ( result ) << " )";
216 std::cout << LogLevel::Error << stream.str() << std::endl;
217 throw std::runtime_error ( stream.str().c_str() );
218 }
219 if ( swapchain_create_info.oldSwapchain != VK_NULL_HANDLE )
220 {
221 vkDestroySwapchainKHR ( mVulkanRenderer.GetDevice(), swapchain_create_info.oldSwapchain, nullptr );
222 }
223
224 std::cout << LogLevel::Debug << "VulkanWindow Swapchain created with " << mSwapchainImageCount << " images." << std::endl;
225 // Create semaphores for rendering.
226 VkSemaphoreCreateInfo semaphore_create_info{};
227 semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
228 if ( VkResult result = vkCreateSemaphore ( mVulkanRenderer.GetDevice(), &semaphore_create_info, nullptr, &mVkAcquireSemaphore ) )
229 {
230 std::ostringstream stream;
231 stream << "Could not create VulkanRenderer semaphore. error code: ( " << GetVulkanResultString ( result ) << " )";
232 throw std::runtime_error ( stream.str().c_str() );
233 }
234 std::cout << LogLevel::Debug << "Created Acquire Semaphore " << std::hex << mVkAcquireSemaphore << std::endl;
235 mVkSubmitSemaphores.resize ( mSwapchainImageCount );
236 for ( size_t i = 0; i < mSwapchainImageCount; ++i )
237 {
238 if ( VkResult result = vkCreateSemaphore ( mVulkanRenderer.GetDevice(), &semaphore_create_info, nullptr, &mVkSubmitSemaphores[i] ) )
239 {
240 std::ostringstream stream;
241 stream << "Could not create VulkanRenderer semaphore. error code: ( " << GetVulkanResultString ( result ) << " )";
242 throw std::runtime_error ( stream.str().c_str() );
243 }
244 std::cout << LogLevel::Debug << "Created Submit Semaphore " << std::hex << mVkSubmitSemaphores[i] << std::endl;
245 }
246 VkFenceCreateInfo fence_create_info{};
247 fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
248 fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
249 vkCreateFence ( mVulkanRenderer.GetDevice(), &fence_create_info, nullptr, &mVkFence );
250 }
251
252 void VulkanWindow::InitializeImageViews()
253 {
254 if ( mVkSwapchainKHR == VK_NULL_HANDLE )
255 {
256 std::ostringstream stream;
257 stream << "Cannot initialize swapchain image views with no swapchain.";
258 std::cout << LogLevel::Error << stream.str() << std::endl;
259 throw std::runtime_error ( stream.str().c_str() );
260 }
261 if ( VkResult result = vkGetSwapchainImagesKHR ( mVulkanRenderer.GetDevice(), mVkSwapchainKHR, &mSwapchainImageCount, nullptr ) )
262 {
263 std::ostringstream stream;
264 stream << "Get swapchain image count failed: ( " << GetVulkanResultString ( result ) << " )";
265 std::cout << LogLevel::Error << stream.str() << std::endl;
266 throw std::runtime_error ( stream.str().c_str() );
267 }
268 mVkSwapchainImages.resize ( mSwapchainImageCount );
269 mVkSwapchainImageViews.resize ( mSwapchainImageCount );
270 if ( VkResult result = vkGetSwapchainImagesKHR ( mVulkanRenderer.GetDevice(),
271 mVkSwapchainKHR,
272 &mSwapchainImageCount,
273 mVkSwapchainImages.data() ) )
274 {
275 std::ostringstream stream;
276 stream << "Get swapchain images failed: ( " << GetVulkanResultString ( result ) << " )";
277 std::cout << LogLevel::Error << stream.str() << std::endl;
278 throw std::runtime_error ( stream.str().c_str() );
279 }
280 for ( uint32_t i = 0; i < mSwapchainImageCount; ++i )
281 {
282 VkImageViewCreateInfo image_view_create_info{};
283 image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
284 image_view_create_info.pNext = nullptr;
285 image_view_create_info.flags = 0;
286 image_view_create_info.image = mVkSwapchainImages[i];
287 image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
288 image_view_create_info.format = mVkSurfaceFormatKHR.format;
289 image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
290 image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
291 image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
292 image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
293 image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
294 image_view_create_info.subresourceRange.baseMipLevel = 0;
295 image_view_create_info.subresourceRange.levelCount = 1;
296 image_view_create_info.subresourceRange.baseArrayLayer = 0;
297 image_view_create_info.subresourceRange.layerCount = 1;
298 vkCreateImageView ( mVulkanRenderer.GetDevice(), &image_view_create_info, nullptr, &mVkSwapchainImageViews[i] );
299 }
300 }
301
302 void VulkanWindow::InitializeDepthStencil()
303 {
304 if ( mVkSurfaceCapabilitiesKHR.currentExtent.width == 0 ||
305 mVkSurfaceCapabilitiesKHR.currentExtent.height == 0 )
306 {
307 std::cout << LogLevel::Debug << "Cannot create depth stencil with zero area. (" << mVkSurfaceCapabilitiesKHR.currentExtent.width << "x" << mVkSurfaceCapabilitiesKHR.currentExtent.height << ")" << std::endl;
308 return;
309 }
310
311 mHasStencil =
312 ( mVkDepthStencilFormat == VK_FORMAT_D32_SFLOAT_S8_UINT ||
313 mVkDepthStencilFormat == VK_FORMAT_D24_UNORM_S8_UINT ||
314 mVkDepthStencilFormat == VK_FORMAT_D16_UNORM_S8_UINT );
315 VkImageCreateInfo image_create_info{};
316 image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
317 image_create_info.flags = 0;
318 image_create_info.format = mVkDepthStencilFormat;
319 image_create_info.imageType = VK_IMAGE_TYPE_2D;
320 image_create_info.extent.width = mVkSurfaceCapabilitiesKHR.currentExtent.width;
321 image_create_info.extent.height = mVkSurfaceCapabilitiesKHR.currentExtent.height;
322 image_create_info.extent.depth = 1;
323 image_create_info.mipLevels = 1;
324 image_create_info.arrayLayers = 1;
325 image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
326 image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
327 image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
328 image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
329 image_create_info.queueFamilyIndexCount = 0;
330 image_create_info.pQueueFamilyIndices = nullptr;
331 image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
332 if ( VkResult result = vkCreateImage ( mVulkanRenderer.GetDevice(), &image_create_info, nullptr, &mVkDepthStencilImage ) )
333 {
334 std::ostringstream stream;
335 stream << "Call to vkCreateImage failed: ( " << GetVulkanResultString ( result ) << " )";
336 std::cout << LogLevel::Error << stream.str() << std::endl;
337 throw std::runtime_error ( stream.str().c_str() );
338 }
339
340 VkMemoryRequirements memory_requirements;
341 vkGetImageMemoryRequirements ( mVulkanRenderer.GetDevice(), mVkDepthStencilImage, &memory_requirements );
342
343 auto required_bits = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
344 uint32_t memory_index = UINT32_MAX;
345 for ( uint32_t i = 0; i < mVulkanRenderer.GetPhysicalDeviceMemoryProperties().memoryTypeCount; ++i )
346 {
347 if ( memory_requirements.memoryTypeBits & ( 1 << i ) )
348 {
349 if ( ( mVulkanRenderer.GetPhysicalDeviceMemoryProperties().memoryTypes[i].propertyFlags & required_bits ) == required_bits )
350 {
351 memory_index = i;
352 break;
353 }
354 }
355 }
356
357 if ( memory_index == UINT32_MAX )
358 {
359 std::ostringstream stream;
360 stream << "Could not find a suitable memory index.";
361 std::cout << LogLevel::Error << stream.str() << std::endl;
362 throw std::runtime_error ( stream.str().c_str() );
363 }
364 VkMemoryAllocateInfo memory_allocate_info{};
365 memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
366 memory_allocate_info.allocationSize = memory_requirements.size;
367 memory_allocate_info.memoryTypeIndex = memory_index;
368 vkAllocateMemory ( mVulkanRenderer.GetDevice(), &memory_allocate_info, nullptr, &mVkDepthStencilImageMemory );
369 vkBindImageMemory ( mVulkanRenderer.GetDevice(), mVkDepthStencilImage, mVkDepthStencilImageMemory, 0 );
370
371 VkImageViewCreateInfo image_view_create_info{};
372 image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
373 image_view_create_info.image = mVkDepthStencilImage;
374 image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
375 image_view_create_info.format = mVkDepthStencilFormat;
376 image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
377 image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
378 image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
379 image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
380 image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | ( mHasStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0 );
381 image_view_create_info.subresourceRange.baseMipLevel = 0;
382 image_view_create_info.subresourceRange.levelCount = 1;
383 image_view_create_info.subresourceRange.baseArrayLayer = 0;
384 image_view_create_info.subresourceRange.layerCount = 1;
385 vkCreateImageView ( mVulkanRenderer.GetDevice(), &image_view_create_info, nullptr, &mVkDepthStencilImageView );
386 }
387
388 void VulkanWindow::InitializeFrameBuffers()
389 {
390 if ( mVkSurfaceCapabilitiesKHR.currentExtent.width == 0 ||
391 mVkSurfaceCapabilitiesKHR.currentExtent.height == 0 )
392 {
393 std::cout << LogLevel::Debug << "Cannot create framebuffers with zero area. (" << mVkSurfaceCapabilitiesKHR.currentExtent.width << "x" << mVkSurfaceCapabilitiesKHR.currentExtent.height << ")" << std::endl;
394 return;
395 }
396 mVkFramebuffers.resize ( mSwapchainImageCount );
397 for ( uint32_t i = 0; i < mSwapchainImageCount; ++i )
398 {
399 std::array<VkImageView, 2> attachments
400 {
401 {
402 mVkSwapchainImageViews[i],
403 mVkDepthStencilImageView
404 }
405 };
406 VkFramebufferCreateInfo framebuffer_create_info{};
407 framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
408 framebuffer_create_info.renderPass = mVkRenderPass;
409 framebuffer_create_info.attachmentCount = static_cast<uint32_t> ( attachments.size() );
410 framebuffer_create_info.pAttachments = attachments.data();
411 framebuffer_create_info.width = mVkSurfaceCapabilitiesKHR.currentExtent.width;
412 framebuffer_create_info.height = mVkSurfaceCapabilitiesKHR.currentExtent.height;
413 framebuffer_create_info.layers = 1;
414 vkCreateFramebuffer ( mVulkanRenderer.GetDevice(), &framebuffer_create_info, nullptr, &mVkFramebuffers[i] );
415 }
416 }
417
418 void VulkanWindow::InitializeRenderPass()
419 {
420 uint32_t surface_format_count = 0;
421 vkGetPhysicalDeviceSurfaceFormatsKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_format_count, nullptr );
422 if ( surface_format_count == 0 )
423 {
424 std::ostringstream stream;
425 stream << "Physical device reports no surface formats.";
426 std::cout << LogLevel::Error << stream.str() << std::endl;
427 throw std::runtime_error ( stream.str().c_str() );
428 }
429
430 std::vector<VkSurfaceFormatKHR> surface_format_list ( surface_format_count );
431 vkGetPhysicalDeviceSurfaceFormatsKHR (
432 mVulkanRenderer.GetPhysicalDevice(),
433 mVkSurfaceKHR,
434 &surface_format_count,
435 surface_format_list.data() );
436
437 if ( surface_format_list[0].format == VK_FORMAT_UNDEFINED )
438 {
439 mVkSurfaceFormatKHR.format = VK_FORMAT_B8G8R8A8_UNORM;
440 mVkSurfaceFormatKHR.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
441 }
442 else
443 {
444 mVkSurfaceFormatKHR = surface_format_list[0];
445 }
446 std::array<VkFormat, 5> try_formats
447 {
448 {
449 VK_FORMAT_D32_SFLOAT_S8_UINT,
450 VK_FORMAT_D24_UNORM_S8_UINT,
451 VK_FORMAT_D16_UNORM_S8_UINT,
452 VK_FORMAT_D32_SFLOAT,
453 VK_FORMAT_D16_UNORM
454 }
455 };
456 for ( auto format : try_formats )
457 {
458 VkFormatProperties format_properties{};
459 vkGetPhysicalDeviceFormatProperties ( mVulkanRenderer.GetPhysicalDevice(), format, &format_properties );
460 if ( format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT )
461 {
462 mVkDepthStencilFormat = format;
463 break;
464 }
465 }
466
467 if ( std::find ( try_formats.begin(), try_formats.end(), mVkDepthStencilFormat ) == try_formats.end() )
468 {
469 std::ostringstream stream;
470 stream << "Unable to find a suitable depth stencil format";
471 std::cout << LogLevel::Error << stream.str() << std::endl;
472 throw std::runtime_error ( stream.str().c_str() );
473 }
474
475 std::array<VkAttachmentDescription, 2> attachment_descriptions{ {} };
476 attachment_descriptions[0].flags = 0;
477 attachment_descriptions[0].format = mVkSurfaceFormatKHR.format;
478 attachment_descriptions[0].samples = VK_SAMPLE_COUNT_1_BIT;
479 attachment_descriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
480 attachment_descriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
481 attachment_descriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
482 attachment_descriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
483 attachment_descriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
484 attachment_descriptions[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
485
486 attachment_descriptions[1].flags = 0;
487 attachment_descriptions[1].format = mVkDepthStencilFormat;
488 attachment_descriptions[1].samples = VK_SAMPLE_COUNT_1_BIT;
489 attachment_descriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
490 attachment_descriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
491 attachment_descriptions[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
492 attachment_descriptions[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
493 attachment_descriptions[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
494 attachment_descriptions[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
495
496 std::array<VkAttachmentReference, 1> color_attachment_references{};
497 color_attachment_references[0].attachment = 0;
498 color_attachment_references[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
499
500 VkAttachmentReference depth_stencil_attachment_reference{};
501 depth_stencil_attachment_reference.attachment = 1;
502 depth_stencil_attachment_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
503
504 std::array<VkSubpassDescription, 1> subpass_descriptions{};
505 subpass_descriptions[0].flags = 0;
506 subpass_descriptions[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
507 subpass_descriptions[0].inputAttachmentCount = 0;
508 subpass_descriptions[0].pInputAttachments = nullptr;
509 subpass_descriptions[0].colorAttachmentCount = static_cast<uint32_t> ( color_attachment_references.size() );
510 subpass_descriptions[0].pColorAttachments = color_attachment_references.data();
511 subpass_descriptions[0].pResolveAttachments = nullptr;
512 subpass_descriptions[0].pDepthStencilAttachment = &depth_stencil_attachment_reference;
513 subpass_descriptions[0].preserveAttachmentCount = 0;
514 subpass_descriptions[0].pPreserveAttachments = nullptr;
515
516 VkSubpassDependency subpass_dependency = {};
517 subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
518 subpass_dependency.dstSubpass = 0;
519 subpass_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
520 subpass_dependency.srcAccessMask = 0;
521 subpass_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
522 subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
523
524 VkRenderPassCreateInfo render_pass_create_info{};
525 render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
526 render_pass_create_info.attachmentCount = static_cast<uint32_t> ( attachment_descriptions.size() );
527 render_pass_create_info.pAttachments = attachment_descriptions.data();
528 render_pass_create_info.dependencyCount = 1;
529 render_pass_create_info.pDependencies = &subpass_dependency;
530 render_pass_create_info.subpassCount = static_cast<uint32_t> ( subpass_descriptions.size() );
531 render_pass_create_info.pSubpasses = subpass_descriptions.data();
532 vkCreateRenderPass ( mVulkanRenderer.GetDevice(), &render_pass_create_info, nullptr, &mVkRenderPass );
533 }
534
535 void VulkanWindow::FinalizeRenderPass()
536 {
537 if ( mVkRenderPass != VK_NULL_HANDLE )
538 {
539 vkDestroyRenderPass ( mVulkanRenderer.GetDevice(), mVkRenderPass, nullptr );
540 }
541 }
542
543 void VulkanWindow::InitializeMatrices()
544 {
545 mMatrices.Initialize (
546 sizeof ( float ) * 16 * 2,
547 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
548 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT );
549
550 VkDescriptorSetLayoutCreateInfo matrices_descriptor_set_layout_create_info{};
551 matrices_descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
552 matrices_descriptor_set_layout_create_info.bindingCount = 1;
553 VkDescriptorSetLayoutBinding matrices_descriptor_set_layout_binding{};
554 matrices_descriptor_set_layout_binding.binding = 0;
555 matrices_descriptor_set_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
556 matrices_descriptor_set_layout_binding.descriptorCount = 1;
557 // we're assuming only vertex shaders will access matrices for now
558 //matrices_descriptor_set_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
559 matrices_descriptor_set_layout_binding.stageFlags = VK_SHADER_STAGE_ALL;
560 matrices_descriptor_set_layout_binding.pImmutableSamplers = nullptr;
561 matrices_descriptor_set_layout_create_info.pBindings = &matrices_descriptor_set_layout_binding;
562
563 mMatricesDescriptorPool = CreateDescriptorPool ( mVulkanRenderer.GetDevice(), {{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}} );
564 mMatricesDescriptorSet = CreateDescriptorSet ( mVulkanRenderer.GetDevice(), mMatricesDescriptorPool, mVulkanRenderer.GetDescriptorSetLayout ( matrices_descriptor_set_layout_create_info ) );
565 VkDescriptorBufferInfo descriptor_buffer_info{};
566 descriptor_buffer_info.buffer = mMatrices.GetBuffer();
567 descriptor_buffer_info.offset = 0;
568 descriptor_buffer_info.range = mMatrices.GetSize();
569 VkWriteDescriptorSet write_descriptor_set{};
570 write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
571 write_descriptor_set.pNext = nullptr;
572 write_descriptor_set.dstSet = mMatricesDescriptorSet;
573 write_descriptor_set.dstBinding = 0;
574 write_descriptor_set.dstArrayElement = 0;
575 write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
576 write_descriptor_set.descriptorCount = 1;
577 write_descriptor_set.pBufferInfo = &descriptor_buffer_info;
578 write_descriptor_set.pImageInfo = nullptr;
579 write_descriptor_set.pTexelBufferView = nullptr;
580 vkUpdateDescriptorSets ( mVulkanRenderer.GetDevice(), 1, &write_descriptor_set, 0, nullptr );
581 }
582
583 void VulkanWindow::FinalizeMatrices()
584 {
585 DestroyDescriptorPool ( mVulkanRenderer.GetDevice(), mMatricesDescriptorPool );
586 mMatrices.Finalize();
587 }
588
589 void VulkanWindow::Initialize()
590 {
591 InitializeMatrices();
592 InitializeSurface();
593 InitializeRenderPass();
594 InitializeSwapchain();
595 InitializeImageViews();
596 InitializeDepthStencil();
597 InitializeFrameBuffers();
598 InitializeCommandBuffer();
599 }
600
601 void VulkanWindow::Finalize()
602 {
603 if ( VkResult result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) )
604 {
605 std::cerr << LogLevel::Error << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result );
606 }
607 if ( VkResult result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) )
608 {
609 std::cerr << LogLevel::Error << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result );
610 }
611 FinalizeCommandBuffer();
612 FinalizeFrameBuffers();
613 FinalizeDepthStencil();
614 FinalizeImageViews();
615 FinalizeSwapchain();
616 FinalizeRenderPass();
617 FinalizeSurface();
618 FinalizeMatrices();
619 }
620
621 void VulkanWindow::ResizeViewport ( int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight )
622 {
623 VkSurfaceCapabilitiesKHR surface_capabilities{};
624 VkResult result {vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( mVulkanRenderer.GetPhysicalDevice(), mVkSurfaceKHR, &surface_capabilities ) };
625 if ( result == VK_SUCCESS && std::memcmp ( &surface_capabilities, &mVkSurfaceCapabilitiesKHR, sizeof ( VkSurfaceCapabilitiesKHR ) ) != 0 )
626 {
627 if ( VK_SUCCESS != ( result = vkQueueWaitIdle ( mVulkanRenderer.GetQueue() ) ) )
628 {
629 std::ostringstream stream;
630 stream << "vkQueueWaitIdle failed: " << GetVulkanResultString ( result );
631 std::cout << LogLevel::Error << stream.str() << std::endl;
632 throw std::runtime_error ( stream.str().c_str() );
633 }
634
635 if ( VK_SUCCESS != ( result = vkDeviceWaitIdle ( mVulkanRenderer.GetDevice() ) ) )
636 {
637 std::ostringstream stream;
638 stream << "vkDeviceWaitIdle failed: " << GetVulkanResultString ( result );
639 std::cout << LogLevel::Error << stream.str() << std::endl;
640 throw std::runtime_error ( stream.str().c_str() );
641 }
642 FinalizeFrameBuffers();
643 FinalizeDepthStencil();
644 FinalizeImageViews();
645 FinalizeSwapchain();
646 InitializeSwapchain();
647 InitializeImageViews();
648 InitializeDepthStencil();
649 InitializeFrameBuffers();
650 }
651 mVkViewport.x = static_cast<float> ( aX );
652 mVkViewport.y = static_cast<float> ( aY );
653 mVkViewport.width = static_cast<float> ( aWidth );
654 mVkViewport.height = static_cast<float> ( aHeight );
655 // Clip Scissors to surface extents
656 mVkScissor.offset.x = ( aX < 0 ) ? 0 : aX;
657 mVkScissor.offset.y = ( aY < 0 ) ? 0 : aY;
658 mVkScissor.extent.width = ( aX + aWidth > mVkSurfaceCapabilitiesKHR.currentExtent.width ) ? mVkSurfaceCapabilitiesKHR.currentExtent.width : aX + aWidth;
659 mVkScissor.extent.height = ( aY + aHeight > mVkSurfaceCapabilitiesKHR.currentExtent.height ) ? mVkSurfaceCapabilitiesKHR.currentExtent.height : aY + aHeight;
660 }
661
663 {
664 mProjectionMatrix = aMatrix;
665 mFrustum = mProjectionMatrix * mViewMatrix;
666 mMatrices.WriteMemory ( 0, sizeof ( float ) * 16, aMatrix.GetMatrix4x4() );
667 }
668
670 {
671 mViewMatrix = aMatrix;
672 mFrustum = mProjectionMatrix * mViewMatrix;
673 mMatrices.WriteMemory ( sizeof ( float ) * 16, sizeof ( float ) * 16, aMatrix.GetMatrix4x4() );
674 }
675
677 {
678 return mProjectionMatrix;
679 }
680
682 {
683 return mViewMatrix;
684 }
685
687 {
688 return mFrustum;
689 }
690
691 void VulkanWindow::InitializeCommandBuffer()
692 {
693 VkCommandPoolCreateInfo command_pool_create_info{};
694 command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
700 command_pool_create_info.flags = /*VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT*/ 0;
701 command_pool_create_info.queueFamilyIndex = mVulkanRenderer.GetQueueFamilyIndex();
702 vkCreateCommandPool ( mVulkanRenderer.GetDevice(), &command_pool_create_info, nullptr, &mVkCommandPool );
703
704 VkCommandBufferAllocateInfo command_buffer_allocate_info{};
705 command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
706 command_buffer_allocate_info.commandPool = mVkCommandPool;
707 command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
708 command_buffer_allocate_info.commandBufferCount = 1;
709 vkAllocateCommandBuffers ( mVulkanRenderer.GetDevice(), &command_buffer_allocate_info, &mVkCommandBuffer );
710 }
711
712 void VulkanWindow::FinalizeCommandBuffer()
713 {
714 if ( mVkCommandPool != VK_NULL_HANDLE )
715 {
716 vkDestroyCommandPool ( mVulkanRenderer.GetDevice(), mVkCommandPool, nullptr );
717 mVkCommandPool = VK_NULL_HANDLE;
718 }
719 }
720
722 {
723 if ( VkResult result = vkWaitForFences ( mVulkanRenderer.GetDevice(), 1,
724 &mVkFence,
725 VK_TRUE, UINT64_MAX ) )
726 {
727 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
728 }
729 if ( VkResult result = vkResetFences ( mVulkanRenderer.GetDevice(), 1,
730 &mVkFence ) )
731 {
732 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
733 }
734 if ( VkResult result = vkAcquireNextImageKHR (
735 mVulkanRenderer.GetDevice(),
736 mVkSwapchainKHR,
737 UINT64_MAX,
738 mVkAcquireSemaphore,
739 VK_NULL_HANDLE,
740 const_cast<uint32_t * > ( &mActiveImageIndex ) ) )
741 {
742 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
743 }
744 VkCommandBufferBeginInfo command_buffer_begin_info{};
745 command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
746 command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
747 vkResetCommandPool ( mVulkanRenderer.GetDevice(), mVkCommandPool, 0 );
748 if ( VkResult result = vkBeginCommandBuffer ( mVkCommandBuffer, &command_buffer_begin_info ) )
749 {
750 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " Error Code: " << result << " at " << __func__ << " line " << __LINE__ << " " << std::endl;
751 }
752
753 vkCmdSetViewport ( mVkCommandBuffer, 0, 1, &mVkViewport );
754 vkCmdSetScissor ( mVkCommandBuffer, 0, 1, &mVkScissor );
755
756 /* [0] is color, [1] is depth/stencil.*/
758 std::array<VkClearValue, 2> clear_values{ { { {{0}} }, { {{0}} } } };
759 clear_values[0].color.float32[0] = 0.5f;
760 clear_values[0].color.float32[1] = 0.5f;
761 clear_values[0].color.float32[2] = 0.5f;
762 clear_values[0].color.float32[3] = 0.0f;
763 clear_values[1].depthStencil.depth = 1.0f;
764 clear_values[1].depthStencil.stencil = 0;
765
766 VkRenderPassBeginInfo render_pass_begin_info{};
767 render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
768 render_pass_begin_info.renderPass = mVkRenderPass;
769 render_pass_begin_info.framebuffer = mVkFramebuffers[mActiveImageIndex];
770 render_pass_begin_info.renderArea = mVkScissor;
771 render_pass_begin_info.clearValueCount = static_cast<uint32_t> ( clear_values.size() );
772 render_pass_begin_info.pClearValues = clear_values.data();
773 vkCmdBeginRenderPass ( mVkCommandBuffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE );
774 }
775
777 {
778 vkCmdEndRenderPass ( mVkCommandBuffer );
779 if ( VkResult result = vkEndCommandBuffer ( mVkCommandBuffer ) )
780 {
781 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
782 }
783 VkSubmitInfo submit_info{};
784 VkPipelineStageFlags wait_stages{ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
785 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
786 submit_info.waitSemaphoreCount = 1;
787 submit_info.pWaitSemaphores = &mVkAcquireSemaphore;
788 submit_info.pWaitDstStageMask = &wait_stages;
789 submit_info.commandBufferCount = 1;
790 submit_info.pCommandBuffers = &mVkCommandBuffer;
791 submit_info.signalSemaphoreCount = 1;
792 submit_info.pSignalSemaphores = &mVkSubmitSemaphores[mActiveImageIndex];
793 if ( VkResult result = vkQueueSubmit ( mVulkanRenderer.GetQueue(), 1, &submit_info, mVkFence ) )
794 {
795 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
796 }
797 std::array<VkResult, 1> result_array{ { VkResult::VK_SUCCESS } };
798 VkPresentInfoKHR present_info{};
799 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
800 present_info.waitSemaphoreCount = 1;
801 present_info.pWaitSemaphores = &mVkSubmitSemaphores[mActiveImageIndex];
802 present_info.swapchainCount = 1;
803 present_info.pSwapchains = &mVkSwapchainKHR;
804 present_info.pImageIndices = &mActiveImageIndex;
805 present_info.pResults = result_array.data();
806 if ( VkResult result = vkQueuePresentKHR ( mVulkanRenderer.GetQueue(), &present_info ) )
807 {
808 std::cout << LogLevel::Error << GetVulkanResultString ( result ) << " " << __func__ << " " << __LINE__ << " " << std::endl;
809 }
810 mMemoryPoolBuffer.Reset();
811 }
812
813 static const std::unordered_map<Topology, VkPrimitiveTopology> TopologyMap
814 {
815 {POINT_LIST, VK_PRIMITIVE_TOPOLOGY_POINT_LIST},
816 {LINE_STRIP, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
817 {LINE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST},
818 {TRIANGLE_STRIP, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
819 {TRIANGLE_FAN, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN},
820 {TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST},
821 {LINE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY},
822 {LINE_STRIP_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY},
823 {TRIANGLE_LIST_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY},
824 {TRIANGLE_STRIP_WITH_ADJACENCY, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY},
825 {PATCH_LIST, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST}
826 };
827
828 void VulkanWindow::Render ( const Matrix4x4& aModelMatrix,
829 const Mesh& aMesh,
830 const Pipeline& aPipeline,
831 const Material* aMaterial,
832 const BufferAccessor* aSkeleton,
833 Topology aTopology,
834 uint32_t aVertexStart,
835 uint32_t aVertexCount,
836 uint32_t aInstanceCount,
837 uint32_t aFirstInstance ) const
838 {
839 const VulkanPipeline* pipeline = mVulkanRenderer.GetVulkanPipeline ( aPipeline );
840 vkCmdBindPipeline ( mVkCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetVkPipeline() );
841 vkCmdSetPrimitiveTopology ( mVkCommandBuffer, TopologyMap.at ( aTopology ) );
842
843
844 if ( uint32_t matrix_set_index = pipeline->GetDescriptorSetIndex ( Mesh::BindingLocations::MATRICES ); matrix_set_index != std::numeric_limits<uint32_t>::max() )
845 {
846 vkCmdBindDescriptorSets ( GetCommandBuffer(),
847 VK_PIPELINE_BIND_POINT_GRAPHICS,
848 pipeline->GetPipelineLayout(),
849 matrix_set_index,
850 1,
851 &mMatricesDescriptorSet, 0, nullptr );
852 }
853
854 if ( const VkPushConstantRange& push_constant_model_matrix = pipeline->GetPushConstantModelMatrix() ; push_constant_model_matrix.size != 0 )
855 {
856 vkCmdPushConstants ( mVkCommandBuffer,
857 pipeline->GetPipelineLayout(),
858 push_constant_model_matrix.stageFlags,
859 push_constant_model_matrix.offset, push_constant_model_matrix.size,
860 aModelMatrix.GetMatrix4x4() );
861 }
862 if ( aMaterial != nullptr )
863 {
864 mVulkanRenderer.GetVulkanMaterial ( *aMaterial )->Bind ( mVkCommandBuffer, *pipeline );
865 }
866 if ( aSkeleton != nullptr )
867 {
868 const VulkanMemoryPoolBuffer* memory_pool_buffer =
869 reinterpret_cast<const VulkanMemoryPoolBuffer*> ( aSkeleton->GetMemoryPoolBuffer() );
870 uint32_t offset = static_cast<uint32_t> ( aSkeleton->GetOffset() );
871 if ( uint32_t skeleton_set_index = pipeline->GetDescriptorSetIndex ( Mesh::BindingLocations::SKELETON ); skeleton_set_index != std::numeric_limits<uint32_t>::max() )
872 {
873 vkCmdBindDescriptorSets ( GetCommandBuffer(),
874 VK_PIPELINE_BIND_POINT_GRAPHICS,
875 pipeline->GetPipelineLayout(),
876 skeleton_set_index,
877 1,
878 &memory_pool_buffer->GetDescriptorSet(), 1, &offset );
879 }
880 }
881 mVulkanRenderer.GetVulkanMesh ( aMesh )->Bind ( mVkCommandBuffer );
882 if ( aMesh.GetIndexCount() )
883 {
884 vkCmdDrawIndexed (
885 mVkCommandBuffer,
886 ( aVertexCount != 0xffffffff ) ? aVertexCount : aMesh.GetIndexCount(),
887 aInstanceCount,
888 aVertexStart,
889 0,
890 aFirstInstance );
891 }
892 else
893 {
894 vkCmdDraw (
895 mVkCommandBuffer,
896 ( aVertexCount != 0xffffffff ) ? aVertexCount : aMesh.GetVertexCount(),
897 aInstanceCount,
898 aVertexStart,
899 aFirstInstance );
900 }
901 }
902
903 void VulkanWindow::FinalizeSurface()
904 {
905 if ( mVkSurfaceKHR != VK_NULL_HANDLE )
906 {
907 vkDestroySurfaceKHR ( mVulkanRenderer.GetInstance(), mVkSurfaceKHR, nullptr );
908 mVkSurfaceKHR = VK_NULL_HANDLE;
909 }
910 }
911
912 void VulkanWindow::FinalizeSwapchain()
913 {
914 if ( mVkSwapchainKHR != VK_NULL_HANDLE )
915 {
916 vkDestroySwapchainKHR ( mVulkanRenderer.GetDevice(), mVkSwapchainKHR, nullptr );
917 mVkSwapchainKHR = VK_NULL_HANDLE;
918 }
919 if ( mVkAcquireSemaphore != VK_NULL_HANDLE )
920 {
921 vkDestroySemaphore ( mVulkanRenderer.GetDevice(), mVkAcquireSemaphore, nullptr );
922 std::cout << LogLevel::Debug << "Destroyed Acquire Semaphore " << std::hex << mVkAcquireSemaphore << std::endl;
923 mVkAcquireSemaphore = VK_NULL_HANDLE;
924 }
925 for ( auto& i : mVkSubmitSemaphores )
926 {
927 if ( i != VK_NULL_HANDLE )
928 {
929 vkDestroySemaphore ( mVulkanRenderer.GetDevice(), i, nullptr );
930 std::cout << LogLevel::Debug << "Destroyed Submit Semaphore " << std::hex << i << std::endl;
931 }
932 }
933 mVkSubmitSemaphores.clear();
934 if ( mVkFence != VK_NULL_HANDLE )
935 {
936 vkDestroyFence ( mVulkanRenderer.GetDevice(), mVkFence, nullptr );
937 mVkFence = VK_NULL_HANDLE;
938 }
939 }
940
941 void VulkanWindow::FinalizeImageViews()
942 {
943 for ( auto& i : mVkSwapchainImageViews )
944 {
945 if ( i != VK_NULL_HANDLE )
946 {
947 vkDestroyImageView ( mVulkanRenderer.GetDevice(), i, nullptr );
948 i = VK_NULL_HANDLE;
949 }
950 }
951 }
952
953 void VulkanWindow::FinalizeDepthStencil()
954 {
955 if ( mVkDepthStencilImageView != VK_NULL_HANDLE )
956 {
957 vkDestroyImageView ( mVulkanRenderer.GetDevice(), mVkDepthStencilImageView, nullptr );
958 mVkDepthStencilImageView = VK_NULL_HANDLE;
959 }
960 if ( mVkDepthStencilImage != VK_NULL_HANDLE )
961 {
962 vkDestroyImage ( mVulkanRenderer.GetDevice(), mVkDepthStencilImage, nullptr );
963 mVkDepthStencilImage = VK_NULL_HANDLE;
964 }
965 if ( mVkDepthStencilImageMemory != VK_NULL_HANDLE )
966 {
967 vkFreeMemory ( mVulkanRenderer.GetDevice(), mVkDepthStencilImageMemory, nullptr );
968 mVkDepthStencilImageMemory = VK_NULL_HANDLE;
969 }
970 }
971
972 void VulkanWindow::FinalizeFrameBuffers()
973 {
974 for ( auto& i : mVkFramebuffers )
975 {
976 if ( i != VK_NULL_HANDLE )
977 {
978 vkDestroyFramebuffer ( mVulkanRenderer.GetDevice(), i, nullptr );
979 i = VK_NULL_HANDLE;
980 }
981 }
982 }
983
985 {
986 return mMemoryPoolBuffer.Allocate ( aSize );
987 }
988
989 VkRenderPass VulkanWindow::GetRenderPass() const
990 {
991 return mVkRenderPass;
992 }
993
994 VkCommandBuffer VulkanWindow::GetCommandBuffer() const
995 {
996 return mVkCommandBuffer;
997 }
998}
Header for the axis aligned bounding box class.
Header for the frustum class.
Defines log severity levels and stream output for the AeonGames engine.
Header for the Scene class.
Provides access to a region within a memory pool buffer.
DLL const MemoryPoolBuffer * GetMemoryPoolBuffer() const
Get the underlying memory pool buffer.
DLL size_t GetOffset() const
Get the byte offset of this accessor within the memory pool buffer.
View frustum defined by six clipping planes, extracted from a projection (or view-projection) matrix.
Definition Frustum.hpp:35
Represents a surface material with uniform properties and texture samplers.
Definition Material.hpp:38
4 by 4 matrix in colum mayor order.
Definition Matrix4x4.hpp:35
DLL const float *const GetMatrix4x4() const
Get a pointer to the internal matrix data.
Definition Matrix4x4.cpp:53
Represents a polygon mesh with vertex attributes and index data.
Definition Mesh.hpp:31
@ MATRICES
Matrices binding.
Definition Mesh.hpp:71
@ SKELETON
Skeleton binding.
Definition Mesh.hpp:73
DLL uint32_t GetIndexCount() const
Get the total number of indices.
Definition Mesh.cpp:48
DLL uint32_t GetVertexCount() const
Get the total number of vertices.
Definition Mesh.cpp:53
Rendering pipeline resource.
Definition Pipeline.hpp:122
Vulkan memory pool buffer for transient per-frame uniform allocations.
const VkDescriptorSet & GetDescriptorSet() const
Get the Vulkan descriptor set for this pool buffer.
Vulkan graphics pipeline with descriptor set and push constant reflection.
uint32_t GetDescriptorSetIndex(uint32_t hash) const
Get the descriptor set index for a given hash.
const VkPipeline GetVkPipeline() const
Get the Vulkan pipeline handle.
const VkPushConstantRange & GetPushConstantModelMatrix() const
Get the push constant range used for the model matrix.
const VkPipelineLayout GetPipelineLayout() const
Get the Vulkan pipeline layout handle.
Vulkan rendering backend implementing the Renderer interface.
VkRenderPass GetRenderPass() const
Get the Vulkan render pass for this window.
void SetViewMatrix(const Matrix4x4 &aMatrix)
Set the view matrix for this window.
VulkanWindow(VulkanRenderer &aVulkanRenderer, void *aWindowId)
Construct from a renderer and native window handle.
BufferAccessor AllocateSingleFrameUniformMemory(size_t aSize)
Allocate transient uniform memory for the current frame.
void EndRender()
End the current frame, submit commands, and present.
const Matrix4x4 & GetProjectionMatrix() const
Get the current projection matrix.
VkCommandBuffer GetCommandBuffer() const
Get the current command buffer being recorded.
void ResizeViewport(int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight)
Resize the rendering viewport.
void Render(const Matrix4x4 &aModelMatrix, const Mesh &aMesh, const Pipeline &aPipeline, const Material *aMaterial=nullptr, const BufferAccessor *aSkeleton=nullptr, Topology aTopology=Topology::TRIANGLE_LIST, uint32_t aVertexStart=0, uint32_t aVertexCount=0xffffffff, uint32_t aInstanceCount=1, uint32_t aFirstInstance=0) const
Render a mesh with the given pipeline, material, and transform.
const Frustum & GetFrustum() const
Get the view frustum derived from the current matrices.
const Matrix4x4 & GetViewMatrix() const
Get the current view matrix.
void SetProjectionMatrix(const Matrix4x4 &aMatrix)
Set the projection matrix for this window.
<- This is here just for the literals
Definition AABB.hpp:31
VkDescriptorPool CreateDescriptorPool(const VkDevice &aVkDevice, const std::vector< VkDescriptorPoolSize > &aVkDescriptorPoolSizes)
Create a Vulkan descriptor pool from the given pool sizes.
void DestroyDescriptorPool(const VkDevice &aVkDevice, VkDescriptorPool aVkDescriptorPool)
Destroy a Vulkan descriptor pool.
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
Topology
Primitive topology types for rendering.
Definition Pipeline.hpp:38
@ TRIANGLE_STRIP
Connected triangle strip.
Definition Pipeline.hpp:43
@ PATCH_LIST
Patch list for tessellation.
Definition Pipeline.hpp:50
@ LINE_LIST_WITH_ADJACENCY
Line list with adjacency information.
Definition Pipeline.hpp:46
@ TRIANGLE_LIST_WITH_ADJACENCY
Triangle list with adjacency information.
Definition Pipeline.hpp:48
@ POINT_LIST
List of individual points.
Definition Pipeline.hpp:40
@ LINE_LIST
Pairs of vertices forming individual lines.
Definition Pipeline.hpp:42
@ TRIANGLE_LIST
Independent triangles.
Definition Pipeline.hpp:45
@ TRIANGLE_STRIP_WITH_ADJACENCY
Triangle strip with adjacency information.
Definition Pipeline.hpp:49
@ TRIANGLE_FAN
Triangles sharing a common vertex.
Definition Pipeline.hpp:44
@ LINE_STRIP_WITH_ADJACENCY
Line strip with adjacency information.
Definition Pipeline.hpp:47
@ Info
General informational messages.
Definition LogLevel.hpp:30
@ Error
Error conditions.
Definition LogLevel.hpp:33
@ Debug
Detailed diagnostic information.
Definition LogLevel.hpp:29
VkDescriptorSet CreateDescriptorSet(const VkDevice &aVkDevice, const VkDescriptorPool &aVkDescriptorPool, const VkDescriptorSetLayout &aVkDescriptorSetLayout, uint32_t aDescriptorSetCount)
Allocate a Vulkan descriptor set from the given pool and layout.
STL namespace.