SwapChain
Bigfoot / Sonarqube (game) (push) Skipped
Bigfoot / Sonarqube (toolmode) (push) Skipped
Bigfoot / Build & Test Debug with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m8s
Bigfoot / Build & Test Debug with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m12s
Bigfoot / Build & Test Debug with clang (Unity Build: ON, Variant: game) (push) Successful in 42s
Bigfoot / Build & Test Debug with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 46s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 2m17s
Bigfoot / Build & Test Release with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m8s
Bigfoot / Build & Test Release with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m30s
Bigfoot / Build & Test Release with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 1m47s
Bigfoot / Build & Test Release with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m28s
Bigfoot / Build & Test Release with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m35s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: ON, Variant: game) (push) Successful in 46s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 49s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m55s
Bigfoot / Clang Format Checks (push) Successful in 10s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 2m17s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m42s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m50s
Bigfoot / Build & Test Release with clang (Unity Build: ON, Variant: game) (push) Successful in 51s
Bigfoot / Build & Test Release with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 1m11s
Bigfoot / Build & Test Release with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m49s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m16s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m18s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 2m23s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 2m24s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m43s
Bigfoot / Sonarqube (game) (push) Skipped
Bigfoot / Sonarqube (toolmode) (push) Skipped
Bigfoot / Build & Test Debug with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m8s
Bigfoot / Build & Test Debug with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m12s
Bigfoot / Build & Test Debug with clang (Unity Build: ON, Variant: game) (push) Successful in 42s
Bigfoot / Build & Test Debug with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 46s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 2m17s
Bigfoot / Build & Test Release with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m8s
Bigfoot / Build & Test Release with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m30s
Bigfoot / Build & Test Release with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 1m47s
Bigfoot / Build & Test Release with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m28s
Bigfoot / Build & Test Release with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m35s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: ON, Variant: game) (push) Successful in 46s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 49s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m55s
Bigfoot / Clang Format Checks (push) Successful in 10s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 2m17s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m42s
Bigfoot / Build & Test Debug with clang_asan (Unity Build: ON, Variant: toolmode) (push) Successful in 1m50s
Bigfoot / Build & Test Release with clang (Unity Build: ON, Variant: game) (push) Successful in 51s
Bigfoot / Build & Test Release with clang (Unity Build: ON, Variant: toolmode) (push) Successful in 1m11s
Bigfoot / Build & Test Release with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m49s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: OFF, Variant: game) (push) Successful in 1m16s
Bigfoot / Build & Test RelWithDebInfo with clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 1m18s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 2m23s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: OFF, Variant: toolmode) (push) Successful in 2m24s
Bigfoot / Build & Test RelWithDebInfo with clang_asan (Unity Build: ON, Variant: game) (push) Successful in 1m43s
This commit is contained in:
@@ -32,6 +32,13 @@ GraphicsContext::GraphicsContext(const GraphicsContextCreateInfo& p_createInfo)
|
||||
m_device != nullptr,
|
||||
"No graphics device registered for GraphicsAPI '{}'",
|
||||
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||
|
||||
const SwapchainCreateInfo swapchainCreateInfo {m_device.get(), m_surface.get(), p_createInfo.m_extent};
|
||||
m_swapchain = g_graphicsSwapchainFactory->Create(p_createInfo.m_api, swapchainCreateInfo);
|
||||
CRITICAL_ASSERT(GraphicsCoreAssertHandler,
|
||||
m_swapchain != nullptr,
|
||||
"No graphics swapchain registered for GraphicsAPI '{}'",
|
||||
EnumNameGraphicsAPI(p_createInfo.m_api));
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
@@ -54,4 +61,11 @@ GraphicsDevice& GraphicsContext::GetDevice() const
|
||||
{
|
||||
return *m_device;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
GraphicsSwapchain& GraphicsContext::GetSwapchain() const
|
||||
{
|
||||
return *m_swapchain;
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <GraphicsInterface/GraphicsDevice.hpp>
|
||||
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||
#include <GraphicsInterface/GraphicsSurface.hpp>
|
||||
#include <GraphicsInterface/GraphicsSwapchain.hpp>
|
||||
|
||||
#include <Utils/Version.hpp>
|
||||
|
||||
@@ -16,6 +17,7 @@
|
||||
|
||||
#include <EASTL/string_view.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
@@ -45,6 +47,11 @@ struct GraphicsContextCreateInfo
|
||||
* Pick a specific physical device by name.
|
||||
*/
|
||||
eastl::string_view m_deviceNameHint;
|
||||
|
||||
/**
|
||||
* The desired size of the swapchain images.
|
||||
*/
|
||||
glm::uvec2 m_extent = {};
|
||||
};
|
||||
|
||||
class GraphicsContext
|
||||
@@ -87,6 +94,14 @@ class GraphicsContext
|
||||
[[nodiscard]]
|
||||
GraphicsDevice& GetDevice() const;
|
||||
|
||||
/**
|
||||
* Get the graphics swapchain
|
||||
*
|
||||
* \return The graphics swapchain
|
||||
*/
|
||||
[[nodiscard]]
|
||||
GraphicsSwapchain& GetSwapchain() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The graphics instance.
|
||||
@@ -102,6 +117,11 @@ class GraphicsContext
|
||||
* The graphics device.
|
||||
*/
|
||||
eastl::unique_ptr<GraphicsDevice> m_device;
|
||||
|
||||
/**
|
||||
* The graphics swapchain.
|
||||
*/
|
||||
eastl::unique_ptr<GraphicsSwapchain> m_swapchain;
|
||||
};
|
||||
} // namespace Bigfoot
|
||||
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*********************************************************************
|
||||
* \file GraphicsSwapchain.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date September 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSWAPCHAIN_HPP
|
||||
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSSWAPCHAIN_HPP
|
||||
#include <GraphicsInterface/GraphicsDevice.hpp>
|
||||
#include <GraphicsInterface/GraphicsImage.hpp>
|
||||
#include <GraphicsInterface/GraphicsInstance.hpp>
|
||||
#include <GraphicsInterface/GraphicsSurface.hpp>
|
||||
|
||||
#include <Utils/Factory.hpp>
|
||||
#include <Utils/LazyGlobal.hpp>
|
||||
|
||||
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
|
||||
|
||||
#include <EASTL/functional.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Bigfoot
|
||||
{
|
||||
struct SwapchainCreateInfo
|
||||
{
|
||||
/**
|
||||
* The device to create the swapchain from. Must be able to present to m_surface.
|
||||
*/
|
||||
const GraphicsDevice* m_device = nullptr;
|
||||
|
||||
/**
|
||||
* The surface the swapchain will present to.
|
||||
*/
|
||||
const GraphicsSurface* m_surface = nullptr;
|
||||
|
||||
/**
|
||||
* The desired size of the swapchain images.
|
||||
*/
|
||||
glm::uvec2 m_extent = {};
|
||||
};
|
||||
|
||||
class GraphicsSwapchain
|
||||
{
|
||||
public:
|
||||
virtual ~GraphicsSwapchain() = default;
|
||||
|
||||
/**
|
||||
* Get the number of images owned by the swapchain
|
||||
*
|
||||
* \return The image count
|
||||
*/
|
||||
[[nodiscard]]
|
||||
virtual std::uint32_t GetImageCount() const = 0;
|
||||
|
||||
/**
|
||||
* Get one of the images owned by the swapchain
|
||||
*
|
||||
* \param p_index The index of the image to get.
|
||||
* \return The image
|
||||
*/
|
||||
[[nodiscard]]
|
||||
virtual const GraphicsImage& GetImage(std::uint32_t p_index) const = 0;
|
||||
|
||||
GraphicsSwapchain(const GraphicsSwapchain& p_swapchain) = delete;
|
||||
GraphicsSwapchain(GraphicsSwapchain&& p_swapchain) = delete;
|
||||
|
||||
GraphicsSwapchain& operator=(const GraphicsSwapchain& p_swapchain) = delete;
|
||||
GraphicsSwapchain& operator=(GraphicsSwapchain&& p_swapchain) = delete;
|
||||
|
||||
protected:
|
||||
GraphicsSwapchain() = default;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
using GraphicsSwapchainFactory =
|
||||
Factory<GraphicsSwapchain,
|
||||
GraphicsAPI,
|
||||
eastl::function<eastl::unique_ptr<GraphicsSwapchain>(const SwapchainCreateInfo&)>>;
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
inline LazyGlobal<GraphicsSwapchainFactory> g_graphicsSwapchainFactory;
|
||||
} // namespace Bigfoot
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
/*********************************************************************
|
||||
* \file VulkanSwapchain.hpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date September 2026
|
||||
*********************************************************************/
|
||||
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANSWAPCHAIN_HPP
|
||||
#define BIGFOOT_GRAPHICSVULKAN_VULKANSWAPCHAIN_HPP
|
||||
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||
#include <GraphicsVulkan/VulkanImage.hpp>
|
||||
#include <GraphicsVulkan/VulkanInclude.hpp>
|
||||
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||
|
||||
#include <GraphicsInterface/GraphicsSwapchain.hpp>
|
||||
|
||||
#include <EASTL/span.h>
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Bigfoot::Vulkan
|
||||
{
|
||||
class VulkanSwapchain final: public GraphicsSwapchain
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* \param p_device The device to create the swapchain from.
|
||||
* \param p_surface The surface the swapchain will present to.
|
||||
* \param p_extent The desired size of the swapchain images.
|
||||
*/
|
||||
VulkanSwapchain(const VulkanDevice& p_device, const VulkanSurface& p_surface, glm::uvec2 p_extent);
|
||||
|
||||
~VulkanSwapchain() override;
|
||||
|
||||
/**
|
||||
* Get the number of images owned by the swapchain
|
||||
*
|
||||
* \return The image count
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::uint32_t GetImageCount() const override;
|
||||
|
||||
/**
|
||||
* Get one of the images owned by the swapchain
|
||||
*
|
||||
* \param p_index The index of the image to get. Must be less than GetImageCount()
|
||||
* \return The image
|
||||
*/
|
||||
[[nodiscard]]
|
||||
const GraphicsImage& GetImage(std::uint32_t p_index) const override;
|
||||
|
||||
/**
|
||||
* Get the underlying Vulkan swapchain handle
|
||||
*
|
||||
* \return The vk::SwapchainKHR handle
|
||||
*/
|
||||
[[nodiscard]]
|
||||
vk::SwapchainKHR GetHandle() const;
|
||||
|
||||
/**
|
||||
* Get the swapchain images
|
||||
*
|
||||
* \return The images owned by the swapchain
|
||||
*/
|
||||
[[nodiscard]]
|
||||
eastl::span<const VulkanImage> GetImages() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The device the swapchain was created from
|
||||
*/
|
||||
const VulkanDevice& m_device;
|
||||
|
||||
/**
|
||||
* The swapchain
|
||||
*/
|
||||
vk::SwapchainKHR m_swapchain;
|
||||
|
||||
/**
|
||||
* The images owned by the swapchain
|
||||
*/
|
||||
eastl::vector<VulkanImage> m_images;
|
||||
};
|
||||
} // namespace Bigfoot::Vulkan
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
/*********************************************************************
|
||||
* \file VulkanSwapchain.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date September 2026
|
||||
*********************************************************************/
|
||||
#include <GraphicsVulkan/VulkanSwapchain.hpp>
|
||||
|
||||
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
|
||||
#include <GraphicsVulkan/VulkanFormatters.hpp>
|
||||
#include <GraphicsVulkan/VulkanPixelFormat.hpp>
|
||||
#include <GraphicsVulkan/VulkanQueue.hpp>
|
||||
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace Bigfoot::Vulkan
|
||||
{
|
||||
[[nodiscard]]
|
||||
vk::SurfaceFormatKHR SelectSurfaceFormat(const std::span<const vk::SurfaceFormatKHR> p_formats)
|
||||
{
|
||||
const auto it = eastl::find_if(p_formats.begin(),
|
||||
p_formats.end(),
|
||||
[](const vk::SurfaceFormatKHR& p_format)
|
||||
{
|
||||
return p_format.format == vk::Format::eB8G8R8A8Srgb &&
|
||||
p_format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
|
||||
});
|
||||
|
||||
return it != p_formats.end() ? *it : p_formats.front();
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
[[nodiscard]]
|
||||
vk::PresentModeKHR SelectPresentMode(const std::span<const vk::PresentModeKHR> p_presentModes)
|
||||
{
|
||||
const auto it = eastl::find(p_presentModes.begin(), p_presentModes.end(), vk::PresentModeKHR::eMailbox);
|
||||
|
||||
// eFifo is guaranteed by the spec to always be supported
|
||||
return it != p_presentModes.end() ? *it : vk::PresentModeKHR::eFifo;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
[[nodiscard]]
|
||||
vk::Extent2D SelectExtent(const vk::SurfaceCapabilitiesKHR& p_capabilities, const glm::uvec2 p_extent)
|
||||
{
|
||||
constexpr std::uint32_t undefinedExtent = std::numeric_limits<std::uint32_t>::max();
|
||||
if (p_capabilities.currentExtent.width != undefinedExtent)
|
||||
{
|
||||
return p_capabilities.currentExtent;
|
||||
}
|
||||
|
||||
return {eastl::clamp(p_extent.x, p_capabilities.minImageExtent.width, p_capabilities.maxImageExtent.width),
|
||||
eastl::clamp(p_extent.y, p_capabilities.minImageExtent.height, p_capabilities.maxImageExtent.height)};
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
[[nodiscard]]
|
||||
vk::CompositeAlphaFlagBitsKHR SelectCompositeAlpha(const vk::CompositeAlphaFlagsKHR p_supportedCompositeAlpha)
|
||||
{
|
||||
for (const vk::CompositeAlphaFlagBitsKHR candidate: {vk::CompositeAlphaFlagBitsKHR::eOpaque,
|
||||
vk::CompositeAlphaFlagBitsKHR::ePreMultiplied,
|
||||
vk::CompositeAlphaFlagBitsKHR::ePostMultiplied,
|
||||
vk::CompositeAlphaFlagBitsKHR::eInherit})
|
||||
{
|
||||
if (p_supportedCompositeAlpha & candidate)
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return vk::CompositeAlphaFlagBitsKHR::eOpaque;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
VulkanSwapchain::VulkanSwapchain(const VulkanDevice& p_device,
|
||||
const VulkanSurface& p_surface,
|
||||
const glm::uvec2 p_extent):
|
||||
m_device(p_device)
|
||||
{
|
||||
const vk::PhysicalDevice physicalDevice = p_device.GetPhysicalDeviceHandle();
|
||||
const vk::SurfaceKHR surface = p_surface.GetHandle();
|
||||
|
||||
const vk::ResultValue<vk::SurfaceCapabilitiesKHR> capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
capabilities.result == vk::Result::eSuccess,
|
||||
"({}) Failed to get Vulkan surface capabilities",
|
||||
capabilities.result);
|
||||
|
||||
const vk::ResultValue<std::vector<vk::SurfaceFormatKHR>> formats = physicalDevice.getSurfaceFormatsKHR(surface);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
formats.result == vk::Result::eSuccess && !formats.value.empty(),
|
||||
"({}) Failed to get Vulkan surface formats",
|
||||
formats.result);
|
||||
|
||||
const vk::ResultValue<std::vector<vk::PresentModeKHR>> presentModes = physicalDevice.getSurfacePresentModesKHR(
|
||||
surface);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
presentModes.result == vk::Result::eSuccess && !presentModes.value.empty(),
|
||||
"({}) Failed to get Vulkan surface present modes",
|
||||
presentModes.result);
|
||||
|
||||
const vk::SurfaceFormatKHR surfaceFormat = SelectSurfaceFormat(formats.value);
|
||||
const vk::PresentModeKHR presentMode = SelectPresentMode(presentModes.value);
|
||||
const vk::Extent2D extent = SelectExtent(capabilities.value, p_extent);
|
||||
|
||||
std::uint32_t imageCount = capabilities.value.minImageCount + 1;
|
||||
if (capabilities.value.maxImageCount > 0)
|
||||
{
|
||||
imageCount = eastl::min(imageCount, capabilities.value.maxImageCount);
|
||||
}
|
||||
|
||||
const auto* const graphicsQueue = static_cast<const VulkanQueue*>(p_device.GetQueue(GraphicsQueueType::Graphics));
|
||||
const auto* const presentQueue = static_cast<const VulkanQueue*>(p_device.GetQueue(GraphicsQueueType::Present));
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
graphicsQueue != nullptr && presentQueue != nullptr,
|
||||
"Cannot create a swapchain on a device with no graphics or present queue");
|
||||
|
||||
const bool sameQueueFamily = graphicsQueue->GetFamilyIndex() == presentQueue->GetFamilyIndex();
|
||||
|
||||
eastl::vector<std::uint32_t> queueFamilyIndices;
|
||||
if (!sameQueueFamily)
|
||||
{
|
||||
queueFamilyIndices = {graphicsQueue->GetFamilyIndex(), presentQueue->GetFamilyIndex()};
|
||||
}
|
||||
|
||||
const vk::SwapchainCreateInfoKHR swapchainCreateInfo {
|
||||
{},
|
||||
surface,
|
||||
imageCount,
|
||||
surfaceFormat.format,
|
||||
surfaceFormat.colorSpace,
|
||||
extent,
|
||||
1,
|
||||
vk::ImageUsageFlagBits::eColorAttachment,
|
||||
sameQueueFamily ? vk::SharingMode::eExclusive : vk::SharingMode::eConcurrent,
|
||||
queueFamilyIndices,
|
||||
capabilities.value.currentTransform,
|
||||
SelectCompositeAlpha(capabilities.value.supportedCompositeAlpha),
|
||||
presentMode,
|
||||
VK_TRUE};
|
||||
|
||||
const vk::ResultValue<vk::SwapchainKHR> swapchain = p_device.GetHandle().createSwapchainKHR(swapchainCreateInfo);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
swapchain.result == vk::Result::eSuccess,
|
||||
"({}) Failed to create Vulkan swapchain",
|
||||
swapchain.result);
|
||||
m_swapchain = swapchain.value;
|
||||
|
||||
const vk::ResultValue<std::vector<vk::Image>> images = p_device.GetHandle().getSwapchainImagesKHR(m_swapchain);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
images.result == vk::Result::eSuccess,
|
||||
"({}) Failed to get Vulkan swapchain images",
|
||||
images.result);
|
||||
const PixelFormat imageFormat = FromVulkanFormat(surfaceFormat.format);
|
||||
m_images.reserve(images.value.size());
|
||||
for (const vk::Image image: images.value)
|
||||
{
|
||||
m_images.emplace_back(image, imageFormat, extent);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
VulkanSwapchain::~VulkanSwapchain()
|
||||
{
|
||||
m_device.GetHandle().destroySwapchainKHR(m_swapchain);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
std::uint32_t VulkanSwapchain::GetImageCount() const
|
||||
{
|
||||
return static_cast<std::uint32_t>(m_images.size());
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
const GraphicsImage& VulkanSwapchain::GetImage(const std::uint32_t p_index) const
|
||||
{
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler,
|
||||
p_index < m_images.size(),
|
||||
"Swapchain image index {} out of range (swapchain has {} images)",
|
||||
p_index,
|
||||
m_images.size());
|
||||
return m_images[p_index];
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
vk::SwapchainKHR VulkanSwapchain::GetHandle() const
|
||||
{
|
||||
return m_swapchain;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
eastl::span<const VulkanImage> VulkanSwapchain::GetImages() const
|
||||
{
|
||||
return {m_images.data(), m_images.size()};
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
[[nodiscard]]
|
||||
eastl::unique_ptr<GraphicsSwapchain> CreateVulkanSwapchain(const SwapchainCreateInfo& p_createInfo)
|
||||
{
|
||||
return eastl::make_unique<VulkanSwapchain>(static_cast<const VulkanDevice&>(*p_createInfo.m_device),
|
||||
static_cast<const VulkanSurface&>(*p_createInfo.m_surface),
|
||||
p_createInfo.m_extent);
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
[[nodiscard]]
|
||||
bool RegisterVulkanSwapchainFactory()
|
||||
{
|
||||
const bool inserted = g_graphicsSwapchainFactory->Register(GraphicsAPI::Vulkan, &CreateVulkanSwapchain);
|
||||
CRITICAL_ASSERT(GraphicsVulkanAssertHandler, inserted, "Failed to register the Vulkan graphics swapchain factory");
|
||||
return inserted;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
const bool g_vulkanSwapchainFactoryRegistered = RegisterVulkanSwapchainFactory();
|
||||
} // namespace Bigfoot::Vulkan
|
||||
@@ -20,12 +20,16 @@ class GraphicsContextFixture: public ::testing::Test
|
||||
{
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
m_window = SDL_CreateWindow("GraphicsContextTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||
{
|
||||
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||
m_window = SDL_CreateWindow("GraphicsContextTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||
}
|
||||
|
||||
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||
|
||||
m_createInfo.m_applicationName = "GraphicsContextTests";
|
||||
m_createInfo.m_applicationVersion = Version {1, 0, 0};
|
||||
m_createInfo.m_extent = {64, 64};
|
||||
#ifdef BIGFOOT_WINDOWS
|
||||
m_createInfo.m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||
@@ -50,7 +54,7 @@ class GraphicsContextFixture: public ::testing::Test
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(GraphicsContextFixture, Constructor_ShouldCreateAValidInstanceSurfaceAndDevice)
|
||||
TEST_F(GraphicsContextFixture, Constructor_ShouldCreateAValidContext)
|
||||
{
|
||||
const GraphicsContext context {m_createInfo};
|
||||
|
||||
@@ -58,5 +62,6 @@ TEST_F(GraphicsContextFixture, Constructor_ShouldCreateAValidInstanceSurfaceAndD
|
||||
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Compute), nullptr);
|
||||
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Transfer), nullptr);
|
||||
EXPECT_NE(context.GetDevice().GetQueue(GraphicsQueueType::Present), nullptr);
|
||||
EXPECT_GT(context.GetSwapchain().GetImageCount(), 0u);
|
||||
}
|
||||
} // namespace Bigfoot
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*********************************************************************
|
||||
* \file VulkanSwapchain.cpp
|
||||
*
|
||||
* \author Romain BOULLARD
|
||||
* \date September 2026
|
||||
*********************************************************************/
|
||||
#include <GraphicsVulkan/VulkanSwapchain.hpp>
|
||||
|
||||
#include <GraphicsVulkan/VulkanDevice.hpp>
|
||||
#include <GraphicsVulkan/VulkanImage.hpp>
|
||||
#include <GraphicsVulkan/VulkanInstance.hpp>
|
||||
#include <GraphicsVulkan/VulkanSurface.hpp>
|
||||
|
||||
#include <Utils/TargetMacros.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Bigfoot::Vulkan
|
||||
{
|
||||
class VulkanSwapchainFixture: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
{
|
||||
BIGFOOT_LSAN_ONLY(const __lsan::ScopedDisabler lsanDisabler;)
|
||||
m_window = SDL_CreateWindow("VulkanSwapchainTests", 64, 64, SDL_WINDOW_HIDDEN | SDL_WINDOW_VULKAN);
|
||||
}
|
||||
|
||||
const SDL_PropertiesID windowProperties = SDL_GetWindowProperties(m_window);
|
||||
|
||||
#ifdef BIGFOOT_WINDOWS
|
||||
m_surfaceCreateInfo.m_windowHandle = static_cast<HWND>(
|
||||
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr));
|
||||
m_surfaceCreateInfo.m_windowInstance = GetModuleHandle(nullptr);
|
||||
#elif defined BIGFOOT_LINUX
|
||||
m_surfaceCreateInfo.m_display = static_cast<wl_display*>(
|
||||
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr));
|
||||
m_surfaceCreateInfo.m_surface = static_cast<wl_surface*>(
|
||||
SDL_GetPointerProperty(windowProperties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
SDL_DestroyWindow(m_window);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
VulkanInstance m_instance {"VulkanSwapchainTests", Version {1, 0, 0}};
|
||||
SDL_Window* m_window = nullptr;
|
||||
SurfaceCreateInfo m_surfaceCreateInfo;
|
||||
};
|
||||
|
||||
/****************************************************************************************/
|
||||
|
||||
TEST_F(VulkanSwapchainFixture, Constructor_ShouldCreateAValidSwapchainWithAtLeastOneImage)
|
||||
{
|
||||
const VulkanSurface surface {m_instance, m_surfaceCreateInfo};
|
||||
const VulkanDevice device {m_instance, &surface, {}};
|
||||
|
||||
const VulkanSwapchain swapchain {device, surface, glm::uvec2 {64, 64}};
|
||||
|
||||
EXPECT_TRUE(swapchain.GetHandle());
|
||||
ASSERT_FALSE(swapchain.GetImages().empty());
|
||||
|
||||
const VulkanImage& image = swapchain.GetImages().front();
|
||||
EXPECT_TRUE(image.GetHandle());
|
||||
EXPECT_NE(image.GetFormat(), PixelFormat::Undefined);
|
||||
EXPECT_GT(image.GetExtent().x, 0u);
|
||||
EXPECT_GT(image.GetExtent().y, 0u);
|
||||
}
|
||||
} // namespace Bigfoot::Vulkan
|
||||
Reference in New Issue
Block a user