Compare commits

..

2 Commits

Author SHA1 Message Date
Caio Oliveira f5f015e289 [chore] license headers 2026-02-17 16:24:40 +01:00
wildcard 731a995089 [Vulkan] Implement Pipeline Derivatives
Applies mostly on android devices, should be tested for regressions on other platforms as well just incase.
2026-02-17 16:24:40 +01:00
8 changed files with 59 additions and 28 deletions
+1 -2
View File
@@ -545,8 +545,7 @@ struct Values {
SwitchableSetting<bool> fix_bloom_effects{linkage, false, "fix_bloom_effects",
Category::RendererHacks};
SwitchableSetting<bool> force_smaller_buffers{linkage, false, "force_smaller_buffers",
Category::RendererHacks};
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererHacks};
@@ -340,10 +340,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
tr("Sync to framerate of video playback"),
tr("Run the game at normal speed during video playback, even when the framerate is "
"unlocked."));
INSERT(Settings,
force_smaller_buffers,
tr("Force smaller buffers"),
tr("Forces buffers to be smaller, may cause reads/writes out of bounds for some games but can fix Out-of-memory errors."));
INSERT(Settings,
barrier_feedback_loops,
tr("Barrier feedback loops"),
@@ -249,10 +249,12 @@ GraphicsPipeline::GraphicsPipeline(
GuestDescriptorQueue& guest_descriptor_queue_, Common::ThreadWorker* worker_thread,
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
const std::array<const Shader::Info*, NUM_STAGES>& infos)
: key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
pipeline_cache(pipeline_cache_), scheduler{scheduler_},
guest_descriptor_queue{guest_descriptor_queue_}, spv_modules{std::move(stages)} {
const std::array<const Shader::Info*, NUM_STAGES>& infos,
GraphicsPipeline* base_pipeline_)
: key{key_}, base_pipeline{base_pipeline_}, allow_derivatives{base_pipeline_ == nullptr},
device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
pipeline_cache(pipeline_cache_), scheduler{scheduler_},
guest_descriptor_queue{guest_descriptor_queue_}, spv_modules{std::move(stages)} {
if (shader_notify) {
shader_notify->MarkShaderBuilding();
}
@@ -941,6 +943,18 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) {
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
}
VkPipeline base_handle = VK_NULL_HANDLE;
// First pipeline in a "cluster" allows derivatives
if (allow_derivatives) {
flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
}
// Children mark themselves as derivatives when base is already built
if (base_pipeline != nullptr && base_pipeline->IsBuilt()) {
flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
base_handle = *base_pipeline->pipeline;
}
pipeline = device.GetLogical().CreateGraphicsPipeline(
{
@@ -961,8 +975,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.layout = *pipeline_layout,
.renderPass = render_pass,
.subpass = 0,
.basePipelineHandle = nullptr,
.basePipelineIndex = 0,
.basePipelineHandle = base_handle,
.basePipelineIndex = -1,
},
*pipeline_cache);
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -79,7 +79,9 @@ public:
GuestDescriptorQueue& guest_descriptor_queue, Common::ThreadWorker* worker_thread,
PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
const std::array<const Shader::Info*, NUM_STAGES>& infos);
const std::array<const Shader::Info*, NUM_STAGES>& infos,
GraphicsPipeline* base_pipeline = nullptr);
bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; }
bool SupportsAlphaToCoverage() const noexcept {
@@ -93,6 +95,11 @@ public:
bool UsesExtendedDynamicState() const noexcept {
return key.state.extended_dynamic_state != 0;
}
[[nodiscard]] const GraphicsPipelineCacheKey& Key() const noexcept {
return key;
}
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
@@ -140,6 +147,8 @@ private:
void Validate();
const GraphicsPipelineCacheKey key;
GraphicsPipeline* base_pipeline = nullptr; // non-owning
bool allow_derivatives = false;
Tegra::Engines::Maxwell3D* maxwell3d;
Tegra::MemoryManager* gpu_memory;
const Device& device;
@@ -625,7 +625,16 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)};
auto& pipeline{pair->second};
if (is_new) {
pipeline = CreateGraphicsPipeline();
GraphicsPipeline* base = nullptr;
// Use the current pipeline as a base if shaders match
if (current_pipeline) {
const auto& base_key = current_pipeline->Key();
if (base_key.unique_hashes == graphics_key.unique_hashes) {
base = current_pipeline;
}
}
pipeline = CreateGraphicsPipeline(base);
}
if (!pipeline) {
return nullptr;
@@ -657,7 +666,7 @@ GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const
std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
ShaderPools& pools, const GraphicsPipelineCacheKey& key,
std::span<Shader::Environment* const> envs, PipelineStatistics* statistics,
bool build_in_parallel) try {
bool build_in_parallel, GraphicsPipeline* base_pipeline) try {
auto hash = key.Hash();
LOG_INFO(Render_Vulkan, "0x{:016x}", hash);
size_t env_index{0};
@@ -747,7 +756,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
return std::make_unique<GraphicsPipeline>(
scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device,
descriptor_pool, guest_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
std::move(modules), infos);
std::move(modules), infos, base_pipeline);
} catch (const Shader::Exception& exception) {
auto hash = key.Hash();
@@ -768,16 +777,23 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
}
std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline() {
// Preserve old behaviour, no base pipeline
return CreateGraphicsPipeline(nullptr);
}
std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
GraphicsPipeline* base_pipeline) {
GraphicsEnvironments environments;
GetGraphicsEnvironments(environments, graphics_key.unique_hashes);
main_pools.ReleaseContents();
auto pipeline{
CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(), nullptr, true)};
auto pipeline{CreateGraphicsPipeline(main_pools, graphics_key, environments.Span(),
nullptr, true, base_pipeline)};
if (!pipeline || pipeline_cache_filename.empty()) {
return pipeline;
}
serialization_thread.QueueWork([this, key = graphics_key, envs = std::move(environments.envs)] {
serialization_thread.QueueWork(
[this, key = graphics_key, envs = std::move(environments.envs)] {
boost::container::static_vector<const GenericEnvironment*, Maxwell::MaxShaderProgram>
env_ptrs;
for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
@@ -122,11 +122,12 @@ private:
[[nodiscard]] GraphicsPipeline* BuiltPipeline(GraphicsPipeline* pipeline) const noexcept;
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline();
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(GraphicsPipeline* base_pipeline);
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(
ShaderPools& pools, const GraphicsPipelineCacheKey& key,
std::span<Shader::Environment* const> envs, PipelineStatistics* statistics,
bool build_in_parallel);
bool build_in_parallel, GraphicsPipeline* base_pipeline = nullptr);
std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineCacheKey& key,
const ShaderInfo* shader);
@@ -15,7 +15,6 @@
#include <vector>
#include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "common/bit_util.h"
#include "common/settings.h"
#include "common/common_types.h"
#include "video_core/engines/draw_manager.h"
#include "video_core/host1x/gpu_device_memory_manager.h"
@@ -544,9 +543,7 @@ private:
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = ::Settings::values.force_smaller_buffers.GetValue()
? (SamplesQueryBank::QUERY_SIZE * (1ULL << log_2))
: (SamplesQueryBank::QUERY_SIZE * num_needed),
.size = SamplesQueryBank::QUERY_SIZE * (1ULL << log_2),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -14,7 +14,6 @@
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/settings.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
@@ -187,7 +186,7 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = ::Settings::values.force_smaller_buffers.GetValue() ? size : (1ULL << log2),
.size = 1ULL << log2,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,