GPUDevice: Add sampler cache to base class
Removes per-backend bookkeeping in D3D12 and Vulkan.
This commit is contained in:
parent
da13579356
commit
609fa5c7d7
|
@ -317,7 +317,6 @@ void D3D12Device::DestroyDevice()
|
|||
m_main_swap_chain.reset();
|
||||
|
||||
DestroyDeferredObjects(m_current_fence_value);
|
||||
DestroySamplers();
|
||||
DestroyTimestampQuery();
|
||||
DestroyBuffers();
|
||||
DestroyDescriptorHeaps();
|
||||
|
@ -571,11 +570,11 @@ bool D3D12Device::CreateDescriptorHeaps(Error* error)
|
|||
m_device->CreateUnorderedAccessView(nullptr, nullptr, &null_uav_desc, m_null_uav_descriptor.cpu_handle);
|
||||
|
||||
// Same for samplers.
|
||||
m_point_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (!m_point_sampler) [[unlikely]]
|
||||
GPUSampler* default_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (!default_sampler) [[unlikely]]
|
||||
return false;
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
m_current_samplers[i] = m_point_sampler;
|
||||
m_current_samplers[i] = static_cast<D3D12Sampler*>(default_sampler)->GetDescriptor();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2123,7 +2122,7 @@ void D3D12Device::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* s
|
|||
}
|
||||
|
||||
const D3D12DescriptorHandle& handle =
|
||||
sampler ? static_cast<D3D12Sampler*>(sampler)->GetDescriptor() : m_point_sampler;
|
||||
static_cast<D3D12Sampler*>(sampler ? sampler : m_nearest_sampler)->GetDescriptor();
|
||||
if (m_current_samplers[slot] != handle)
|
||||
{
|
||||
m_current_samplers[slot] = handle;
|
||||
|
@ -2295,7 +2294,7 @@ void D3D12Device::RenderTextureMipmap(D3D12Texture* texture, u32 dst_level, u32
|
|||
|
||||
cmdlist->SetPipelineState(pipeline.Get());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(0, srv_handle);
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12Sampler*>(m_linear_sampler.get())->GetDescriptor());
|
||||
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12Sampler*>(m_linear_sampler)->GetDescriptor());
|
||||
cmdlist->DrawInstanced(3, 1, 0, 0);
|
||||
|
||||
cmdlist->EndRenderPass();
|
||||
|
|
|
@ -246,8 +246,6 @@ private:
|
|||
};
|
||||
static_assert(sizeof(PIPELINE_CACHE_HEADER) == 16);
|
||||
|
||||
using SamplerMap = std::unordered_map<u64, D3D12DescriptorHandle>;
|
||||
|
||||
void GetPipelineCacheHeader(PIPELINE_CACHE_HEADER* hdr);
|
||||
void SetFeatures(D3D_FEATURE_LEVEL feature_level, FeatureMask disabled_features);
|
||||
|
||||
|
@ -261,8 +259,6 @@ private:
|
|||
void DestroyDescriptorHeaps();
|
||||
bool CreateTimestampQuery();
|
||||
void DestroyTimestampQuery();
|
||||
D3D12DescriptorHandle GetSampler(const GPUSampler::Config& config, Error* error);
|
||||
void DestroySamplers();
|
||||
void DestroyDeferredObjects(u64 fence_value);
|
||||
|
||||
void RenderBlankFrame(D3D12SwapChain* swap_chain);
|
||||
|
@ -320,7 +316,6 @@ private:
|
|||
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
||||
D3D12DescriptorHandle m_null_srv_descriptor;
|
||||
D3D12DescriptorHandle m_null_uav_descriptor;
|
||||
D3D12DescriptorHandle m_point_sampler;
|
||||
|
||||
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
|
||||
ComPtr<ID3D12Resource> m_timestamp_query_buffer;
|
||||
|
@ -342,7 +337,6 @@ private:
|
|||
u32 m_uniform_buffer_position = 0;
|
||||
bool m_in_render_pass = false;
|
||||
|
||||
SamplerMap m_sampler_map;
|
||||
ComPtr<ID3D12PipelineLibrary> m_pipeline_library;
|
||||
|
||||
// Which bindings/state has to be updated before the next draw.
|
||||
|
|
|
@ -699,7 +699,8 @@ D3D12Sampler::D3D12Sampler(D3D12DescriptorHandle descriptor) : m_descriptor(desc
|
|||
|
||||
D3D12Sampler::~D3D12Sampler()
|
||||
{
|
||||
// Cleaned up by main class.
|
||||
D3D12Device& dev = D3D12Device::GetInstance();
|
||||
dev.DeferDescriptorDestruction(dev.GetSamplerHeapManager(), &m_descriptor);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GPU_OBJECT_NAMES
|
||||
|
@ -710,12 +711,8 @@ void D3D12Sampler::SetDebugName(std::string_view name)
|
|||
|
||||
#endif
|
||||
|
||||
D3D12DescriptorHandle D3D12Device::GetSampler(const GPUSampler::Config& config, Error* error)
|
||||
std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const auto it = m_sampler_map.find(config.key);
|
||||
if (it != m_sampler_map.end())
|
||||
return it->second;
|
||||
|
||||
static constexpr std::array<D3D12_TEXTURE_ADDRESS_MODE, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{
|
||||
D3D12_TEXTURE_ADDRESS_MODE_WRAP, // Repeat
|
||||
D3D12_TEXTURE_ADDRESS_MODE_CLAMP, // ClampToEdge
|
||||
|
@ -756,31 +753,15 @@ D3D12DescriptorHandle D3D12Device::GetSampler(const GPUSampler::Config& config,
|
|||
|
||||
D3D12DescriptorHandle handle;
|
||||
if (m_sampler_heap_manager.Allocate(&handle)) [[likely]]
|
||||
m_device->CreateSampler(&desc, handle);
|
||||
else
|
||||
Error::SetStringView(error, "Failed to allocate sampler handle.");
|
||||
|
||||
m_sampler_map.emplace(config.key, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void D3D12Device::DestroySamplers()
|
||||
{
|
||||
for (auto& it : m_sampler_map)
|
||||
{
|
||||
if (it.second)
|
||||
m_sampler_heap_manager.Free(&it.second);
|
||||
m_device->CreateSampler(&desc, handle);
|
||||
return std::unique_ptr<GPUSampler>(new D3D12Sampler(handle));
|
||||
}
|
||||
m_sampler_map.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const D3D12DescriptorHandle handle = GetSampler(config, error);
|
||||
if (!handle)
|
||||
else
|
||||
{
|
||||
Error::SetStringView(error, "Failed to allocate sampler handle.");
|
||||
return {};
|
||||
|
||||
return std::unique_ptr<GPUSampler>(new D3D12Sampler(handle));
|
||||
}
|
||||
}
|
||||
|
||||
D3D12TextureBuffer::D3D12TextureBuffer(Format format, u32 size_in_elements) : GPUTextureBuffer(format, size_in_elements)
|
||||
|
|
|
@ -650,12 +650,14 @@ bool GPUDevice::GetPipelineCacheData(DynamicHeapArray<u8>* data, Error* error)
|
|||
|
||||
bool GPUDevice::CreateResources(Error* error)
|
||||
{
|
||||
if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig(), error)) ||
|
||||
!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig(), error)))
|
||||
if (!(m_nearest_sampler = GetSampler(GPUSampler::GetNearestConfig(), error)) ||
|
||||
!(m_linear_sampler = GetSampler(GPUSampler::GetLinearConfig(), error)))
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to create samplers: ");
|
||||
return false;
|
||||
}
|
||||
GL_OBJECT_NAME(m_nearest_sampler, "Nearest Sampler");
|
||||
GL_OBJECT_NAME(m_linear_sampler, "Nearest Sampler");
|
||||
|
||||
const RenderAPI render_api = GetRenderAPI();
|
||||
ShaderGen shadergen(render_api, ShaderGen::GetShaderLanguageForAPI(render_api), m_features.dual_source_blend,
|
||||
|
@ -717,8 +719,9 @@ void GPUDevice::DestroyResources()
|
|||
|
||||
m_imgui_pipeline.reset();
|
||||
|
||||
m_linear_sampler.reset();
|
||||
m_nearest_sampler.reset();
|
||||
m_linear_sampler = nullptr;
|
||||
m_nearest_sampler = nullptr;
|
||||
m_sampler_map.clear();
|
||||
|
||||
m_shader_cache.Close();
|
||||
}
|
||||
|
@ -773,7 +776,7 @@ void GPUDevice::RenderImGui(GPUSwapChain* swap_chain)
|
|||
clip = FlipToLowerLeft(clip, post_rotated_height);
|
||||
|
||||
SetScissor(clip);
|
||||
SetTextureSampler(0, reinterpret_cast<GPUTexture*>(pcmd->TextureId), m_linear_sampler.get());
|
||||
SetTextureSampler(0, reinterpret_cast<GPUTexture*>(pcmd->TextureId), m_linear_sampler);
|
||||
|
||||
if (pcmd->UserCallback) [[unlikely]]
|
||||
{
|
||||
|
@ -1015,6 +1018,25 @@ GSVector4i GPUDevice::FlipToLowerLeft(GSVector4i rc, s32 target_height)
|
|||
return rc;
|
||||
}
|
||||
|
||||
GPUSampler* GPUDevice::GetSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
auto it = m_sampler_map.find(config.key);
|
||||
if (it != m_sampler_map.end())
|
||||
{
|
||||
if (!it->second) [[unlikely]]
|
||||
Error::SetStringView(error, "Sampler previously failed creation.");
|
||||
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> sampler = g_gpu_device->CreateSampler(config, error);
|
||||
if (sampler)
|
||||
GL_OBJECT_NAME_FMT(sampler, "Sampler {:016X}", config.key);
|
||||
|
||||
it = m_sampler_map.emplace(config.key, std::move(sampler)).first;
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
bool GPUDevice::IsTexturePoolType(GPUTexture::Type type)
|
||||
{
|
||||
return (type == GPUTexture::Type::Texture);
|
||||
|
|
|
@ -716,8 +716,8 @@ public:
|
|||
ALWAYS_INLINE GPUSwapChain* GetMainSwapChain() const { return m_main_swap_chain.get(); }
|
||||
ALWAYS_INLINE bool HasMainSwapChain() const { return static_cast<bool>(m_main_swap_chain); }
|
||||
|
||||
ALWAYS_INLINE GPUSampler* GetLinearSampler() const { return m_linear_sampler.get(); }
|
||||
ALWAYS_INLINE GPUSampler* GetNearestSampler() const { return m_nearest_sampler.get(); }
|
||||
ALWAYS_INLINE GPUSampler* GetLinearSampler() const { return m_linear_sampler; }
|
||||
ALWAYS_INLINE GPUSampler* GetNearestSampler() const { return m_nearest_sampler; }
|
||||
|
||||
ALWAYS_INLINE bool IsGPUTimingEnabled() const { return m_gpu_timing_enabled; }
|
||||
|
||||
|
@ -757,6 +757,8 @@ public:
|
|||
virtual std::unique_ptr<GPUTextureBuffer> CreateTextureBuffer(GPUTextureBuffer::Format format, u32 size_in_elements,
|
||||
Error* error = nullptr) = 0;
|
||||
|
||||
GPUSampler* GetSampler(const GPUSampler::Config& config, Error* error = nullptr);
|
||||
|
||||
// Texture pooling.
|
||||
std::unique_ptr<GPUTexture> FetchTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples,
|
||||
GPUTexture::Type type, GPUTexture::Format format, GPUTexture::Flags flags,
|
||||
|
@ -918,11 +920,11 @@ protected:
|
|||
u32 m_max_multisamples = 0;
|
||||
|
||||
std::unique_ptr<GPUSwapChain> m_main_swap_chain;
|
||||
GPUSampler* m_nearest_sampler = nullptr;
|
||||
GPUSampler* m_linear_sampler = nullptr;
|
||||
|
||||
GPUShaderCache m_shader_cache;
|
||||
|
||||
std::unique_ptr<GPUSampler> m_nearest_sampler;
|
||||
std::unique_ptr<GPUSampler> m_linear_sampler;
|
||||
|
||||
private:
|
||||
static constexpr u32 MAX_TEXTURE_POOL_SIZE = 125;
|
||||
|
@ -957,6 +959,7 @@ private:
|
|||
};
|
||||
|
||||
using TexturePool = std::deque<TexturePoolEntry>;
|
||||
using SamplerMap = std::unordered_map<u64, std::unique_ptr<GPUSampler>>;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// We have to define these in the base class, because they're in Objective C++.
|
||||
|
@ -976,11 +979,14 @@ private:
|
|||
std::unique_ptr<GPUPipeline> m_imgui_pipeline;
|
||||
std::unique_ptr<GPUTexture> m_imgui_font_texture;
|
||||
|
||||
SamplerMap m_sampler_map;
|
||||
|
||||
TexturePool m_texture_pool;
|
||||
TexturePool m_target_pool;
|
||||
size_t m_pool_vram_usage = 0;
|
||||
u32 m_texture_pool_counter = 0;
|
||||
|
||||
|
||||
protected:
|
||||
static Statistics s_stats;
|
||||
|
||||
|
|
|
@ -1604,6 +1604,12 @@ void VulkanDevice::DeferPersistentDescriptorSetDestruction(VkDescriptorSet objec
|
|||
m_cleanup_objects.emplace_back(GetCurrentFenceCounter(), [this, object]() { FreePersistentDescriptorSet(object); });
|
||||
}
|
||||
|
||||
void VulkanDevice::DeferSamplerDestruction(VkSampler object)
|
||||
{
|
||||
m_cleanup_objects.emplace_back(GetCurrentFenceCounter(),
|
||||
[this, object]() { vkDestroySampler(m_device, object, nullptr); });
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
|
@ -2064,7 +2070,6 @@ void VulkanDevice::DestroyDevice()
|
|||
m_cleanup_objects.clear();
|
||||
DestroyPersistentDescriptorSets();
|
||||
DestroyBuffers();
|
||||
DestroySamplers();
|
||||
|
||||
DestroyPersistentDescriptorPool();
|
||||
DestroyPipelineLayouts();
|
||||
|
@ -2790,15 +2795,15 @@ bool VulkanDevice::CreateNullTexture(Error* error)
|
|||
Vulkan::SetObjectName(m_device, m_null_texture->GetView(), "Null texture view");
|
||||
|
||||
// Bind null texture and point sampler state to all.
|
||||
const VkSampler point_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (point_sampler == VK_NULL_HANDLE)
|
||||
GPUSampler* point_sampler = GetSampler(GPUSampler::GetNearestConfig(), error);
|
||||
if (!point_sampler)
|
||||
{
|
||||
Error::AddPrefix(error, "Failed to get nearest sampler for init bind: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < MAX_TEXTURE_SAMPLERS; i++)
|
||||
m_current_samplers[i] = point_sampler;
|
||||
m_current_samplers[i] = static_cast<VulkanSampler*>(point_sampler)->GetSampler();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3568,7 +3573,7 @@ void VulkanDevice::SetInitialPipelineState()
|
|||
void VulkanDevice::SetTextureSampler(u32 slot, GPUTexture* texture, GPUSampler* sampler)
|
||||
{
|
||||
VulkanTexture* T = static_cast<VulkanTexture*>(texture);
|
||||
const VkSampler vsampler = static_cast<VulkanSampler*>(sampler ? sampler : m_nearest_sampler.get())->GetSampler();
|
||||
const VkSampler vsampler = static_cast<VulkanSampler*>(sampler ? sampler : m_nearest_sampler)->GetSampler();
|
||||
if (m_current_textures[slot] != T || m_current_samplers[slot] != vsampler)
|
||||
{
|
||||
m_current_textures[slot] = T;
|
||||
|
|
|
@ -222,6 +222,7 @@ public:
|
|||
void DeferPipelineDestruction(VkPipeline object);
|
||||
void DeferBufferViewDestruction(VkBufferView object);
|
||||
void DeferPersistentDescriptorSetDestruction(VkDescriptorSet object);
|
||||
void DeferSamplerDestruction(VkSampler object);
|
||||
|
||||
// Wait for a fence to be completed.
|
||||
// Also invokes callbacks for completion.
|
||||
|
@ -315,7 +316,6 @@ private:
|
|||
};
|
||||
|
||||
using CleanupObjectFunction = void (*)(VulkanDevice& dev, void* obj);
|
||||
using SamplerMap = std::unordered_map<u64, VkSampler>;
|
||||
|
||||
// Helper method to create a Vulkan instance.
|
||||
static VkInstance CreateVulkanInstance(const WindowInfo& wi, OptionalExtensions* oe, bool enable_debug_utils,
|
||||
|
@ -363,8 +363,6 @@ private:
|
|||
void DestroyPipelineLayouts();
|
||||
bool CreatePersistentDescriptorSets();
|
||||
void DestroyPersistentDescriptorSets();
|
||||
VkSampler GetSampler(const GPUSampler::Config& config, Error* error = nullptr);
|
||||
void DestroySamplers();
|
||||
|
||||
void RenderBlankFrame(VulkanSwapChain* swap_chain);
|
||||
|
||||
|
@ -457,8 +455,6 @@ private:
|
|||
VkDescriptorSet m_ubo_descriptor_set = VK_NULL_HANDLE;
|
||||
u32 m_uniform_buffer_position = 0;
|
||||
|
||||
SamplerMap m_sampler_map;
|
||||
|
||||
// Which bindings/state has to be updated before the next draw.
|
||||
u32 m_dirty_flags = ALL_DIRTY_STATE;
|
||||
|
||||
|
|
|
@ -776,7 +776,7 @@ VulkanSampler::VulkanSampler(VkSampler sampler) : m_sampler(sampler)
|
|||
|
||||
VulkanSampler::~VulkanSampler()
|
||||
{
|
||||
// Cleaned up by main class.
|
||||
VulkanDevice::GetInstance().DeferSamplerDestruction(m_sampler);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GPU_OBJECT_NAMES
|
||||
|
@ -788,12 +788,8 @@ void VulkanSampler::SetDebugName(std::string_view name)
|
|||
|
||||
#endif
|
||||
|
||||
VkSampler VulkanDevice::GetSampler(const GPUSampler::Config& config, Error* error)
|
||||
std::unique_ptr<GPUSampler> VulkanDevice::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const auto it = m_sampler_map.find(config.key);
|
||||
if (it != m_sampler_map.end())
|
||||
return it->second;
|
||||
|
||||
static constexpr std::array<VkSamplerAddressMode, static_cast<u8>(GPUSampler::AddressMode::MaxCount)> ta = {{
|
||||
VK_SAMPLER_ADDRESS_MODE_REPEAT, // Repeat
|
||||
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // ClampToEdge
|
||||
|
@ -867,29 +863,10 @@ VkSampler VulkanDevice::GetSampler(const GPUSampler::Config& config, Error* erro
|
|||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSampler() failed: ");
|
||||
Vulkan::SetErrorObject(error, "vkCreateSampler() failed: ", res);
|
||||
}
|
||||
|
||||
m_sampler_map.emplace(config.key, sampler);
|
||||
return sampler;
|
||||
}
|
||||
|
||||
void VulkanDevice::DestroySamplers()
|
||||
{
|
||||
for (auto& it : m_sampler_map)
|
||||
{
|
||||
if (it.second != VK_NULL_HANDLE)
|
||||
vkDestroySampler(m_device, it.second, nullptr);
|
||||
}
|
||||
m_sampler_map.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUSampler> VulkanDevice::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
|
||||
{
|
||||
const VkSampler vsampler = GetSampler(config, error);
|
||||
if (vsampler == VK_NULL_HANDLE)
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::unique_ptr<GPUSampler>(new VulkanSampler(vsampler));
|
||||
return std::unique_ptr<GPUSampler>(new VulkanSampler(sampler));
|
||||
}
|
||||
|
||||
VulkanTextureBuffer::VulkanTextureBuffer(Format format, u32 size_in_elements)
|
||||
|
|
Loading…
Reference in New Issue