mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
Avoids assertions on Vulkan backend device creation in case of driver bugs.
This commit is contained in:
@@ -606,9 +606,11 @@ std::unique_ptr<CDevice> CDevice::Create(SDL_Window* window)
|
||||
device->m_RenderPassManager =
|
||||
std::make_unique<CRenderPassManager>(device.get());
|
||||
device->m_SamplerManager = std::make_unique<CSamplerManager>(device.get());
|
||||
device->m_SubmitScheduler =
|
||||
std::make_unique<CSubmitScheduler>(
|
||||
device.get(), device->m_GraphicsQueueFamilyIndex, device->m_GraphicsQueue);
|
||||
|
||||
device->m_SubmitScheduler = CSubmitScheduler::Create(
|
||||
device.get(), device->m_GraphicsQueueFamilyIndex, device->m_GraphicsQueue);
|
||||
if (!device->m_SubmitScheduler)
|
||||
return nullptr;
|
||||
|
||||
bool disableDescriptorIndexing = false;
|
||||
CFG_GET_VAL("renderer.backend.vulkan.disabledescriptorindexing", disableDescriptorIndexing);
|
||||
@@ -617,6 +619,10 @@ std::unique_ptr<CDevice> CDevice::Create(SDL_Window* window)
|
||||
std::make_unique<CDescriptorManager>(device.get(), useDescriptorIndexing);
|
||||
|
||||
device->RecreateSwapChain();
|
||||
// Currently we assume that we should have a valid swapchain on the device
|
||||
// creation.
|
||||
if (!device->m_SwapChain)
|
||||
return nullptr;
|
||||
|
||||
device->m_Name = choosenDevice.properties.deviceName;
|
||||
device->m_Version =
|
||||
@@ -936,7 +942,7 @@ void CDevice::SetObjectName(VkObjectType type, const uint64_t handle, const char
|
||||
|
||||
std::unique_ptr<CRingCommandContext> CDevice::CreateRingCommandContext(const size_t size)
|
||||
{
|
||||
return std::make_unique<CRingCommandContext>(
|
||||
return CRingCommandContext::Create(
|
||||
this, size, m_GraphicsQueueFamilyIndex, *m_SubmitScheduler);
|
||||
}
|
||||
|
||||
|
||||
@@ -318,8 +318,10 @@ std::unique_ptr<IDeviceCommandContext> CDeviceCommandContext::Create(CDevice* de
|
||||
deviceCommandContext->m_DebugScopedLabels = device->GetCapabilities().debugScopedLabels;
|
||||
deviceCommandContext->m_PrependCommandContext =
|
||||
device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
|
||||
ENSURE(deviceCommandContext->m_PrependCommandContext);
|
||||
deviceCommandContext->m_CommandContext =
|
||||
device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
|
||||
ENSURE(deviceCommandContext->m_CommandContext);
|
||||
|
||||
deviceCommandContext->m_VertexUploadRing = std::make_unique<CUploadRing>(
|
||||
device, IBuffer::Type::VERTEX, FRAME_INPLACE_BUFFER_INITIAL_SIZE);
|
||||
|
||||
@@ -49,31 +49,33 @@ constexpr uint32_t INVALID_OFFSET = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CRingCommandContext::CRingCommandContext(
|
||||
std::unique_ptr<CRingCommandContext> CRingCommandContext::Create(
|
||||
CDevice* device, const size_t size, const uint32_t queueFamilyIndex,
|
||||
CSubmitScheduler& submitScheduler)
|
||||
: m_Device(device), m_SubmitScheduler(submitScheduler)
|
||||
{
|
||||
ENSURE(m_Device);
|
||||
ENSURE(device);
|
||||
|
||||
m_OptimalBufferCopyOffsetAlignment = std::max(
|
||||
1u, static_cast<uint32_t>(m_Device->GetChoosenPhysicalDevice().properties.limits.optimalBufferCopyOffsetAlignment));
|
||||
std::unique_ptr<CRingCommandContext> ringCommandContext{
|
||||
new CRingCommandContext{device, submitScheduler}};
|
||||
|
||||
ringCommandContext->m_OptimalBufferCopyOffsetAlignment = std::max(
|
||||
1u, static_cast<uint32_t>(device->GetChoosenPhysicalDevice().properties.limits.optimalBufferCopyOffsetAlignment));
|
||||
// In case of small amount of host memory it's better to make uploading
|
||||
// slower rather than crashing due to OOM, because memory for a
|
||||
// staging buffer is allocated in the host memory.
|
||||
m_MaxStagingBufferCapacity =
|
||||
m_Device->GetChoosenPhysicalDevice().hostTotalMemory <= SMALL_HOST_TOTAL_MEMORY_THRESHOLD
|
||||
ringCommandContext->m_MaxStagingBufferCapacity =
|
||||
device->GetChoosenPhysicalDevice().hostTotalMemory <= SMALL_HOST_TOTAL_MEMORY_THRESHOLD
|
||||
? MAX_SMALL_STAGING_BUFFER_CAPACITY
|
||||
: MAX_STAGING_BUFFER_CAPACITY;
|
||||
|
||||
m_Ring.resize(size);
|
||||
for (RingItem& item : m_Ring)
|
||||
ringCommandContext->m_Ring.resize(size);
|
||||
for (RingItem& item : ringCommandContext->m_Ring)
|
||||
{
|
||||
VkCommandPoolCreateInfo commandPoolCreateInfoInfo{};
|
||||
commandPoolCreateInfoInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
commandPoolCreateInfoInfo.queueFamilyIndex = queueFamilyIndex;
|
||||
ENSURE_VK_SUCCESS(vkCreateCommandPool(
|
||||
m_Device->GetVkDevice(), &commandPoolCreateInfoInfo,
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkCreateCommandPool(
|
||||
device->GetVkDevice(), &commandPoolCreateInfoInfo,
|
||||
nullptr, &item.commandPool));
|
||||
|
||||
VkCommandBufferAllocateInfo allocateInfo{};
|
||||
@@ -81,11 +83,19 @@ CRingCommandContext::CRingCommandContext(
|
||||
allocateInfo.commandPool = item.commandPool;
|
||||
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocateInfo.commandBufferCount = 1;
|
||||
ENSURE_VK_SUCCESS(vkAllocateCommandBuffers(
|
||||
m_Device->GetVkDevice(), &allocateInfo, &item.commandBuffer));
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkAllocateCommandBuffers(
|
||||
device->GetVkDevice(), &allocateInfo, &item.commandBuffer));
|
||||
device->SetObjectName(
|
||||
VK_OBJECT_TYPE_COMMAND_BUFFER, item.commandBuffer, "RingCommandBuffer");
|
||||
}
|
||||
|
||||
return ringCommandContext;
|
||||
}
|
||||
|
||||
CRingCommandContext::CRingCommandContext(
|
||||
CDevice* device, CSubmitScheduler& submitScheduler)
|
||||
: m_Device(device), m_SubmitScheduler(submitScheduler)
|
||||
{
|
||||
}
|
||||
|
||||
CRingCommandContext::~CRingCommandContext()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -47,9 +47,10 @@ class CDevice;
|
||||
class CRingCommandContext
|
||||
{
|
||||
public:
|
||||
CRingCommandContext(
|
||||
static std::unique_ptr<CRingCommandContext> Create(
|
||||
CDevice* device, const size_t size, const uint32_t queueFamilyIndex,
|
||||
CSubmitScheduler& submitScheduler);
|
||||
|
||||
~CRingCommandContext();
|
||||
|
||||
/**
|
||||
@@ -95,6 +96,9 @@ public:
|
||||
const UploadBufferFunction& uploadFunction);
|
||||
|
||||
private:
|
||||
CRingCommandContext(
|
||||
CDevice* device, CSubmitScheduler& submitScheduler);
|
||||
|
||||
void Begin();
|
||||
void End();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -34,43 +34,55 @@ namespace Backend
|
||||
namespace Vulkan
|
||||
{
|
||||
|
||||
CSubmitScheduler::CSubmitScheduler(
|
||||
std::unique_ptr<CSubmitScheduler> CSubmitScheduler::Create(
|
||||
CDevice* device, const uint32_t queueFamilyIndex, VkQueue queue)
|
||||
: m_Device(device), m_Queue(queue)
|
||||
{
|
||||
std::unique_ptr<CSubmitScheduler> submitScheduler{new CSubmitScheduler{device, queue}};
|
||||
|
||||
// Currently we need exactly NUMBER_OF_FRAMES_IN_FLIGHT fences to avoid
|
||||
// possible overlapping of different work between frames.
|
||||
constexpr size_t numberOfFences = NUMBER_OF_FRAMES_IN_FLIGHT;
|
||||
m_Fences.reserve(numberOfFences);
|
||||
submitScheduler->m_Fences.reserve(numberOfFences);
|
||||
for (size_t index = 0; index < numberOfFences; ++index)
|
||||
{
|
||||
VkFenceCreateInfo fenceCreateInfo{};
|
||||
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
VkFence fence = VK_NULL_HANDLE;
|
||||
ENSURE_VK_SUCCESS(vkCreateFence(
|
||||
m_Device->GetVkDevice(), &fenceCreateInfo, nullptr, &fence));
|
||||
m_Fences.push_back({fence, INVALID_SUBMIT_HANDLE});
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkCreateFence(
|
||||
device->GetVkDevice(), &fenceCreateInfo, nullptr, &fence));
|
||||
submitScheduler->m_Fences.push_back({fence, INVALID_SUBMIT_HANDLE});
|
||||
}
|
||||
|
||||
for (FrameObject& frameObject : m_FrameObjects)
|
||||
for (FrameObject& frameObject : submitScheduler->m_FrameObjects)
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo{};
|
||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
ENSURE_VK_SUCCESS(vkCreateSemaphore(
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkCreateSemaphore(
|
||||
device->GetVkDevice(), &semaphoreCreateInfo, nullptr, &frameObject.acquireImageSemaphore));
|
||||
|
||||
ENSURE_VK_SUCCESS(vkCreateSemaphore(
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkCreateSemaphore(
|
||||
device->GetVkDevice(), &semaphoreCreateInfo, nullptr, &frameObject.submitDone));
|
||||
}
|
||||
|
||||
m_AcquireCommandContext = std::make_unique<CRingCommandContext>(
|
||||
device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *this);
|
||||
m_PresentCommandContext = std::make_unique<CRingCommandContext>(
|
||||
device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *this);
|
||||
submitScheduler->m_AcquireCommandContext = CRingCommandContext::Create(
|
||||
device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *submitScheduler);
|
||||
if (!submitScheduler->m_AcquireCommandContext)
|
||||
return nullptr;
|
||||
submitScheduler->m_PresentCommandContext = CRingCommandContext::Create(
|
||||
device, NUMBER_OF_FRAMES_IN_FLIGHT, queueFamilyIndex, *submitScheduler);
|
||||
if (!submitScheduler->m_PresentCommandContext)
|
||||
return nullptr;
|
||||
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidlebeforeacquire", m_DebugWaitIdleBeforeAcquire);
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidlebeforepresent", m_DebugWaitIdleBeforePresent);
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidleafterpresent", m_DebugWaitIdleAfterPresent);
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidlebeforeacquire", submitScheduler->m_DebugWaitIdleBeforeAcquire);
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidlebeforepresent", submitScheduler->m_DebugWaitIdleBeforePresent);
|
||||
CFG_GET_VAL("renderer.backend.vulkan.debugwaitidleafterpresent", submitScheduler->m_DebugWaitIdleAfterPresent);
|
||||
|
||||
return submitScheduler;
|
||||
}
|
||||
|
||||
CSubmitScheduler::CSubmitScheduler(CDevice* device, VkQueue queue)
|
||||
: m_Device(device), m_Queue(queue)
|
||||
{
|
||||
}
|
||||
|
||||
CSubmitScheduler::~CSubmitScheduler()
|
||||
|
||||
@@ -49,7 +49,8 @@ public:
|
||||
using SubmitHandle = uint32_t;
|
||||
static constexpr SubmitHandle INVALID_SUBMIT_HANDLE = 0;
|
||||
|
||||
CSubmitScheduler(CDevice* device, const uint32_t queueFamilyIndex, VkQueue queue);
|
||||
static std::unique_ptr<CSubmitScheduler> Create(
|
||||
CDevice* device, const uint32_t queueFamilyIndex, VkQueue queue);
|
||||
~CSubmitScheduler();
|
||||
|
||||
bool AcquireNextImage(CSwapChain& swapChain);
|
||||
@@ -65,6 +66,8 @@ public:
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
CSubmitScheduler(CDevice* device, VkQueue queue);
|
||||
|
||||
CDevice* m_Device = nullptr;
|
||||
VkQueue m_Queue = VK_NULL_HANDLE;
|
||||
|
||||
|
||||
@@ -182,7 +182,8 @@ std::unique_ptr<CSwapChain> CSwapChain::Create(
|
||||
|
||||
std::unique_ptr<CSwapChain> swapChain(new CSwapChain());
|
||||
swapChain->m_Device = device;
|
||||
ENSURE_VK_SUCCESS(vkCreateSwapchainKHR(
|
||||
|
||||
RETURN_NULLPTR_IF_NOT_VK_SUCCESS(vkCreateSwapchainKHR(
|
||||
device->GetVkDevice(), &swapChainCreateInfo, nullptr, &swapChain->m_SwapChain));
|
||||
|
||||
char nameBuffer[64];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -33,6 +33,17 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN_NULLPTR_IF_NOT_VK_SUCCESS(EXPR) \
|
||||
do \
|
||||
{ \
|
||||
const VkResult result = (EXPR); \
|
||||
if (result != VK_SUCCESS) \
|
||||
{ \
|
||||
LOGERROR(#EXPR " returned %d (%s) instead of VK_SUCCESS (%s:%d)", static_cast<int>(result), Utilities::GetVkResultName(result), __func__, __LINE__); \
|
||||
return nullptr; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user