Skip to content

Commit

Permalink
GPUDevice: Add sampler cache to base class
Browse files Browse the repository at this point in the history
Removes per-backend bookkeeping in D3D12 and Vulkan.
  • Loading branch information
stenzek committed Jan 18, 2025
1 parent da13579 commit 609fa5c
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 85 deletions.
11 changes: 5 additions & 6 deletions src/util/d3d12_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ void D3D12Device::DestroyDevice()
m_main_swap_chain.reset();

DestroyDeferredObjects(m_current_fence_value);
DestroySamplers();
DestroyTimestampQuery();
DestroyBuffers();
DestroyDescriptorHeaps();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
6 changes: 0 additions & 6 deletions src/util/d3d12_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,6 @@ class D3D12Device final : public GPUDevice
};
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);

Expand All @@ -261,8 +259,6 @@ class D3D12Device final : public GPUDevice
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);
Expand Down Expand Up @@ -320,7 +316,6 @@ class D3D12Device final : public GPUDevice
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;
Expand All @@ -342,7 +337,6 @@ class D3D12Device final : public GPUDevice
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.
Expand Down
35 changes: 8 additions & 27 deletions src/util/d3d12_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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);
return std::unique_ptr<GPUSampler>(new D3D12Sampler(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_sampler_map.clear();
}

std::unique_ptr<GPUSampler> D3D12Device::CreateSampler(const GPUSampler::Config& config, Error* error /* = nullptr */)
{
const D3D12DescriptorHandle handle = GetSampler(config, error);
if (!handle)
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)
Expand Down
32 changes: 27 additions & 5 deletions src/util/gpu_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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]]
{
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 10 additions & 4 deletions src/util/gpu_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,8 @@ class GPUDevice
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; }

Expand Down Expand Up @@ -757,6 +757,8 @@ class GPUDevice
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,
Expand Down Expand Up @@ -918,11 +920,11 @@ class GPUDevice
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;
Expand Down Expand Up @@ -957,6 +959,7 @@ class GPUDevice
};

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++.
Expand All @@ -976,11 +979,14 @@ class GPUDevice
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;

Expand Down
15 changes: 10 additions & 5 deletions src/util/vulkan_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -2064,7 +2070,6 @@ void VulkanDevice::DestroyDevice()
m_cleanup_objects.clear();
DestroyPersistentDescriptorSets();
DestroyBuffers();
DestroySamplers();

DestroyPersistentDescriptorPool();
DestroyPipelineLayouts();
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 1 addition & 5 deletions src/util/vulkan_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ class VulkanDevice final : public GPUDevice
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.
Expand Down Expand Up @@ -315,7 +316,6 @@ class VulkanDevice final : public GPUDevice
};

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,
Expand Down Expand Up @@ -363,8 +363,6 @@ class VulkanDevice final : public GPUDevice
void DestroyPipelineLayouts();
bool CreatePersistentDescriptorSets();
void DestroyPersistentDescriptorSets();
VkSampler GetSampler(const GPUSampler::Config& config, Error* error = nullptr);
void DestroySamplers();

void RenderBlankFrame(VulkanSwapChain* swap_chain);

Expand Down Expand Up @@ -457,8 +455,6 @@ class VulkanDevice final : public GPUDevice
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;

Expand Down
31 changes: 4 additions & 27 deletions src/util/vulkan_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 609fa5c

Please sign in to comment.