forked from mirrors/0ad
Font: make atlas uploads queue-aware on Vulkan
Goal
----
Avoid corrupting the dynamic font-atlas on Vulkan by blocking any
re-uploads until the command buffer that created / last updated the
texture has actually been submitted.
What changed
------------
* **Queue-aware textures**
* Added `queueSubmitAware` flag to `IDevice::CreateTexture*` APIs.
* `Vulkan::CTexture` now stores two booleans:
- `m_QueueSubmitAware` – opt-in per texture.
- `m_PendingQueueSubmit` – set to *true* the moment an upload
is recorded, cleared once the submit scheduler has flushed.
* `CRingCommandContext::ScheduleUpload` marks the texture as
pending (`SetPendingQueueSubmit(true)`).
* **Device-side watcher**
* `Vulkan::CDevice` keeps a
`m_TextureUploadWatcherQueue`. Each frame it checks textures that
were uploaded ≥ `NUMBER_OF_FRAMES_IN_FLIGHT` frames ago and
clears their pending flag.
* New helpers
`ScheduleTextureUploadWatch `,
`ProcessTextureUploadWatchQueue()`.
* **Font code**
* Atlas texture is now created with
`queueSubmitAware = true`.
* `CFont::UploadTextureAtlasToGPU()` early-outs when
`IsPendingQueueSubmit()` returns *true*, instead of tracking a
submit-handle or the manual `m_IsLoadingTextureToGPU` flag
(removed).
Why this is better
------------------
The logic to wait for a flush is localised inside the rendering
backend, so `CFont` only needs to ask *“is my texture busy?”*.
This removes the fragile submit-handle bookkeeping and works even if
the scheduler issues multiple submits per frame in future.
Result
------
Atlas uploads are deferred until the previous submit completes,
eliminating the intermittent glyph corruption on the Vulkan backend
while leaving GL and the dummy backend unchanged.
This commit is contained in:
@@ -26,7 +26,9 @@
|
||||
#include "ps/Profiler2.h"
|
||||
#include "ps/containers/Span.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/backend/Backend.h"
|
||||
#include "renderer/backend/IDevice.h"
|
||||
#include "renderer/backend/vulkan/Device.h"
|
||||
#include "renderer/backend/IDeviceCommandContext.h"
|
||||
#include "renderer/backend/ITexture.h"
|
||||
#include "renderer/backend/Sampler.h"
|
||||
@@ -288,7 +290,7 @@ bool CFont::ConstructTextureAtlas()
|
||||
Renderer::Backend::ITexture::Usage::TRANSFER_DST |
|
||||
Renderer::Backend::ITexture::Usage::SAMPLED,
|
||||
m_TextureFormat,
|
||||
textureSize, textureSize, defaultSamplerDesc
|
||||
textureSize, textureSize, defaultSamplerDesc, 1, 1, true
|
||||
));
|
||||
|
||||
if (!m_Texture)
|
||||
@@ -297,8 +299,6 @@ bool CFont::ConstructTextureAtlas()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_IsLoadingTextureToGPU = true;
|
||||
|
||||
// Initialise texture with transparency, for the areas we don't
|
||||
// overwrite with uploading later.
|
||||
m_TexData = std::make_unique<u8[]>(m_AtlasSize);
|
||||
@@ -493,10 +493,7 @@ std::optional<CVector2D> CFont::GenerateGlyphBitmap(FT_Glyph& glyph, u16 codepoi
|
||||
|
||||
void CFont::UploadTextureAtlasToGPU()
|
||||
{
|
||||
if (std::exchange(m_IsLoadingTextureToGPU, false))
|
||||
return;
|
||||
|
||||
if (!m_IsDirty)
|
||||
if (m_Texture->GetBackendTexture()->IsPendingQueueSubmit() || !m_IsDirty)
|
||||
return;
|
||||
|
||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext();
|
||||
|
||||
@@ -162,7 +162,6 @@ private:
|
||||
|
||||
int m_AtlasPadding;
|
||||
bool m_IsDirty{false};
|
||||
bool m_IsLoadingTextureToGPU{false};
|
||||
float m_StrokeWidth{0.0f};
|
||||
float m_Scale{1.0f};
|
||||
|
||||
|
||||
@@ -122,12 +122,12 @@ public:
|
||||
virtual std::unique_ptr<ITexture> CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) = 0;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware = false) = 0;
|
||||
|
||||
virtual std::unique_ptr<ITexture> CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) = 0;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1, const bool queueSubmitAware = false) = 0;
|
||||
|
||||
/**
|
||||
* @see IFramebuffer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -58,6 +58,8 @@ public:
|
||||
virtual uint32_t GetWidth() const = 0;
|
||||
virtual uint32_t GetHeight() const = 0;
|
||||
virtual uint32_t GetMIPLevelCount() const = 0;
|
||||
|
||||
virtual bool IsPendingQueueSubmit() const = 0;
|
||||
};
|
||||
|
||||
} // namespace Backend
|
||||
|
||||
@@ -97,7 +97,7 @@ std::unique_ptr<ITexture> CDevice::CreateTexture(
|
||||
const char* /*name*/, const CTexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& /*defaultSamplerDesc*/, const uint32_t MIPLevelCount,
|
||||
const uint32_t /*sampleCount*/)
|
||||
const uint32_t /*sampleCount*/, const bool /*queueSubmitAware*/)
|
||||
{
|
||||
return CTexture::Create(this, type, usage, format, width, height, MIPLevelCount);
|
||||
}
|
||||
@@ -105,10 +105,10 @@ std::unique_ptr<ITexture> CDevice::CreateTexture(
|
||||
std::unique_ptr<ITexture> CDevice::CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware)
|
||||
{
|
||||
return CreateTexture(name, ITexture::Type::TEXTURE_2D, usage,
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount, queueSubmitAware);
|
||||
}
|
||||
|
||||
std::unique_ptr<IFramebuffer> CDevice::CreateFramebuffer(
|
||||
|
||||
@@ -69,12 +69,12 @@ public:
|
||||
std::unique_ptr<ITexture> CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware = false) override;
|
||||
|
||||
std::unique_ptr<ITexture> CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1, const bool queueSubmitAware = false) override;
|
||||
|
||||
std::unique_ptr<IFramebuffer> CreateFramebuffer(
|
||||
const char* name, SColorAttachment* colorAttachment,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -51,6 +51,9 @@ public:
|
||||
uint32_t GetHeight() const override { return m_Height; }
|
||||
uint32_t GetMIPLevelCount() const override { return m_MIPLevelCount; }
|
||||
|
||||
// Dummy backend does not support queue submission.
|
||||
bool IsPendingQueueSubmit() const override { return false; }
|
||||
|
||||
private:
|
||||
friend class CDevice;
|
||||
|
||||
|
||||
@@ -908,7 +908,7 @@ std::unique_ptr<IVertexInputLayout> CDevice::CreateVertexInputLayout(
|
||||
std::unique_ptr<ITexture> CDevice::CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool /*queueSubmitAware*/)
|
||||
{
|
||||
return CTexture::Create(this, name, type, usage,
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
@@ -917,10 +917,10 @@ std::unique_ptr<ITexture> CDevice::CreateTexture(
|
||||
std::unique_ptr<ITexture> CDevice::CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware)
|
||||
{
|
||||
return CreateTexture(name, CTexture::Type::TEXTURE_2D, usage,
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount, queueSubmitAware);
|
||||
}
|
||||
|
||||
std::unique_ptr<IFramebuffer> CDevice::CreateFramebuffer(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -84,12 +84,12 @@ public:
|
||||
std::unique_ptr<ITexture> CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware) override;
|
||||
|
||||
std::unique_ptr<ITexture> CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1, const bool queueSubmitAware = false) override;
|
||||
|
||||
std::unique_ptr<IFramebuffer> CreateFramebuffer(
|
||||
const char* name, SColorAttachment* colorAttachment,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -58,6 +58,8 @@ public:
|
||||
|
||||
GLuint GetHandle() const { return m_Handle; }
|
||||
|
||||
// GL doesn's support queue submmit, so we don't need to track pending.
|
||||
bool IsPendingQueueSubmit() const override { return false; }
|
||||
private:
|
||||
friend class CDevice;
|
||||
|
||||
|
||||
@@ -677,6 +677,7 @@ CDevice::~CDevice()
|
||||
if (m_QueryPool)
|
||||
vkDestroyQueryPool(GetVkDevice(), m_QueryPool, nullptr);
|
||||
|
||||
ProcessTextureUploadWatchQueue(true);
|
||||
ProcessDeviceObjectToDestroyQueue(true);
|
||||
|
||||
m_RenderPassManager.reset();
|
||||
@@ -749,21 +750,21 @@ std::unique_ptr<IVertexInputLayout> CDevice::CreateVertexInputLayout(
|
||||
std::unique_ptr<ITexture> CDevice::CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware)
|
||||
{
|
||||
return CTexture::Create(
|
||||
this, name, type, usage, format, width, height,
|
||||
defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
defaultSamplerDesc, MIPLevelCount, sampleCount, queueSubmitAware);
|
||||
}
|
||||
|
||||
std::unique_ptr<ITexture> CDevice::CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware)
|
||||
{
|
||||
return CreateTexture(
|
||||
name, ITexture::Type::TEXTURE_2D, usage, format,
|
||||
width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
width, height, defaultSamplerDesc, MIPLevelCount, sampleCount, queueSubmitAware);
|
||||
}
|
||||
|
||||
std::unique_ptr<IFramebuffer> CDevice::CreateFramebuffer(
|
||||
@@ -832,6 +833,7 @@ void CDevice::Present()
|
||||
|
||||
m_SubmitScheduler->Present(*m_SwapChain);
|
||||
|
||||
ProcessTextureUploadWatchQueue();
|
||||
ProcessObjectToDestroyQueue();
|
||||
ProcessDeviceObjectToDestroyQueue();
|
||||
|
||||
@@ -1012,6 +1014,10 @@ void CDevice::ScheduleBufferToDestroy(const DeviceObjectUID uid)
|
||||
{
|
||||
m_BufferToDestroyQueue.push({m_FrameID, uid});
|
||||
}
|
||||
void CDevice::ScheduleTextureUploadWatch(CTexture* texture)
|
||||
{
|
||||
m_TextureUploadWatcherQueue.push({ m_FrameID, texture });
|
||||
}
|
||||
|
||||
void CDevice::SetObjectName(VkObjectType type, const uint64_t handle, const char* name)
|
||||
{
|
||||
@@ -1115,6 +1121,18 @@ void CDevice::ProcessDeviceObjectToDestroyQueue(const bool ignoreFrameID)
|
||||
}
|
||||
}
|
||||
|
||||
void CDevice::ProcessTextureUploadWatchQueue(const bool ignoreFrameID)
|
||||
{
|
||||
while (!m_TextureUploadWatcherQueue.empty() &&
|
||||
(ignoreFrameID || m_TextureUploadWatcherQueue.front().first + NUMBER_OF_FRAMES_IN_FLIGHT < m_FrameID))
|
||||
{
|
||||
CTexture* texture = m_TextureUploadWatcherQueue.front().second;
|
||||
if (texture)
|
||||
texture->SetPendingQueueSubmit(false);
|
||||
m_TextureUploadWatcherQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
CTexture* CDevice::GetCurrentBackbufferTexture()
|
||||
{
|
||||
return IsSwapChainValid() ? m_SwapChain->GetCurrentBackbufferTexture() : nullptr;
|
||||
@@ -1147,6 +1165,11 @@ std::unique_ptr<IDevice> CreateDevice(SDL_Window* window)
|
||||
return Vulkan::CDevice::Create(window);
|
||||
}
|
||||
|
||||
uint32_t CDevice::GetCurrentSchedulerHandle() const
|
||||
{
|
||||
return m_SubmitScheduler ? m_SubmitScheduler->GetCurrentHandle() : CSubmitScheduler::INVALID_SUBMIT_HANDLE;
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
} // namespace Backend
|
||||
|
||||
@@ -56,6 +56,7 @@ class CRingCommandContext;
|
||||
class CSamplerManager;
|
||||
class CSubmitScheduler;
|
||||
class CSwapChain;
|
||||
class CTexture;
|
||||
|
||||
class CDevice final : public IDevice
|
||||
{
|
||||
@@ -90,12 +91,12 @@ public:
|
||||
std::unique_ptr<ITexture> CreateTexture(
|
||||
const char* name, const ITexture::Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware = false) override;
|
||||
|
||||
std::unique_ptr<ITexture> CreateTexture2D(
|
||||
const char* name, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1) override;
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1, const bool queueSubmitAware = false) override;
|
||||
|
||||
std::unique_ptr<IFramebuffer> CreateFramebuffer(
|
||||
const char* name, SColorAttachment* colorAttachment,
|
||||
@@ -159,6 +160,8 @@ public:
|
||||
|
||||
void ScheduleBufferToDestroy(const DeviceObjectUID uid);
|
||||
|
||||
void ScheduleTextureUploadWatch(CTexture* texture);
|
||||
|
||||
void SetObjectName(VkObjectType type, const void* handle, const char* name)
|
||||
{
|
||||
SetObjectName(type, reinterpret_cast<uint64_t>(handle), name);
|
||||
@@ -182,6 +185,8 @@ public:
|
||||
|
||||
DeviceObjectUID GenerateNextDeviceObjectUID();
|
||||
|
||||
uint32_t GetCurrentSchedulerHandle() const;
|
||||
|
||||
private:
|
||||
CDevice();
|
||||
|
||||
@@ -189,6 +194,7 @@ private:
|
||||
bool IsSwapChainValid();
|
||||
void ProcessObjectToDestroyQueue(const bool ignoreFrameID = false);
|
||||
void ProcessDeviceObjectToDestroyQueue(const bool ignoreFrameID = false);
|
||||
void ProcessTextureUploadWatchQueue(const bool ignoreFrameID = false);
|
||||
|
||||
bool IsFormatSupportedForUsage(const Format format, const uint32_t usage) const;
|
||||
|
||||
@@ -239,6 +245,7 @@ private:
|
||||
};
|
||||
std::queue<ObjectToDestroy> m_ObjectToDestroyQueue;
|
||||
std::queue<std::pair<uint32_t, DeviceObjectUID>> m_TextureToDestroyQueue;
|
||||
std::queue<std::pair<uint32_t, CTexture*>> m_TextureUploadWatcherQueue;
|
||||
std::queue<std::pair<uint32_t, DeviceObjectUID>> m_BufferToDestroyQueue;
|
||||
|
||||
std::unique_ptr<CRenderPassManager> m_RenderPassManager;
|
||||
|
||||
@@ -164,6 +164,7 @@ void CRingCommandContext::ScheduleUpload(
|
||||
const uint32_t level, const uint32_t layer)
|
||||
{
|
||||
ENSURE(texture->GetType() != ITexture::Type::TEXTURE_2D_MULTISAMPLE);
|
||||
|
||||
const Format format = texture->GetFormat();
|
||||
if (texture->GetType() != ITexture::Type::TEXTURE_CUBE)
|
||||
ENSURE(layer == 0);
|
||||
@@ -223,6 +224,7 @@ void CRingCommandContext::ScheduleUpload(
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask);
|
||||
texture->SetInitialized();
|
||||
texture->SetPendingQueueSubmit(true);
|
||||
}
|
||||
|
||||
void CRingCommandContext::ScheduleUpload(
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
|
||||
void Flush();
|
||||
|
||||
SubmitHandle GetCurrentHandle() const { return m_CurrentHandle; };
|
||||
private:
|
||||
CSubmitScheduler(CDevice* device, VkQueue queue);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "renderer/backend/vulkan/SamplerManager.h"
|
||||
#include "renderer/backend/vulkan/Utilities.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
|
||||
@@ -38,7 +40,7 @@ std::unique_ptr<CTexture> CTexture::Create(
|
||||
CDevice* device, const char* name, const Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc,
|
||||
const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware)
|
||||
{
|
||||
std::unique_ptr<CTexture> texture(new CTexture(device));
|
||||
|
||||
@@ -50,6 +52,7 @@ std::unique_ptr<CTexture> CTexture::Create(
|
||||
texture->m_MIPLevelCount = MIPLevelCount;
|
||||
texture->m_SampleCount = sampleCount;
|
||||
texture->m_LayerCount = type == ITexture::Type::TEXTURE_CUBE ? 6 : 1;
|
||||
texture->m_QueueSubmitAware = queueSubmitAware;
|
||||
|
||||
if (type == Type::TEXTURE_2D_MULTISAMPLE)
|
||||
ENSURE(sampleCount > 1);
|
||||
@@ -376,6 +379,15 @@ CTexture::~CTexture()
|
||||
m_Device->ScheduleTextureToDestroy(m_UID);
|
||||
}
|
||||
|
||||
void CTexture::SetPendingQueueSubmit(bool pending)
|
||||
{
|
||||
if (!m_QueueSubmitAware)
|
||||
return;
|
||||
|
||||
if (!std::exchange(m_PendingQueueSubmit, pending) && pending)
|
||||
m_Device->ScheduleTextureUploadWatch(this);
|
||||
}
|
||||
|
||||
IDevice* CTexture::GetDevice()
|
||||
{
|
||||
return m_Device;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2025 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -54,6 +54,9 @@ public:
|
||||
uint32_t GetSampleCount() const { return m_SampleCount; }
|
||||
uint32_t GetLayerCount() const { return m_LayerCount; }
|
||||
|
||||
bool IsPendingQueueSubmit() const override { return m_PendingQueueSubmit; }
|
||||
void SetPendingQueueSubmit(bool pending);
|
||||
|
||||
VkImage GetImage() { return m_Image; }
|
||||
VkImageView GetAttachmentImageView() { return m_AttachmentImageView; }
|
||||
VkImageView GetSamplerImageView() { return m_SamplerImageView; }
|
||||
@@ -86,7 +89,7 @@ private:
|
||||
CDevice* device, const char* name, const Type type, const uint32_t usage,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc,
|
||||
const uint32_t MIPLevelCount, const uint32_t sampleCount);
|
||||
const uint32_t MIPLevelCount, const uint32_t sampleCount, const bool queueSubmitAware = false);
|
||||
|
||||
static std::unique_ptr<CTexture> WrapBackbufferImage(
|
||||
CDevice* device, const char* name, const VkImage image, const VkFormat format,
|
||||
@@ -128,6 +131,14 @@ private:
|
||||
// It's safe to store the current state while we use a single device command
|
||||
// context.
|
||||
bool m_Initialized = false;
|
||||
|
||||
// We store a flag to indicate that the texture is in Queue submit.
|
||||
bool m_PendingQueueSubmit = false;
|
||||
|
||||
// If true, the texture is aware of queue submission useful for
|
||||
// for dynamic textures that are updated frequently and needs to wait for
|
||||
// the queue submission to finish before overwriting the texture data.
|
||||
bool m_QueueSubmitAware = false;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
Reference in New Issue
Block a user