Merge pull request #9708 from ameerj/gl-context-flush
gl_shader_cache: Force context flush when loading disk shader cache
This commit is contained in:
commit
8a33f8bd30
|
@ -30,7 +30,7 @@ bool ComputePipelineKey::operator==(const ComputePipelineKey& rhs) const noexcep
|
||||||
ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cache_,
|
ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cache_,
|
||||||
BufferCache& buffer_cache_, ProgramManager& program_manager_,
|
BufferCache& buffer_cache_, ProgramManager& program_manager_,
|
||||||
const Shader::Info& info_, std::string code,
|
const Shader::Info& info_, std::string code,
|
||||||
std::vector<u32> code_v)
|
std::vector<u32> code_v, bool force_context_flush)
|
||||||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
|
||||||
program_manager{program_manager_}, info{info_} {
|
program_manager{program_manager_}, info{info_} {
|
||||||
switch (device.GetShaderBackend()) {
|
switch (device.GetShaderBackend()) {
|
||||||
|
@ -63,6 +63,15 @@ ComputePipeline::ComputePipeline(const Device& device, TextureCache& texture_cac
|
||||||
writes_global_memory = !use_storage_buffers &&
|
writes_global_memory = !use_storage_buffers &&
|
||||||
std::ranges::any_of(info.storage_buffers_descriptors,
|
std::ranges::any_of(info.storage_buffers_descriptors,
|
||||||
[](const auto& desc) { return desc.is_written; });
|
[](const auto& desc) { return desc.is_written; });
|
||||||
|
if (force_context_flush) {
|
||||||
|
std::scoped_lock lock{built_mutex};
|
||||||
|
built_fence.Create();
|
||||||
|
// Flush this context to ensure compilation commands and fence are in the GPU pipe.
|
||||||
|
glFlush();
|
||||||
|
built_condvar.notify_one();
|
||||||
|
} else {
|
||||||
|
is_built = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComputePipeline::Configure() {
|
void ComputePipeline::Configure() {
|
||||||
|
@ -142,6 +151,9 @@ void ComputePipeline::Configure() {
|
||||||
}
|
}
|
||||||
texture_cache.FillComputeImageViews(std::span(views.data(), views.size()));
|
texture_cache.FillComputeImageViews(std::span(views.data(), views.size()));
|
||||||
|
|
||||||
|
if (!is_built) {
|
||||||
|
WaitForBuild();
|
||||||
|
}
|
||||||
if (assembly_program.handle != 0) {
|
if (assembly_program.handle != 0) {
|
||||||
program_manager.BindComputeAssemblyProgram(assembly_program.handle);
|
program_manager.BindComputeAssemblyProgram(assembly_program.handle);
|
||||||
} else {
|
} else {
|
||||||
|
@ -223,4 +235,13 @@ void ComputePipeline::Configure() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ComputePipeline::WaitForBuild() {
|
||||||
|
if (built_fence.handle == 0) {
|
||||||
|
std::unique_lock lock{built_mutex};
|
||||||
|
built_condvar.wait(lock, [this] { return built_fence.handle != 0; });
|
||||||
|
}
|
||||||
|
ASSERT(glClientWaitSync(built_fence.handle, 0, GL_TIMEOUT_IGNORED) != GL_WAIT_FAILED);
|
||||||
|
is_built = true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -50,7 +50,8 @@ class ComputePipeline {
|
||||||
public:
|
public:
|
||||||
explicit ComputePipeline(const Device& device, TextureCache& texture_cache_,
|
explicit ComputePipeline(const Device& device, TextureCache& texture_cache_,
|
||||||
BufferCache& buffer_cache_, ProgramManager& program_manager_,
|
BufferCache& buffer_cache_, ProgramManager& program_manager_,
|
||||||
const Shader::Info& info_, std::string code, std::vector<u32> code_v);
|
const Shader::Info& info_, std::string code, std::vector<u32> code_v,
|
||||||
|
bool force_context_flush = false);
|
||||||
|
|
||||||
void Configure();
|
void Configure();
|
||||||
|
|
||||||
|
@ -65,6 +66,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void WaitForBuild();
|
||||||
|
|
||||||
TextureCache& texture_cache;
|
TextureCache& texture_cache;
|
||||||
BufferCache& buffer_cache;
|
BufferCache& buffer_cache;
|
||||||
Tegra::MemoryManager* gpu_memory;
|
Tegra::MemoryManager* gpu_memory;
|
||||||
|
@ -81,6 +84,11 @@ private:
|
||||||
|
|
||||||
bool use_storage_buffers{};
|
bool use_storage_buffers{};
|
||||||
bool writes_global_memory{};
|
bool writes_global_memory{};
|
||||||
|
|
||||||
|
std::mutex built_mutex;
|
||||||
|
std::condition_variable built_condvar;
|
||||||
|
OGLSync built_fence{};
|
||||||
|
bool is_built{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -176,7 +176,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
|
||||||
std::array<std::string, 5> sources,
|
std::array<std::string, 5> sources,
|
||||||
std::array<std::vector<u32>, 5> sources_spirv,
|
std::array<std::vector<u32>, 5> sources_spirv,
|
||||||
const std::array<const Shader::Info*, 5>& infos,
|
const std::array<const Shader::Info*, 5>& infos,
|
||||||
const GraphicsPipelineKey& key_)
|
const GraphicsPipelineKey& key_, bool force_context_flush)
|
||||||
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
|
: texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, program_manager{program_manager_},
|
||||||
state_tracker{state_tracker_}, key{key_} {
|
state_tracker{state_tracker_}, key{key_} {
|
||||||
if (shader_notify) {
|
if (shader_notify) {
|
||||||
|
@ -231,7 +231,8 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
|
||||||
const bool in_parallel = thread_worker != nullptr;
|
const bool in_parallel = thread_worker != nullptr;
|
||||||
const auto backend = device.GetShaderBackend();
|
const auto backend = device.GetShaderBackend();
|
||||||
auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv),
|
auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv),
|
||||||
shader_notify, backend, in_parallel](ShaderContext::Context*) mutable {
|
shader_notify, backend, in_parallel,
|
||||||
|
force_context_flush](ShaderContext::Context*) mutable {
|
||||||
for (size_t stage = 0; stage < 5; ++stage) {
|
for (size_t stage = 0; stage < 5; ++stage) {
|
||||||
switch (backend) {
|
switch (backend) {
|
||||||
case Settings::ShaderBackend::GLSL:
|
case Settings::ShaderBackend::GLSL:
|
||||||
|
@ -251,7 +252,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_parallel) {
|
if (force_context_flush || in_parallel) {
|
||||||
std::scoped_lock lock{built_mutex};
|
std::scoped_lock lock{built_mutex};
|
||||||
built_fence.Create();
|
built_fence.Create();
|
||||||
// Flush this context to ensure compilation commands and fence are in the GPU pipe.
|
// Flush this context to ensure compilation commands and fence are in the GPU pipe.
|
||||||
|
|
|
@ -78,7 +78,7 @@ public:
|
||||||
std::array<std::string, 5> sources,
|
std::array<std::string, 5> sources,
|
||||||
std::array<std::vector<u32>, 5> sources_spirv,
|
std::array<std::vector<u32>, 5> sources_spirv,
|
||||||
const std::array<const Shader::Info*, 5>& infos,
|
const std::array<const Shader::Info*, 5>& infos,
|
||||||
const GraphicsPipelineKey& key_);
|
const GraphicsPipelineKey& key_, bool force_context_flush = false);
|
||||||
|
|
||||||
void Configure(bool is_indexed) {
|
void Configure(bool is_indexed) {
|
||||||
configure_func(this, is_indexed);
|
configure_func(this, is_indexed);
|
||||||
|
|
|
@ -286,7 +286,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||||
file.read(reinterpret_cast<char*>(&key), sizeof(key));
|
file.read(reinterpret_cast<char*>(&key), sizeof(key));
|
||||||
queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
|
queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable {
|
||||||
ctx->pools.ReleaseContents();
|
ctx->pools.ReleaseContents();
|
||||||
auto pipeline{CreateComputePipeline(ctx->pools, key, env)};
|
auto pipeline{CreateComputePipeline(ctx->pools, key, env, true)};
|
||||||
std::scoped_lock lock{state.mutex};
|
std::scoped_lock lock{state.mutex};
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
compute_cache.emplace(key, std::move(pipeline));
|
compute_cache.emplace(key, std::move(pipeline));
|
||||||
|
@ -307,7 +307,7 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading,
|
||||||
env_ptrs.push_back(&env);
|
env_ptrs.push_back(&env);
|
||||||
}
|
}
|
||||||
ctx->pools.ReleaseContents();
|
ctx->pools.ReleaseContents();
|
||||||
auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false)};
|
auto pipeline{CreateGraphicsPipeline(ctx->pools, key, MakeSpan(env_ptrs), false, true)};
|
||||||
std::scoped_lock lock{state.mutex};
|
std::scoped_lock lock{state.mutex};
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
graphics_cache.emplace(key, std::move(pipeline));
|
graphics_cache.emplace(key, std::move(pipeline));
|
||||||
|
@ -439,7 +439,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline() {
|
||||||
|
|
||||||
std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||||
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
|
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
|
||||||
std::span<Shader::Environment* const> envs, bool build_in_parallel) try {
|
std::span<Shader::Environment* const> envs, bool use_shader_workers,
|
||||||
|
bool force_context_flush) try {
|
||||||
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
||||||
size_t env_index{};
|
size_t env_index{};
|
||||||
u32 total_storage_buffers{};
|
u32 total_storage_buffers{};
|
||||||
|
@ -531,10 +532,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||||
}
|
}
|
||||||
previous_program = &program;
|
previous_program = &program;
|
||||||
}
|
}
|
||||||
auto* const thread_worker{build_in_parallel ? workers.get() : nullptr};
|
auto* const thread_worker{use_shader_workers ? workers.get() : nullptr};
|
||||||
return std::make_unique<GraphicsPipeline>(device, texture_cache, buffer_cache, program_manager,
|
return std::make_unique<GraphicsPipeline>(device, texture_cache, buffer_cache, program_manager,
|
||||||
state_tracker, thread_worker, &shader_notify, sources,
|
state_tracker, thread_worker, &shader_notify, sources,
|
||||||
sources_spirv, infos, key);
|
sources_spirv, infos, key, force_context_flush);
|
||||||
|
|
||||||
} catch (Shader::Exception& exception) {
|
} catch (Shader::Exception& exception) {
|
||||||
LOG_ERROR(Render_OpenGL, "{}", exception.what());
|
LOG_ERROR(Render_OpenGL, "{}", exception.what());
|
||||||
|
@ -559,8 +560,8 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||||
ShaderContext::ShaderPools& pools, const ComputePipelineKey& key,
|
ShaderContext::ShaderPools& pools, const ComputePipelineKey& key, Shader::Environment& env,
|
||||||
Shader::Environment& env) try {
|
bool force_context_flush) try {
|
||||||
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
LOG_INFO(Render_OpenGL, "0x{:016x}", key.Hash());
|
||||||
|
|
||||||
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
|
||||||
|
@ -589,7 +590,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<ComputePipeline>(device, texture_cache, buffer_cache, program_manager,
|
return std::make_unique<ComputePipeline>(device, texture_cache, buffer_cache, program_manager,
|
||||||
program.info, code, code_spirv);
|
program.info, code, code_spirv, force_context_flush);
|
||||||
} catch (Shader::Exception& exception) {
|
} catch (Shader::Exception& exception) {
|
||||||
LOG_ERROR(Render_OpenGL, "{}", exception.what());
|
LOG_ERROR(Render_OpenGL, "{}", exception.what());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -50,14 +50,16 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(
|
std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(
|
||||||
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
|
ShaderContext::ShaderPools& pools, const GraphicsPipelineKey& key,
|
||||||
std::span<Shader::Environment* const> envs, bool build_in_parallel);
|
std::span<Shader::Environment* const> envs, bool use_shader_workers,
|
||||||
|
bool force_context_flush = false);
|
||||||
|
|
||||||
std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineKey& key,
|
std::unique_ptr<ComputePipeline> CreateComputePipeline(const ComputePipelineKey& key,
|
||||||
const VideoCommon::ShaderInfo* shader);
|
const VideoCommon::ShaderInfo* shader);
|
||||||
|
|
||||||
std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderContext::ShaderPools& pools,
|
std::unique_ptr<ComputePipeline> CreateComputePipeline(ShaderContext::ShaderPools& pools,
|
||||||
const ComputePipelineKey& key,
|
const ComputePipelineKey& key,
|
||||||
Shader::Environment& env);
|
Shader::Environment& env,
|
||||||
|
bool force_context_flush = false);
|
||||||
|
|
||||||
std::unique_ptr<ShaderWorker> CreateWorkers() const;
|
std::unique_ptr<ShaderWorker> CreateWorkers() const;
|
||||||
|
|
||||||
|
|
Reference in New Issue