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>
|
template<uint32 TRegisterBase>
|
||||||
LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
||||||
{
|
{
|
||||||
|
nWords--; // subtract the register offset field
|
||||||
uint32 registerOffset = LatteReadCMD();
|
uint32 registerOffset = LatteReadCMD();
|
||||||
uint32 registerIndex = TRegisterBase + registerOffset;
|
uint32 registerIndex = TRegisterBase + registerOffset;
|
||||||
uint32 registerStartIndex = registerIndex;
|
uint32 registerStartIndex = registerIndex;
|
||||||
@ -324,7 +325,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
|||||||
// state shadowing enabled
|
// state shadowing enabled
|
||||||
uint32* __restrict shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
uint32* __restrict shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
||||||
sint32 indexCounter = 0;
|
sint32 indexCounter = 0;
|
||||||
while (--nWords)
|
while (nWords--)
|
||||||
{
|
{
|
||||||
uint32 dataWord = LatteReadCMD();
|
uint32 dataWord = LatteReadCMD();
|
||||||
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
||||||
@ -337,10 +338,19 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// state shadowing disabled
|
// state shadowing disabled
|
||||||
while (--nWords)
|
if (nWords == 1) // common case
|
||||||
{
|
{
|
||||||
*outputReg = LatteReadCMD();
|
*outputReg = LatteReadCMD();
|
||||||
outputReg++;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sint32 i = 0;
|
||||||
|
while (i < nWords)
|
||||||
|
{
|
||||||
|
outputReg[i] = cmd[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
cmd += nWords;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// some register writes trigger special behavior
|
// some register writes trigger special behavior
|
||||||
@ -352,6 +362,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)
|
|||||||
template<uint32 TRegisterBase, typename TRegRangeCallback>
|
template<uint32 TRegisterBase, typename TRegRangeCallback>
|
||||||
bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange)
|
bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange)
|
||||||
{
|
{
|
||||||
|
nWords--;
|
||||||
const uint32 registerOffset = LatteReadCMD();
|
const uint32 registerOffset = LatteReadCMD();
|
||||||
const uint32 registerIndex = TRegisterBase + registerOffset;
|
const uint32 registerIndex = TRegisterBase + registerOffset;
|
||||||
const uint32 registerStartIndex = registerIndex;
|
const uint32 registerStartIndex = registerIndex;
|
||||||
@ -365,7 +376,7 @@ bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCal
|
|||||||
// state shadowing enabled
|
// state shadowing enabled
|
||||||
uint32* shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
uint32* shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;
|
||||||
sint32 indexCounter = 0;
|
sint32 indexCounter = 0;
|
||||||
while (--nWords)
|
while (nWords--)
|
||||||
{
|
{
|
||||||
uint32 dataWord = LatteReadCMD();
|
uint32 dataWord = LatteReadCMD();
|
||||||
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
MPTR regShadowAddr = shadowAddrs[indexCounter];
|
||||||
@ -379,13 +390,23 @@ bool LatteCP_itSetRegistersGeneric2(LatteCMDPtr cmd, uint32 nWords, TRegRangeCal
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// state shadowing disabled
|
// state shadowing disabled
|
||||||
sint32 indexCounter = 0;
|
if (nWords == 1) // common case
|
||||||
while (--nWords)
|
|
||||||
{
|
{
|
||||||
uint32 dataWord = LatteReadCMD();
|
uint32 v = LatteReadCMD();
|
||||||
hasRegChange |= (*outputReg != dataWord);
|
hasRegChange |= (*outputReg != v);
|
||||||
*outputReg = dataWord;
|
*outputReg = v;
|
||||||
outputReg++;
|
}
|
||||||
|
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
|
// some register writes trigger special behavior
|
||||||
|
|||||||
@ -109,16 +109,13 @@ namespace LatteConst
|
|||||||
{
|
{
|
||||||
enum class ShaderType : uint32
|
enum class ShaderType : uint32
|
||||||
{
|
{
|
||||||
Reserved = 0,
|
|
||||||
// shaders for drawing
|
// shaders for drawing
|
||||||
FirstRender = 1,
|
Vertex = 0,
|
||||||
Vertex = 1,
|
Pixel = 1,
|
||||||
Pixel = 2,
|
Geometry = 2,
|
||||||
Geometry = 3,
|
|
||||||
LastRender = 3,
|
|
||||||
// compute shader
|
// compute shader
|
||||||
Compute = 4,
|
Compute = 3,
|
||||||
TotalCount = 5
|
TotalCount = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class VertexFetchNFA
|
enum class VertexFetchNFA
|
||||||
|
|||||||
@ -58,20 +58,13 @@ PipelineInfo::~PipelineInfo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete descriptor sets
|
// delete descriptor sets
|
||||||
while (!pixel_ds_cache.empty())
|
for (auto& it : ds_cache)
|
||||||
{
|
{
|
||||||
VkDescriptorSetInfo* dsInfo = pixel_ds_cache.begin()->second;
|
while (!it.empty())
|
||||||
delete dsInfo;
|
{
|
||||||
}
|
VkDescriptorSetInfo* dsInfo = it.begin()->second;
|
||||||
while (!geometry_ds_cache.empty())
|
delete dsInfo;
|
||||||
{
|
}
|
||||||
VkDescriptorSetInfo* dsInfo = geometry_ds_cache.begin()->second;
|
|
||||||
delete dsInfo;
|
|
||||||
}
|
|
||||||
while (!vertex_ds_cache.empty())
|
|
||||||
{
|
|
||||||
VkDescriptorSetInfo* dsInfo = vertex_ds_cache.begin()->second;
|
|
||||||
delete dsInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disassociate from shaders
|
// disassociate from shaders
|
||||||
|
|||||||
@ -3374,29 +3374,8 @@ VkDescriptorSetInfo::~VkDescriptorSetInfo()
|
|||||||
for (auto& it : list_referencedViews)
|
for (auto& it : list_referencedViews)
|
||||||
it->RemoveDescriptorSetReference(this);
|
it->RemoveDescriptorSetReference(this);
|
||||||
// unregister
|
// unregister
|
||||||
switch (shaderType)
|
auto r = pipeline_info->GetDescriptorSetCache(shaderType).erase(stateHash);
|
||||||
{
|
cemu_assert_debug(r == 1);
|
||||||
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;
|
|
||||||
}
|
|
||||||
// update global stats
|
// update global stats
|
||||||
performanceMonitor.vk.numDescriptorSamplerTextures.decrement(statsNumSamplerTextures);
|
performanceMonitor.vk.numDescriptorSamplerTextures.decrement(statsNumSamplerTextures);
|
||||||
performanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers);
|
performanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers);
|
||||||
|
|||||||
@ -55,12 +55,17 @@ private:
|
|||||||
|
|
||||||
namespace VulkanRendererConst
|
namespace VulkanRendererConst
|
||||||
{
|
{
|
||||||
static const inline int SHADER_STAGE_INDEX_VERTEX = 0;
|
static const inline int SHADER_STAGE_INDEX_VERTEX = static_cast<int>(LatteConst::ShaderType::Vertex);
|
||||||
static const inline int SHADER_STAGE_INDEX_FRAGMENT = 1;
|
static const inline int SHADER_STAGE_INDEX_FRAGMENT = static_cast<int>(LatteConst::ShaderType::Pixel);
|
||||||
static const inline int SHADER_STAGE_INDEX_GEOMETRY = 2;
|
static const inline int SHADER_STAGE_INDEX_GEOMETRY = static_cast<int>(LatteConst::ShaderType::Geometry);
|
||||||
static const inline int SHADER_STAGE_INDEX_COUNT = 3;
|
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
|
class PipelineInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -82,11 +87,18 @@ public:
|
|||||||
return k;
|
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)
|
// 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%
|
// robin_hood::unordered_flat_map<uint64, VkDescriptorSetInfo*> descriptor set cache; ~1.80%
|
||||||
// ska::bytell_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; -> 1.91%
|
// ska::bytell_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> descriptor set cache; -> 1.91%
|
||||||
ska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; // 1.71%
|
DescriptorSetCache ds_cache[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT]; // 1.71%
|
||||||
|
|
||||||
VKRObjectPipeline* m_vkrObjPipeline;
|
VKRObjectPipeline* m_vkrObjPipeline;
|
||||||
|
|
||||||
|
|||||||
@ -590,31 +590,27 @@ uint64 VulkanRenderer::GetDescriptorSetStateHash(LatteDecompilerShader* shader)
|
|||||||
VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo* pipeline_info, LatteDecompilerShader* shader)
|
VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo* pipeline_info, LatteDecompilerShader* shader)
|
||||||
{
|
{
|
||||||
const uint64 stateHash = GetDescriptorSetStateHash(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;
|
VkDescriptorSetLayout descriptor_set_layout;
|
||||||
switch (shader->shaderType)
|
switch (shader->shaderType)
|
||||||
{
|
{
|
||||||
case LatteConst::ShaderType::Vertex:
|
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;
|
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_vertexDSL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LatteConst::ShaderType::Pixel:
|
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;
|
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_pixelDSL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LatteConst::ShaderType::Geometry:
|
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;
|
descriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_geometryDSL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1006,26 +1002,7 @@ VkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo*
|
|||||||
if (!descriptorWrites.empty())
|
if (!descriptorWrites.empty())
|
||||||
vkUpdateDescriptorSets(m_logicalDevice, (uint32)descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_logicalDevice, (uint32)descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||||
|
|
||||||
switch (shader->shaderType)
|
ds_cache[stateHash] = dsInfo;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dsInfo;
|
return dsInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user