mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-03 22:24:13 +01:00
[dxvk] Implement sampler pool
Deduplicates redundant sampler objects and makes sampler creation as well as lifetime tracking a bit more efficient.
This commit is contained in:
parent
5f9f43e658
commit
4635397bb1
@ -9,63 +9,58 @@ namespace dxvk {
|
|||||||
const D3D11_SAMPLER_DESC& desc)
|
const D3D11_SAMPLER_DESC& desc)
|
||||||
: D3D11StateObject<ID3D11SamplerState>(device),
|
: D3D11StateObject<ID3D11SamplerState>(device),
|
||||||
m_desc(desc), m_d3d10(this) {
|
m_desc(desc), m_d3d10(this) {
|
||||||
DxvkSamplerCreateInfo info;
|
DxvkSamplerKey info = { };
|
||||||
|
|
||||||
// While D3D11_FILTER is technically an enum, its value bits
|
// While D3D11_FILTER is technically an enum, its value bits
|
||||||
// can be used to decode the filter properties more efficiently.
|
// can be used to decode the filter properties more efficiently.
|
||||||
const uint32_t filterBits = uint32_t(desc.Filter);
|
const uint32_t filterBits = uint32_t(desc.Filter);
|
||||||
info.magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
||||||
info.minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
VkFilter minFilter = (filterBits & 0x10) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||||
|
VkFilter magFilter = (filterBits & 0x04) ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||||
|
|
||||||
|
info.setFilter(minFilter, magFilter,
|
||||||
|
(filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||||
|
|
||||||
|
// Enforce LOD bias specified in the device options
|
||||||
|
float lodBias = desc.MipLODBias;
|
||||||
|
|
||||||
|
if (minFilter == VK_FILTER_LINEAR && magFilter == VK_FILTER_LINEAR) {
|
||||||
|
lodBias += device->GetOptions()->samplerLodBias;
|
||||||
|
|
||||||
|
if (device->GetOptions()->clampNegativeLodBias)
|
||||||
|
lodBias = std::max(lodBias, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
info.setLodRange(desc.MinLOD, desc.MaxLOD, lodBias);
|
||||||
|
|
||||||
|
// Enforce anisotropy specified in the device options
|
||||||
|
uint32_t anisotropy = (filterBits & 0x40) ? desc.MaxAnisotropy : 0u;
|
||||||
|
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
||||||
|
|
||||||
|
if (samplerAnisotropyOption >= 0 && minFilter == VK_FILTER_LINEAR)
|
||||||
|
anisotropy = samplerAnisotropyOption > 0;
|
||||||
|
|
||||||
|
info.setAniso(anisotropy);
|
||||||
|
|
||||||
// Set up the remaining properties, which are
|
// Set up the remaining properties, which are
|
||||||
// stored directly in the sampler description
|
// stored directly in the sampler description
|
||||||
info.mipmapMode = (filterBits & 0x01) ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
info.setAddressModes(
|
||||||
info.mipmapLodBias = desc.MipLODBias;
|
DecodeAddressMode(desc.AddressU),
|
||||||
info.mipmapLodMin = desc.MinLOD;
|
DecodeAddressMode(desc.AddressV),
|
||||||
info.mipmapLodMax = desc.MaxLOD;
|
DecodeAddressMode(desc.AddressW));
|
||||||
|
|
||||||
info.useAnisotropy = (filterBits & 0x40) ? VK_TRUE : VK_FALSE;
|
|
||||||
info.maxAnisotropy = float(desc.MaxAnisotropy);
|
|
||||||
|
|
||||||
info.addressModeU = DecodeAddressMode(desc.AddressU);
|
|
||||||
info.addressModeV = DecodeAddressMode(desc.AddressV);
|
|
||||||
info.addressModeW = DecodeAddressMode(desc.AddressW);
|
|
||||||
|
|
||||||
info.compareToDepth = (filterBits & 0x180) == 0x80 ? VK_TRUE : VK_FALSE;
|
|
||||||
info.compareOp = DecodeCompareOp(desc.ComparisonFunc);
|
|
||||||
|
|
||||||
info.reductionMode = DecodeReductionMode(filterBits);
|
info.setDepthCompare((filterBits & 0x180) == 0x80,
|
||||||
|
DecodeCompareOp(desc.ComparisonFunc));
|
||||||
|
|
||||||
|
info.setReduction(DecodeReductionMode(filterBits));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 4; i++)
|
for (uint32_t i = 0; i < 4; i++)
|
||||||
info.borderColor.float32[i] = desc.BorderColor[i];
|
info.borderColor.float32[i] = desc.BorderColor[i];
|
||||||
|
|
||||||
info.usePixelCoord = VK_FALSE; // Not supported in D3D11
|
|
||||||
info.nonSeamless = VK_FALSE;
|
|
||||||
|
|
||||||
// Make sure to use a valid anisotropy value
|
|
||||||
if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;
|
|
||||||
if (desc.MaxAnisotropy > 16) info.maxAnisotropy = 16.0f;
|
|
||||||
|
|
||||||
// Enforce LOD bias specified in the device options
|
|
||||||
if (info.minFilter == VK_FILTER_LINEAR && info.magFilter == VK_FILTER_LINEAR) {
|
|
||||||
info.mipmapLodBias += device->GetOptions()->samplerLodBias;
|
|
||||||
|
|
||||||
if (device->GetOptions()->clampNegativeLodBias)
|
|
||||||
info.mipmapLodBias = std::max(info.mipmapLodBias, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce anisotropy specified in the device options
|
|
||||||
int32_t samplerAnisotropyOption = device->GetOptions()->samplerAnisotropy;
|
|
||||||
|
|
||||||
if (samplerAnisotropyOption >= 0 && info.minFilter == VK_FILTER_LINEAR) {
|
|
||||||
info.useAnisotropy = samplerAnisotropyOption > 0;
|
|
||||||
info.maxAnisotropy = float(samplerAnisotropyOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_sampler = device->GetDXVKDevice()->createSampler(info);
|
m_sampler = device->GetDXVKDevice()->createSampler(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
D3D11SamplerState::~D3D11SamplerState() {
|
D3D11SamplerState::~D3D11SamplerState() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6690,42 +6690,37 @@ namespace dxvk {
|
|||||||
|
|
||||||
auto mipFilter = DecodeMipFilter(cKey.MipFilter);
|
auto mipFilter = DecodeMipFilter(cKey.MipFilter);
|
||||||
|
|
||||||
DxvkSamplerCreateInfo info;
|
DxvkSamplerKey info = { };
|
||||||
info.addressModeU = DecodeAddressMode(cKey.AddressU);
|
|
||||||
info.addressModeV = DecodeAddressMode(cKey.AddressV);
|
info.setFilter(
|
||||||
info.addressModeW = DecodeAddressMode(cKey.AddressW);
|
DecodeFilter(cKey.MinFilter),
|
||||||
info.compareToDepth = cKey.Depth;
|
DecodeFilter(cKey.MagFilter),
|
||||||
info.compareOp = cKey.Depth ? VK_COMPARE_OP_LESS_OR_EQUAL : VK_COMPARE_OP_NEVER;
|
mipFilter.MipFilter);
|
||||||
info.magFilter = DecodeFilter(cKey.MagFilter);
|
|
||||||
info.minFilter = DecodeFilter(cKey.MinFilter);
|
info.setAddressModes(
|
||||||
info.mipmapMode = mipFilter.MipFilter;
|
DecodeAddressMode(cKey.AddressU),
|
||||||
info.maxAnisotropy = float(cKey.MaxAnisotropy);
|
DecodeAddressMode(cKey.AddressV),
|
||||||
info.useAnisotropy = cKey.MaxAnisotropy > 1;
|
DecodeAddressMode(cKey.AddressW));
|
||||||
|
|
||||||
|
info.setDepthCompare(cKey.Depth,
|
||||||
|
VK_COMPARE_OP_LESS_OR_EQUAL);
|
||||||
|
|
||||||
|
info.setAniso(cKey.MaxAnisotropy);
|
||||||
|
|
||||||
|
float lodBias = cKey.MipmapLodBias + m_d3d9Options.samplerLodBias;
|
||||||
|
|
||||||
info.mipmapLodBias = cKey.MipmapLodBias + m_d3d9Options.samplerLodBias;
|
|
||||||
if (m_d3d9Options.clampNegativeLodBias)
|
if (m_d3d9Options.clampNegativeLodBias)
|
||||||
info.mipmapLodBias = std::max(info.mipmapLodBias, 0.0f);
|
lodBias = std::max(lodBias, 0.0f);
|
||||||
|
|
||||||
info.mipmapLodMin = mipFilter.MipsEnabled ? float(cKey.MaxMipLevel) : 0;
|
info.setLodRange(
|
||||||
info.mipmapLodMax = mipFilter.MipsEnabled ? FLT_MAX : 0;
|
mipFilter.MipsEnabled ? float(cKey.MaxMipLevel) : 0.0f,
|
||||||
info.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
mipFilter.MipsEnabled ? FLT_MAX : 0.0f,
|
||||||
info.usePixelCoord = VK_FALSE;
|
lodBias);
|
||||||
info.nonSeamless = m_dxvkDevice->features().extNonSeamlessCubeMap.nonSeamlessCubeMap && !m_d3d9Options.seamlessCubes;
|
|
||||||
|
info.setLegacyCubeFilter(!m_d3d9Options.seamlessCubes);
|
||||||
|
|
||||||
DecodeD3DCOLOR(cKey.BorderColor, info.borderColor.float32);
|
DecodeD3DCOLOR(cKey.BorderColor, info.borderColor.float32);
|
||||||
|
|
||||||
if (!m_dxvkDevice->features().extCustomBorderColor.customBorderColorWithoutFormat) {
|
|
||||||
// HACK: Let's get OPAQUE_WHITE border color over
|
|
||||||
// TRANSPARENT_BLACK if the border RGB is white.
|
|
||||||
if (info.borderColor.float32[0] == 1.0f
|
|
||||||
&& info.borderColor.float32[1] == 1.0f
|
|
||||||
&& info.borderColor.float32[2] == 1.0f
|
|
||||||
&& !m_dxvkDevice->features().extCustomBorderColor.customBorderColors) {
|
|
||||||
// Then set the alpha to 1.
|
|
||||||
info.borderColor.float32[3] = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto sampler = m_dxvkDevice->createSampler(info);
|
auto sampler = m_dxvkDevice->createSampler(info);
|
||||||
|
|
||||||
|
@ -281,6 +281,10 @@ namespace dxvk {
|
|||||||
m_resources.trackResource(DxvkLifetime<DxvkResource>(rc, Access));
|
m_resources.trackResource(DxvkLifetime<DxvkResource>(rc, Access));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void trackSampler(const Rc<DxvkSampler>& sampler) {
|
||||||
|
m_resources.trackSampler(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Tracks a GPU event
|
* \brief Tracks a GPU event
|
||||||
*
|
*
|
||||||
|
@ -5260,7 +5260,7 @@ namespace dxvk {
|
|||||||
descriptorInfo.image.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
descriptorInfo.image.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
if (m_rcTracked.set(binding.resourceBinding))
|
if (m_rcTracked.set(binding.resourceBinding))
|
||||||
m_cmd->trackResource<DxvkAccess::None>(res.sampler);
|
m_cmd->trackSampler(res.sampler);
|
||||||
} else {
|
} else {
|
||||||
descriptorInfo.image.sampler = m_common->dummyResources().samplerHandle();
|
descriptorInfo.image.sampler = m_common->dummyResources().samplerHandle();
|
||||||
descriptorInfo.image.imageView = VK_NULL_HANDLE;
|
descriptorInfo.image.imageView = VK_NULL_HANDLE;
|
||||||
@ -5312,7 +5312,7 @@ namespace dxvk {
|
|||||||
descriptorInfo.image.imageLayout = res.imageView->image()->info().layout;
|
descriptorInfo.image.imageLayout = res.imageView->image()->info().layout;
|
||||||
|
|
||||||
if (m_rcTracked.set(binding.resourceBinding)) {
|
if (m_rcTracked.set(binding.resourceBinding)) {
|
||||||
m_cmd->trackResource<DxvkAccess::None>(res.sampler);
|
m_cmd->trackSampler(res.sampler);
|
||||||
m_cmd->trackResource<DxvkAccess::Read>(res.imageView->image());
|
m_cmd->trackResource<DxvkAccess::Read>(res.imageView->image());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,8 +172,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
Rc<DxvkSampler> DxvkDevice::createSampler(
|
Rc<DxvkSampler> DxvkDevice::createSampler(
|
||||||
const DxvkSamplerCreateInfo& createInfo) {
|
const DxvkSamplerKey& createInfo) {
|
||||||
return new DxvkSampler(this, createInfo);
|
return m_objects.samplerPool().createSampler(createInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ namespace dxvk {
|
|||||||
* \returns Newly created sampler object
|
* \returns Newly created sampler object
|
||||||
*/
|
*/
|
||||||
Rc<DxvkSampler> createSampler(
|
Rc<DxvkSampler> createSampler(
|
||||||
const DxvkSamplerCreateInfo& createInfo);
|
const DxvkSamplerKey& createInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Creates local allocation cache
|
* \brief Creates local allocation cache
|
||||||
|
@ -9,6 +9,7 @@ namespace dxvk {
|
|||||||
void DxvkLifetimeTracker::reset() {
|
void DxvkLifetimeTracker::reset() {
|
||||||
m_resources.clear();
|
m_resources.clear();
|
||||||
m_allocations.clear();
|
m_allocations.clear();
|
||||||
|
m_samplers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dxvk_resource.h"
|
#include "dxvk_resource.h"
|
||||||
|
#include "dxvk_sampler.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
@ -106,6 +107,14 @@ namespace dxvk {
|
|||||||
DxvkLifetimeTracker();
|
DxvkLifetimeTracker();
|
||||||
~DxvkLifetimeTracker();
|
~DxvkLifetimeTracker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds a sampler to track
|
||||||
|
* \param [in] res The sampler to track
|
||||||
|
*/
|
||||||
|
void trackSampler(const Rc<DxvkSampler>& res) {
|
||||||
|
m_samplers.push_back(res);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Adds a resource to track
|
* \brief Adds a resource to track
|
||||||
* \param [in] res The resource to track
|
* \param [in] res The resource to track
|
||||||
@ -132,6 +141,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::vector<Rc<DxvkSampler>> m_samplers;
|
||||||
|
|
||||||
std::vector<DxvkLifetime<DxvkResource>> m_resources;
|
std::vector<DxvkLifetime<DxvkResource>> m_resources;
|
||||||
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
|
std::vector<DxvkLifetime<DxvkResourceAllocation>> m_allocations;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "dxvk_meta_resolve.h"
|
#include "dxvk_meta_resolve.h"
|
||||||
#include "dxvk_pipemanager.h"
|
#include "dxvk_pipemanager.h"
|
||||||
#include "dxvk_renderpass.h"
|
#include "dxvk_renderpass.h"
|
||||||
|
#include "dxvk_sampler.h"
|
||||||
#include "dxvk_unbound.h"
|
#include "dxvk_unbound.h"
|
||||||
|
|
||||||
#include "../util/util_lazy.h"
|
#include "../util/util_lazy.h"
|
||||||
@ -25,6 +26,7 @@ namespace dxvk {
|
|||||||
: m_device (device),
|
: m_device (device),
|
||||||
m_memoryManager (device),
|
m_memoryManager (device),
|
||||||
m_pipelineManager (device),
|
m_pipelineManager (device),
|
||||||
|
m_samplerPool (device),
|
||||||
m_eventPool (device),
|
m_eventPool (device),
|
||||||
m_queryPool (device),
|
m_queryPool (device),
|
||||||
m_dummyResources (device) {
|
m_dummyResources (device) {
|
||||||
@ -39,6 +41,10 @@ namespace dxvk {
|
|||||||
return m_pipelineManager;
|
return m_pipelineManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DxvkSamplerPool& samplerPool() {
|
||||||
|
return m_samplerPool;
|
||||||
|
}
|
||||||
|
|
||||||
DxvkGpuEventPool& eventPool() {
|
DxvkGpuEventPool& eventPool() {
|
||||||
return m_eventPool;
|
return m_eventPool;
|
||||||
}
|
}
|
||||||
@ -78,6 +84,7 @@ namespace dxvk {
|
|||||||
DxvkMemoryAllocator m_memoryManager;
|
DxvkMemoryAllocator m_memoryManager;
|
||||||
DxvkPipelineManager m_pipelineManager;
|
DxvkPipelineManager m_pipelineManager;
|
||||||
|
|
||||||
|
DxvkSamplerPool m_samplerPool;
|
||||||
DxvkGpuEventPool m_eventPool;
|
DxvkGpuEventPool m_eventPool;
|
||||||
DxvkGpuQueryPool m_queryPool;
|
DxvkGpuQueryPool m_queryPool;
|
||||||
|
|
||||||
|
@ -4,82 +4,216 @@
|
|||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
DxvkSampler::DxvkSampler(
|
DxvkSampler::DxvkSampler(
|
||||||
DxvkDevice* device,
|
DxvkSamplerPool* pool,
|
||||||
const DxvkSamplerCreateInfo& info)
|
const DxvkSamplerKey& key)
|
||||||
: m_vkd(device->vkd()) {
|
: m_pool(pool), m_key(key) {
|
||||||
|
auto vk = m_pool->m_device->vkd();
|
||||||
|
|
||||||
VkSamplerCustomBorderColorCreateInfoEXT borderColorInfo = { VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT };
|
VkSamplerCustomBorderColorCreateInfoEXT borderColorInfo = { VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT };
|
||||||
borderColorInfo.customBorderColor = info.borderColor;
|
borderColorInfo.customBorderColor = key.borderColor;
|
||||||
|
|
||||||
VkSamplerReductionModeCreateInfo reductionInfo = { VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO };
|
VkSamplerReductionModeCreateInfo reductionInfo = { VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO };
|
||||||
reductionInfo.reductionMode = info.reductionMode;
|
reductionInfo.reductionMode = VkSamplerReductionMode(key.u.p.reduction);
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
||||||
samplerInfo.flags = info.nonSeamless ? VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT : 0;
|
samplerInfo.magFilter = VkFilter(key.u.p.magFilter);
|
||||||
samplerInfo.magFilter = info.magFilter;
|
samplerInfo.minFilter = VkFilter(key.u.p.minFilter);
|
||||||
samplerInfo.minFilter = info.minFilter;
|
samplerInfo.mipmapMode = VkSamplerMipmapMode(key.u.p.mipMode);
|
||||||
samplerInfo.mipmapMode = info.mipmapMode;
|
samplerInfo.addressModeU = VkSamplerAddressMode(key.u.p.addressU);
|
||||||
samplerInfo.addressModeU = info.addressModeU;
|
samplerInfo.addressModeV = VkSamplerAddressMode(key.u.p.addressV);
|
||||||
samplerInfo.addressModeV = info.addressModeV;
|
samplerInfo.addressModeW = VkSamplerAddressMode(key.u.p.addressW);
|
||||||
samplerInfo.addressModeW = info.addressModeW;
|
samplerInfo.mipLodBias = bit::decodeFixed<int32_t, 6, 8>(key.u.p.lodBias);
|
||||||
samplerInfo.mipLodBias = info.mipmapLodBias;
|
samplerInfo.anisotropyEnable = key.u.p.anisotropy > 0u;
|
||||||
samplerInfo.anisotropyEnable = info.useAnisotropy;
|
samplerInfo.maxAnisotropy = float(key.u.p.anisotropy);
|
||||||
samplerInfo.maxAnisotropy = info.maxAnisotropy;
|
samplerInfo.compareEnable = key.u.p.compareEnable != 0u;
|
||||||
samplerInfo.compareEnable = info.compareToDepth;
|
samplerInfo.compareOp = VkCompareOp(key.u.p.compareOp);
|
||||||
samplerInfo.compareOp = info.compareOp;
|
samplerInfo.minLod = bit::decodeFixed<uint32_t, 4, 8>(key.u.p.minLod);
|
||||||
samplerInfo.minLod = info.mipmapLodMin;
|
samplerInfo.maxLod = bit::decodeFixed<uint32_t, 4, 8>(key.u.p.maxLod);
|
||||||
samplerInfo.maxLod = info.mipmapLodMax;
|
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
samplerInfo.unnormalizedCoordinates = key.u.p.pixelCoord;
|
||||||
samplerInfo.unnormalizedCoordinates = info.usePixelCoord;
|
|
||||||
|
|
||||||
if (!device->features().core.features.samplerAnisotropy)
|
if (key.u.p.legacyCube && m_pool->m_device->features().extNonSeamlessCubeMap.nonSeamlessCubeMap)
|
||||||
|
samplerInfo.flags |= VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT;
|
||||||
|
|
||||||
|
if (!m_pool->m_device->features().core.features.samplerAnisotropy)
|
||||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||||
|
|
||||||
if (samplerInfo.addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
|
if (key.u.p.hasBorder)
|
||||||
|| samplerInfo.addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
|
samplerInfo.borderColor = determineBorderColorType();
|
||||||
|| samplerInfo.addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER)
|
|
||||||
samplerInfo.borderColor = getBorderColor(device, info);
|
|
||||||
|
|
||||||
if (samplerInfo.borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT)
|
if (samplerInfo.borderColor == VK_BORDER_COLOR_FLOAT_CUSTOM_EXT
|
||||||
|
|| samplerInfo.borderColor == VK_BORDER_COLOR_INT_CUSTOM_EXT)
|
||||||
borderColorInfo.pNext = std::exchange(samplerInfo.pNext, &borderColorInfo);
|
borderColorInfo.pNext = std::exchange(samplerInfo.pNext, &borderColorInfo);
|
||||||
|
|
||||||
if (reductionInfo.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
|
if (reductionInfo.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE)
|
||||||
reductionInfo.pNext = std::exchange(samplerInfo.pNext, &reductionInfo);
|
reductionInfo.pNext = std::exchange(samplerInfo.pNext, &reductionInfo);
|
||||||
|
|
||||||
if (m_vkd->vkCreateSampler(m_vkd->device(),
|
if (vk->vkCreateSampler(vk->device(),
|
||||||
&samplerInfo, nullptr, &m_sampler) != VK_SUCCESS)
|
&samplerInfo, nullptr, &m_sampler) != VK_SUCCESS)
|
||||||
throw DxvkError("DxvkSampler::DxvkSampler: Failed to create sampler");
|
throw DxvkError("DxvkSampler::DxvkSampler: Failed to create sampler");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkSampler::~DxvkSampler() {
|
DxvkSampler::~DxvkSampler() {
|
||||||
m_vkd->vkDestroySampler(
|
auto vk = m_pool->m_device->vkd();
|
||||||
m_vkd->device(), m_sampler, nullptr);
|
|
||||||
|
vk->vkDestroySampler(vk->device(), m_sampler, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkBorderColor DxvkSampler::getBorderColor(const Rc<DxvkDevice>& device, const DxvkSamplerCreateInfo& info) {
|
void DxvkSampler::release() {
|
||||||
static const std::array<std::pair<VkClearColorValue, VkBorderColor>, 3> s_borderColors = {{
|
m_pool->releaseSampler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkBorderColor DxvkSampler::determineBorderColorType() const {
|
||||||
|
static const std::array<std::pair<VkClearColorValue, VkBorderColor>, 4> s_borderColors = {{
|
||||||
{ { { 0.0f, 0.0f, 0.0f, 0.0f } }, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK },
|
{ { { 0.0f, 0.0f, 0.0f, 0.0f } }, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK },
|
||||||
{ { { 0.0f, 0.0f, 0.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK },
|
{ { { 0.0f, 0.0f, 0.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK },
|
||||||
{ { { 1.0f, 1.0f, 1.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE },
|
{ { { 1.0f, 1.0f, 1.0f, 1.0f } }, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE },
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Ignore G/B/A components for shadow samplers
|
// Iterate over border colors and try to find an exact match
|
||||||
size_t size = !info.compareToDepth
|
uint32_t componentCount = m_key.u.p.compareEnable ? 1u : 4u;
|
||||||
? sizeof(VkClearColorValue)
|
|
||||||
: sizeof(float);
|
|
||||||
|
|
||||||
for (const auto& e : s_borderColors) {
|
for (const auto& e : s_borderColors) {
|
||||||
if (!std::memcmp(&e.first, &info.borderColor, size))
|
bool allEqual = true;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < componentCount; i++)
|
||||||
|
allEqual &= m_key.borderColor.float32[i] == e.first.float32[i];
|
||||||
|
|
||||||
|
if (allEqual)
|
||||||
return e.second;
|
return e.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device->features().extCustomBorderColor.customBorderColorWithoutFormat) {
|
// If custom border colors are supported, use that
|
||||||
Logger::warn("DXVK: Custom border colors not supported");
|
if (m_pool->m_device->features().extCustomBorderColor.customBorderColorWithoutFormat)
|
||||||
return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
return VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
|
||||||
|
|
||||||
|
// Otherwise, use the sum of absolute differences to find the
|
||||||
|
// closest fallback value. Some D3D9 games may rely on this.
|
||||||
|
Logger::warn("DXVK: Custom border colors not supported");
|
||||||
|
|
||||||
|
VkBorderColor result = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||||
|
|
||||||
|
float minSad = -1.0f;
|
||||||
|
|
||||||
|
for (const auto& e : s_borderColors) {
|
||||||
|
float sad = 0.0f;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < componentCount; i++)
|
||||||
|
sad += std::abs(m_key.borderColor.float32[i] - e.first.float32[i]);
|
||||||
|
|
||||||
|
if (sad < minSad || minSad < 0.0f) {
|
||||||
|
minSad = sad;
|
||||||
|
result = e.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DxvkSamplerPool::DxvkSamplerPool(DxvkDevice* device)
|
||||||
|
: m_device(device) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkSamplerPool::~DxvkSamplerPool() {
|
||||||
|
m_samplers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rc<DxvkSampler> DxvkSamplerPool::createSampler(const DxvkSamplerKey& key) {
|
||||||
|
std::unique_lock lock(m_mutex);
|
||||||
|
auto entry = m_samplers.find(key);
|
||||||
|
|
||||||
|
if (entry != m_samplers.end()) {
|
||||||
|
DxvkSampler* sampler = &entry->second;
|
||||||
|
|
||||||
|
// Remove the sampler from the LRU list if it's in there. Due
|
||||||
|
// to the way releasing samplers is implemented upon reaching
|
||||||
|
// a ref count of 0, it is possible that we reach this before
|
||||||
|
// the releasing thread inserted the list into the LRU list.
|
||||||
|
if (!sampler->m_refCount.fetch_add(1u, std::memory_order_acquire)) {
|
||||||
|
if (sampler->m_lruPrev)
|
||||||
|
sampler->m_lruPrev->m_lruNext = sampler->m_lruNext;
|
||||||
|
else if (m_lruHead == sampler)
|
||||||
|
m_lruHead = sampler->m_lruNext;
|
||||||
|
|
||||||
|
if (sampler->m_lruNext)
|
||||||
|
sampler->m_lruNext->m_lruPrev = sampler->m_lruPrev;
|
||||||
|
else if (m_lruTail == sampler)
|
||||||
|
m_lruTail = sampler->m_lruPrev;
|
||||||
|
|
||||||
|
sampler->m_lruPrev = nullptr;
|
||||||
|
sampler->m_lruNext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We already took a reference, forward the pointer as-is
|
||||||
|
return Rc<DxvkSampler>::unsafeCreate(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're spamming sampler allocations, we might need
|
||||||
|
// to clean up unused ones here to stay within the limit
|
||||||
|
if (m_samplers.size() >= MaxSamplerCount)
|
||||||
|
destroyLeastRecentlyUsedSampler();
|
||||||
|
|
||||||
|
// Create new sampler object
|
||||||
|
return &m_samplers.emplace(std::piecewise_construct,
|
||||||
|
std::forward_as_tuple(key),
|
||||||
|
std::forward_as_tuple(this, key)).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkSamplerPool::releaseSampler(DxvkSampler* sampler) {
|
||||||
|
std::unique_lock lock(m_mutex);
|
||||||
|
|
||||||
|
// Back off if another thread has re-aquired the sampler. This is
|
||||||
|
// safe since the ref count can only be incremented from zero when
|
||||||
|
// the pool is locked.
|
||||||
|
if (sampler->m_refCount.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// It is also possible that two threads end up here while the ref
|
||||||
|
// count is zero. Make sure to not add the sampler to the LRU list
|
||||||
|
// more than once in that case.
|
||||||
|
if (sampler->m_lruPrev || m_lruHead == sampler)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add sampler to the end of the LRU list
|
||||||
|
sampler->m_lruPrev = m_lruTail;
|
||||||
|
sampler->m_lruNext = nullptr;
|
||||||
|
|
||||||
|
if (m_lruTail)
|
||||||
|
m_lruTail->m_lruNext = sampler;
|
||||||
|
else
|
||||||
|
m_lruHead = sampler;
|
||||||
|
|
||||||
|
m_lruTail = sampler;
|
||||||
|
|
||||||
|
// Try to keep some samplers available for subsequent allocations
|
||||||
|
if (m_samplers.size() > MinSamplerCount)
|
||||||
|
destroyLeastRecentlyUsedSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkSamplerPool::destroyLeastRecentlyUsedSampler() {
|
||||||
|
DxvkSampler* sampler = m_lruHead;
|
||||||
|
|
||||||
|
if (sampler) {
|
||||||
|
m_lruHead = sampler->m_lruNext;
|
||||||
|
|
||||||
|
if (m_lruHead)
|
||||||
|
m_lruHead->m_lruPrev = nullptr;
|
||||||
|
else
|
||||||
|
m_lruTail = nullptr;
|
||||||
|
|
||||||
|
m_samplers.erase(sampler->key());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,50 +1,131 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "../util/util_bit.h"
|
||||||
|
#include "../util/thread.h"
|
||||||
|
|
||||||
#include "dxvk_resource.h"
|
#include "dxvk_resource.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
class DxvkDevice;
|
class DxvkDevice;
|
||||||
|
class DxvkSamplerPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sampler properties
|
* \brief Sampler key
|
||||||
|
*
|
||||||
|
* Stores packed sampler properties and in a way that
|
||||||
|
* can be reasonably efficiently used with a hash map.
|
||||||
*/
|
*/
|
||||||
struct DxvkSamplerCreateInfo {
|
struct DxvkSamplerKey {
|
||||||
/// Texture filter propertoes
|
union {
|
||||||
VkFilter magFilter;
|
struct {
|
||||||
VkFilter minFilter;
|
uint32_t minFilter : 1;
|
||||||
|
uint32_t magFilter : 1;
|
||||||
/// Mipmapping properties
|
uint32_t mipMode : 1;
|
||||||
VkSamplerMipmapMode mipmapMode;
|
uint32_t anisotropy : 5;
|
||||||
float mipmapLodBias;
|
|
||||||
float mipmapLodMin;
|
|
||||||
float mipmapLodMax;
|
|
||||||
|
|
||||||
/// Anisotropic filtering
|
|
||||||
VkBool32 useAnisotropy;
|
|
||||||
float maxAnisotropy;
|
|
||||||
|
|
||||||
/// Address modes
|
|
||||||
VkSamplerAddressMode addressModeU;
|
|
||||||
VkSamplerAddressMode addressModeV;
|
|
||||||
VkSamplerAddressMode addressModeW;
|
|
||||||
|
|
||||||
/// Compare op for shadow textures
|
|
||||||
VkBool32 compareToDepth;
|
|
||||||
VkCompareOp compareOp;
|
|
||||||
|
|
||||||
/// Reduction mode for min/max samplers
|
|
||||||
VkSamplerReductionMode reductionMode;
|
|
||||||
|
|
||||||
/// Texture border color
|
|
||||||
VkClearColorValue borderColor;
|
|
||||||
|
|
||||||
/// Enables unnormalized coordinates
|
uint32_t addressU : 3;
|
||||||
VkBool32 usePixelCoord;
|
uint32_t addressV : 3;
|
||||||
|
uint32_t addressW : 3;
|
||||||
|
uint32_t hasBorder : 1;
|
||||||
|
|
||||||
|
uint32_t lodBias : 14;
|
||||||
|
|
||||||
|
uint32_t minLod : 12;
|
||||||
|
uint32_t maxLod : 12;
|
||||||
|
|
||||||
|
uint32_t compareEnable : 1;
|
||||||
|
uint32_t compareOp : 3;
|
||||||
|
uint32_t reduction : 2;
|
||||||
|
uint32_t pixelCoord : 1;
|
||||||
|
uint32_t legacyCube : 1;
|
||||||
|
} p;
|
||||||
|
|
||||||
|
uint32_t properties[2] = { 0u, 0u };
|
||||||
|
} u;
|
||||||
|
|
||||||
|
VkClearColorValue borderColor = { };
|
||||||
|
|
||||||
|
void setFilter(VkFilter min, VkFilter mag, VkSamplerMipmapMode mip) {
|
||||||
|
u.p.minFilter = uint32_t(min);
|
||||||
|
u.p.magFilter = uint32_t(mag);
|
||||||
|
u.p.mipMode = uint32_t(mip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAniso(uint32_t anisotropy) {
|
||||||
|
u.p.anisotropy = std::min(anisotropy, 16u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDepthCompare(bool enable, VkCompareOp op) {
|
||||||
|
u.p.compareEnable = uint32_t(enable);
|
||||||
|
u.p.compareOp = enable ? uint32_t(op) : 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setReduction(VkSamplerReductionMode reduction) {
|
||||||
|
u.p.reduction = uint32_t(reduction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUsePixelCoordinates(bool enable) {
|
||||||
|
u.p.pixelCoord = uint32_t(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLegacyCubeFilter(bool enable) {
|
||||||
|
u.p.legacyCube = uint32_t(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAddressModes(VkSamplerAddressMode u_, VkSamplerAddressMode v_, VkSamplerAddressMode w_) {
|
||||||
|
u.p.addressU = u_;
|
||||||
|
u.p.addressV = v_;
|
||||||
|
u.p.addressW = w_;
|
||||||
|
u.p.hasBorder = uint32_t(u_ == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
|
||||||
|
|| v_ == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
|
||||||
|
|| w_ == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLodRange(float min, float max, float bias) {
|
||||||
|
u.p.minLod = bit::encodeFixed<uint32_t, 4, 8>(min);
|
||||||
|
u.p.maxLod = bit::encodeFixed<uint32_t, 4, 8>(max);
|
||||||
|
u.p.lodBias = bit::encodeFixed<int32_t, 6, 8>(bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBorderColor(VkClearColorValue color) {
|
||||||
|
borderColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eq(const DxvkSamplerKey& other) const {
|
||||||
|
bool eq = u.properties[0] == other.u.properties[0]
|
||||||
|
&& u.properties[1] == other.u.properties[1];
|
||||||
|
|
||||||
|
if (eq && u.p.hasBorder) {
|
||||||
|
eq = borderColor.uint32[0] == other.borderColor.uint32[0]
|
||||||
|
&& borderColor.uint32[1] == other.borderColor.uint32[1]
|
||||||
|
&& borderColor.uint32[2] == other.borderColor.uint32[2]
|
||||||
|
&& borderColor.uint32[3] == other.borderColor.uint32[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
hash.add(u.properties[0]);
|
||||||
|
hash.add(u.properties[1]);
|
||||||
|
|
||||||
|
if (u.p.hasBorder) {
|
||||||
|
hash.add(borderColor.uint32[0]);
|
||||||
|
hash.add(borderColor.uint32[1]);
|
||||||
|
hash.add(borderColor.uint32[2]);
|
||||||
|
hash.add(borderColor.uint32[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
/// Enables non seamless cube map filtering
|
|
||||||
VkBool32 nonSeamless;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DxvkSamplerKey) == 24u);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,15 +135,33 @@ namespace dxvk {
|
|||||||
* a pipeline. Sampler objects provide parameters
|
* a pipeline. Sampler objects provide parameters
|
||||||
* for texture lookups within a shader.
|
* for texture lookups within a shader.
|
||||||
*/
|
*/
|
||||||
class DxvkSampler : public DxvkResource {
|
class DxvkSampler {
|
||||||
|
friend class DxvkSamplerPool;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DxvkSampler(
|
DxvkSampler(
|
||||||
DxvkDevice* device,
|
DxvkSamplerPool* pool,
|
||||||
const DxvkSamplerCreateInfo& info);
|
const DxvkSamplerKey& key);
|
||||||
|
|
||||||
~DxvkSampler();
|
~DxvkSampler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Increments reference count
|
||||||
|
*/
|
||||||
|
force_inline void incRef() {
|
||||||
|
m_refCount.fetch_add(1u, std::memory_order_acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decrements reference count
|
||||||
|
*
|
||||||
|
* Recycles the sampler once the ref count reaches zero.
|
||||||
|
*/
|
||||||
|
force_inline void decRef() {
|
||||||
|
if (m_refCount.fetch_sub(1u, std::memory_order_relaxed) == 1u)
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sampler handle
|
* \brief Sampler handle
|
||||||
* \returns Sampler handle
|
* \returns Sampler handle
|
||||||
@ -71,15 +170,77 @@ namespace dxvk {
|
|||||||
return m_sampler;
|
return m_sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sampler key
|
||||||
|
* \returns Sampler properties
|
||||||
|
*/
|
||||||
|
const DxvkSamplerKey& key() const {
|
||||||
|
return m_key;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Rc<vk::DeviceFn> m_vkd;
|
std::atomic<uint32_t> m_refCount = { 0u };
|
||||||
VkSampler m_sampler = VK_NULL_HANDLE;
|
|
||||||
|
DxvkSamplerPool* m_pool = nullptr;
|
||||||
|
DxvkSamplerKey m_key = { };
|
||||||
|
|
||||||
|
VkSampler m_sampler = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
DxvkSampler* m_lruPrev = nullptr;
|
||||||
|
DxvkSampler* m_lruNext = nullptr;
|
||||||
|
|
||||||
|
void release();
|
||||||
|
|
||||||
|
VkBorderColor determineBorderColorType() const;
|
||||||
|
|
||||||
static VkBorderColor getBorderColor(
|
|
||||||
const Rc<DxvkDevice>& device,
|
|
||||||
const DxvkSamplerCreateInfo& info);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sampler pool
|
||||||
|
*
|
||||||
|
* Manages unique samplers within a device.
|
||||||
|
*/
|
||||||
|
class DxvkSamplerPool {
|
||||||
|
friend DxvkSampler;
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The Vulkan limit for samplers is at least 4000.
|
||||||
|
// Keep some objects available for internal use.
|
||||||
|
constexpr static uint32_t MaxSamplerCount = 3584u;
|
||||||
|
|
||||||
|
// Minimum number of samplers to keep alive.
|
||||||
|
constexpr static uint32_t MinSamplerCount = 1024u;
|
||||||
|
|
||||||
|
DxvkSamplerPool(DxvkDevice* device);
|
||||||
|
|
||||||
|
~DxvkSamplerPool();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates sampler
|
||||||
|
*
|
||||||
|
* \param [in] key Sampler key
|
||||||
|
* \returns Sampler object
|
||||||
|
*/
|
||||||
|
Rc<DxvkSampler> createSampler(const DxvkSamplerKey& key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DxvkDevice* m_device;
|
||||||
|
|
||||||
|
dxvk::mutex m_mutex;
|
||||||
|
std::unordered_map<DxvkSamplerKey,
|
||||||
|
DxvkSampler, DxvkHash, DxvkEq> m_samplers;
|
||||||
|
|
||||||
|
DxvkSampler* m_lruHead = nullptr;
|
||||||
|
DxvkSampler* m_lruTail = nullptr;
|
||||||
|
|
||||||
|
void releaseSampler(DxvkSampler* sampler);
|
||||||
|
|
||||||
|
void destroyLeastRecentlyUsedSampler();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -286,30 +286,23 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void DxvkSwapchainBlitter::createSampler() {
|
void DxvkSwapchainBlitter::createSampler() {
|
||||||
DxvkSamplerCreateInfo samplerInfo;
|
DxvkSamplerKey samplerInfo = { };
|
||||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
samplerInfo.setFilter(VK_FILTER_LINEAR, VK_FILTER_LINEAR,
|
||||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
samplerInfo.setAddressModes(
|
||||||
samplerInfo.mipmapLodBias = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||||
samplerInfo.mipmapLodMin = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||||
samplerInfo.mipmapLodMax = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER);
|
||||||
samplerInfo.useAnisotropy = VK_FALSE;
|
samplerInfo.setUsePixelCoordinates(true);
|
||||||
samplerInfo.maxAnisotropy = 1.0f;
|
|
||||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
||||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
||||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
||||||
samplerInfo.compareToDepth = VK_FALSE;
|
|
||||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
samplerInfo.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
|
||||||
samplerInfo.borderColor = VkClearColorValue();
|
|
||||||
samplerInfo.usePixelCoord = VK_TRUE;
|
|
||||||
samplerInfo.nonSeamless = VK_FALSE;
|
|
||||||
m_samplerPresent = m_device->createSampler(samplerInfo);
|
m_samplerPresent = m_device->createSampler(samplerInfo);
|
||||||
|
|
||||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
samplerInfo.setAddressModes(
|
||||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
samplerInfo.usePixelCoord = VK_FALSE;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
|
||||||
|
samplerInfo.setUsePixelCoordinates(false);
|
||||||
|
|
||||||
m_samplerGamma = m_device->createSampler(samplerInfo);
|
m_samplerGamma = m_device->createSampler(samplerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,25 +54,15 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
Rc<DxvkSampler> DxvkUnboundResources::createSampler() {
|
Rc<DxvkSampler> DxvkUnboundResources::createSampler() {
|
||||||
DxvkSamplerCreateInfo info;
|
DxvkSamplerKey info;
|
||||||
info.minFilter = VK_FILTER_LINEAR;
|
info.setFilter(VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR);
|
||||||
info.magFilter = VK_FILTER_LINEAR;
|
info.setLodRange(-256.0f, 256.0f, 0.0f);
|
||||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
info.setAddressModes(
|
||||||
info.mipmapLodBias = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
info.mipmapLodMin = -256.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
info.mipmapLodMax = 256.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
|
||||||
info.useAnisotropy = VK_FALSE;
|
info.setReduction(VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE);
|
||||||
info.maxAnisotropy = 1.0f;
|
|
||||||
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.compareToDepth = VK_FALSE;
|
|
||||||
info.compareOp = VK_COMPARE_OP_NEVER;
|
|
||||||
info.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
|
||||||
info.borderColor = VkClearColorValue();
|
|
||||||
info.usePixelCoord = VK_FALSE;
|
|
||||||
info.nonSeamless = VK_FALSE;
|
|
||||||
|
|
||||||
return m_device->createSampler(info);
|
return m_device->createSampler(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,24 +321,14 @@ namespace dxvk::hud {
|
|||||||
|
|
||||||
|
|
||||||
Rc<DxvkSampler> HudRenderer::createFontSampler() {
|
Rc<DxvkSampler> HudRenderer::createFontSampler() {
|
||||||
DxvkSamplerCreateInfo info;
|
DxvkSamplerKey info = { };
|
||||||
info.magFilter = VK_FILTER_LINEAR;
|
info.setFilter(VK_FILTER_LINEAR,
|
||||||
info.minFilter = VK_FILTER_LINEAR;
|
VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
info.setAddressModes(
|
||||||
info.mipmapLodBias = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
info.mipmapLodMin = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||||
info.mipmapLodMax = 0.0f;
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
|
||||||
info.useAnisotropy = VK_FALSE;
|
info.setUsePixelCoordinates(true);
|
||||||
info.maxAnisotropy = 1.0f;
|
|
||||||
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
info.compareToDepth = VK_FALSE;
|
|
||||||
info.compareOp = VK_COMPARE_OP_NEVER;
|
|
||||||
info.reductionMode = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE;
|
|
||||||
info.borderColor = VkClearColorValue();
|
|
||||||
info.usePixelCoord = VK_TRUE;
|
|
||||||
info.nonSeamless = VK_FALSE;
|
|
||||||
|
|
||||||
return m_device->createSampler(info);
|
return m_device->createSampler(info);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -107,19 +109,47 @@ namespace dxvk {
|
|||||||
return m_object != nullptr;
|
return m_object != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Sets pointer without acquiring a reference
|
||||||
|
*
|
||||||
|
* Must only be use when a reference has been taken via
|
||||||
|
* other means.
|
||||||
|
* \param [in] object Object pointer
|
||||||
|
*/
|
||||||
void unsafeInsert(T* object) {
|
void unsafeInsert(T* object) {
|
||||||
this->decRef();
|
this->decRef();
|
||||||
m_object = object;
|
m_object = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Extracts raw pointer
|
||||||
|
*
|
||||||
|
* Sets the smart pointer to null without decrementing the
|
||||||
|
* reference count. Must only be used when the reference
|
||||||
|
* count is decremented in some other way.
|
||||||
|
* \returns Pointer to owned object
|
||||||
|
*/
|
||||||
T* unsafeExtract() {
|
T* unsafeExtract() {
|
||||||
return std::exchange(m_object, nullptr);
|
return std::exchange(m_object, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Creates smart pointer without taking reference
|
||||||
|
*
|
||||||
|
* Must only be used when a refernece has been obtained via other means.
|
||||||
|
* \param [in] object Pointer to object to take ownership of
|
||||||
|
*/
|
||||||
|
static Rc<T> unsafeCreate(T* object) {
|
||||||
|
return Rc<T>(object, false);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
T* m_object = nullptr;
|
T* m_object = nullptr;
|
||||||
|
|
||||||
|
explicit Rc(T* object, bool)
|
||||||
|
: m_object(object) { }
|
||||||
|
|
||||||
force_inline void incRef() const {
|
force_inline void incRef() const {
|
||||||
if (m_object != nullptr)
|
if (m_object != nullptr)
|
||||||
m_object->incRef();
|
m_object->incRef();
|
||||||
@ -145,6 +175,13 @@ namespace dxvk {
|
|||||||
template<typename Tx, typename Ty>
|
template<typename Tx, typename Ty>
|
||||||
bool operator != (Tx* a, const Rc<Ty>& b) { return b != a; }
|
bool operator != (Tx* a, const Rc<Ty>& b) { return b != a; }
|
||||||
|
|
||||||
|
struct RcHash {
|
||||||
|
template<typename T>
|
||||||
|
size_t operator () (const Rc<T>& rc) const {
|
||||||
|
return reinterpret_cast<uintptr_t>(rc.ptr()) / sizeof(T);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
Loading…
Reference in New Issue
Block a user