mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-09 17:14:47 -06:00
Vulkan: Additional smaller optimizations
This commit is contained in:
parent
6d050e68ea
commit
a5d8ceb0dd
@ -311,6 +311,7 @@ void LatteCP_itSetRegistersGeneric_handleSpecialRanges(uint32 registerStartIndex
|
||||
template<uint32 TRegisterBase>
|
||||
LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
||||
{
|
||||
nWords--; // subtract the register offset field
|
||||
uint32 registerOffset = LatteReadCMD();
|
||||
uint32 registerIndex = TRegisterBase + registerOffset;
|
||||
uint32 registerStartIndex = registerIndex;
|
||||
@ -324,7 +325,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
||||
// state shadowing enabled
|
||||
uint32* __restrict shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
||||
sint32 indexCounter = 0;
|
||||
while (--nWords)
|
||||
while (nWords--)
|
||||
{
|
||||
uint32 dataWord = LatteReadCMD();
|
||||
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
||||
@ -337,10 +338,19 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
||||
else
|
||||
{
|
||||
// state shadowing disabled
|
||||
while (--nWords)
|
||||
if (nWords == 1) // common case
|
||||
{
|
||||
*outputReg = LatteReadCMD();
|
||||
outputReg++;
|
||||
}
|
||||
else
|
||||
{
|
||||
sint32 i = 0;
|
||||
while (i < nWords)
|
||||
{
|
||||
outputReg[i] = cmd[i];
|
||||
i++;
|
||||
}
|
||||
cmd += nWords;
|
||||
}
|
||||
}
|
||||
// some register writes trigger special behavior
|
||||
@ -352,6 +362,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
||||
template<uint32 TRegisterBase, typename TRegRangeCallback>
|
||||
bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange)
|
||||
{
|
||||
nWords--;
|
||||
const uint32 registerOffset = LatteReadCMD();
|
||||
const uint32 registerIndex = TRegisterBase + registerOffset;
|
||||
const uint32 registerStartIndex = registerIndex;
|
||||
@ -365,7 +376,7 @@ bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCal
|
||||
// state shadowing enabled
|
||||
uint32* shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
||||
sint32 indexCounter = 0;
|
||||
while (--nWords)
|
||||
while (nWords--)
|
||||
{
|
||||
uint32 dataWord = LatteReadCMD();
|
||||
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
||||
@ -379,13 +390,23 @@ bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCal
|
||||
else
|
||||
{
|
||||
// state shadowing disabled
|
||||
sint32 indexCounter = 0;
|
||||
while (--nWords)
|
||||
if (nWords == 1) // common case
|
||||
{
|
||||
uint32 dataWord = LatteReadCMD();
|
||||
hasRegChange |= (*outputReg != dataWord);
|
||||
*outputReg = dataWord;
|
||||
outputReg++;
|
||||
uint32 v = LatteReadCMD();
|
||||
hasRegChange |= (*outputReg != v);
|
||||
*outputReg = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
sint32 i = 0;
|
||||
while (i < nWords)
|
||||
{
|
||||
uint32 v = cmd[i];
|
||||
hasRegChange |= (outputReg[i] != v);
|
||||
outputReg[i] = v;
|
||||
i++;
|
||||
}
|
||||
cmd += nWords;
|
||||
}
|
||||
}
|
||||
// some register writes trigger special behavior
|
||||
|
||||
@ -109,16 +109,13 @@ namespace LatteConst
|
||||
{
|
||||
enum class ShaderType : uint32
|
||||
{
|
||||
Reserved = 0,
|
||||
// shaders for drawing
|
||||
FirstRender = 1,
|
||||
Vertex = 1,
|
||||
Pixel = 2,
|
||||
Geometry = 3,
|
||||
LastRender = 3,
|
||||
Vertex = 0,
|
||||
Pixel = 1,
|
||||
Geometry = 2,
|
||||
// compute shader
|
||||
Compute = 4,
|
||||
TotalCount = 5
|
||||
Compute = 3,
|
||||
TotalCount = 4
|
||||
};
|
||||
|
||||
enum class VertexFetchNFA
|
||||
|
||||
@ -58,20 +58,13 @@ PipelineInfo::~PipelineInfo()
|
||||
}
|
||||
|
||||
// delete descriptor sets
|
||||
while (!pixel_ds_cache.empty())
|
||||
for (auto& it : ds_cache)
|
||||
{
|
||||
VkDescriptorSetInfo* dsInfo = pixel_ds_cache.begin()->second;
|
||||
delete dsInfo;
|
||||
}
|
||||
while (!geometry_ds_cache.empty())
|
||||
{
|
||||
VkDescriptorSetInfo* dsInfo = geometry_ds_cache.begin()->second;
|
||||
delete dsInfo;
|
||||
}
|
||||
while (!vertex_ds_cache.empty())
|
||||
{
|
||||
VkDescriptorSetInfo* dsInfo = vertex_ds_cache.begin()->second;
|
||||
delete dsInfo;
|
||||
while (!it.empty())
|
||||
{
|
||||
VkDescriptorSetInfo* dsInfo = it.begin()->second;
|
||||
delete dsInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// disassociate from shaders
|
||||
|
||||
@ -3374,29 +3374,8 @@ VkDescriptorSetInfo::~VkDescriptorSetInfo()
|
||||
for (auto& it : list_referencedViews)
|
||||
it->RemoveDescriptorSetReference(this);
|
||||
// unregister
|
||||
switch (shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
auto r = pipeline_info->vertex_ds_cache.erase(stateHash);
|
||||
cemu_assert_debug(r == 1);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
auto r = pipeline_info->pixel_ds_cache.erase(stateHash);
|
||||
cemu_assert_debug(r == 1);
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
{
|
||||
auto r = pipeline_info->geometry_ds_cache.erase(stateHash);
|
||||
cemu_assert_debug(r == 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
auto r = pipeline_info->GetDescriptorSetCache(shaderType).erase(stateHash);
|
||||
cemu_assert_debug(r == 1);
|
||||
// update global stats
|
||||
performanceMonitor.vk.numDescriptorSamplerTextures.decrement(statsNumSamplerTextures);
|
||||
performanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers);
|
||||
|
||||
@ -55,12 +55,17 @@ private:
|
||||
|
||||
namespace VulkanRendererConst
|
||||
{
|
||||
static const inline int SHADER_STAGE_INDEX_VERTEX = 0;
|
||||
static const inline int SHADER_STAGE_INDEX_FRAGMENT = 1;
|
||||
static const inline int SHADER_STAGE_INDEX_GEOMETRY = 2;
|
||||
static const inline int SHADER_STAGE_INDEX_COUNT = 3;
|
||||
static const inline int SHADER_STAGE_INDEX_VERTEX = static_cast<int>(LatteConst::ShaderType::Vertex);
|
||||
static const inline int SHADER_STAGE_INDEX_FRAGMENT = static_cast<int>(LatteConst::ShaderType::Pixel);
|
||||
static const inline int SHADER_STAGE_INDEX_GEOMETRY = static_cast<int>(LatteConst::ShaderType::Geometry);
|
||||
static const inline int SHADER_STAGE_INDEX_COUNT = 4;
|
||||
};
|
||||
|
||||
// the order doesnt really matter but the types should cover range 0-2 since we use them as an array index
|
||||
static_assert(static_cast<int>(LatteConst::ShaderType::Vertex) == 0);
|
||||
static_assert(static_cast<int>(LatteConst::ShaderType::Pixel) == 1);
|
||||
static_assert(static_cast<int>(LatteConst::ShaderType::Geometry) == 2);
|
||||
|
||||
class PipelineInfo
|
||||
{
|
||||
public:
|
||||
@ -82,11 +87,18 @@ public:
|
||||
return k;
|
||||
}
|
||||
};
|
||||
using DescriptorSetCache = ska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>>;
|
||||
|
||||
FORCEINLINE DescriptorSetCache& GetDescriptorSetCache(LatteConst::ShaderType shaderType)
|
||||
{
|
||||
cemu_assert_debug(shaderType == LatteConst::ShaderType::Vertex || shaderType == LatteConst::ShaderType::Pixel || shaderType == LatteConst::ShaderType::Geometry);
|
||||
return ds_cache[static_cast<size_t>(shaderType)];
|
||||
}
|
||||
|
||||
// std::unordered_map<uint64, VkDescriptorSetInfo*> 3.16% (total CPU time)
|
||||
// robin_hood::unordered_flat_map<uint64, VkDescriptorSetInfo*> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; ~1.80%
|
||||
// ska::bytell_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; -> 1.91%
|
||||
ska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; // 1.71%
|
||||
// robin_hood::unordered_flat_map<uint64, VkDescriptorSetInfo*> descriptor set cache; ~1.80%
|
||||
// ska::bytell_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> descriptor set cache; -> 1.91%
|
||||
DescriptorSetCache ds_cache[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT]; // 1.71%
|
||||
|
||||
VKRObjectPipeline* m_vkrObjPipeline;
|
||||
|
||||
|
||||
@ -590,31 +590,27 @@ uint64 VulkanRenderer::GetDescriptorSetStateHash(LatteDecompilerShader* shader)
|
||||
VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo* pipeline_info, LatteDecompilerShader* shader)
|
||||
{
|
||||
const uint64 stateHash = GetDescriptorSetStateHash(shader);
|
||||
cemu_assert_debug(shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Pixel || shader->shaderType == LatteConst::ShaderType::Geometry);
|
||||
auto& ds_cache = pipeline_info->GetDescriptorSetCache(shader->shaderType);
|
||||
const auto it = ds_cache.find(stateHash);
|
||||
if (it != ds_cache.cend())
|
||||
return it->second;
|
||||
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
const auto it = pipeline_info->vertex_ds_cache.find(stateHash);
|
||||
if (it != pipeline_info->vertex_ds_cache.cend())
|
||||
return it->second;
|
||||
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_vertexDSL;
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
const auto it = pipeline_info->pixel_ds_cache.find(stateHash);
|
||||
if (it != pipeline_info->pixel_ds_cache.cend())
|
||||
return it->second;
|
||||
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_pixelDSL;
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
{
|
||||
const auto it = pipeline_info->geometry_ds_cache.find(stateHash);
|
||||
if (it != pipeline_info->geometry_ds_cache.cend())
|
||||
return it->second;
|
||||
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_geometryDSL;
|
||||
break;
|
||||
}
|
||||
@ -1006,26 +1002,7 @@ VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo*
|
||||
if (!descriptorWrites.empty())
|
||||
vkUpdateDescriptorSets(m_logicalDevice, (uint32)descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
|
||||
switch (shader->shaderType)
|
||||
{
|
||||
case LatteConst::ShaderType::Vertex:
|
||||
{
|
||||
pipeline_info->vertex_ds_cache[stateHash] = dsInfo;
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Pixel:
|
||||
{
|
||||
pipeline_info->pixel_ds_cache[stateHash] = dsInfo;
|
||||
break;
|
||||
}
|
||||
case LatteConst::ShaderType::Geometry:
|
||||
{
|
||||
pipeline_info->geometry_ds_cache[stateHash] = dsInfo;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
ds_cache[stateHash] = dsInfo;
|
||||
|
||||
return dsInfo;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user