opengl: Fix asynchronous shaders
Wait for shader to build before configuring it, and wait for the shader to build before sharing it with other contexts.
This commit is contained in:
parent
258f35515d
commit
8381490a04
2 changed files with 33 additions and 4 deletions
|
@ -237,10 +237,12 @@ GraphicsPipeline::GraphicsPipeline(
|
||||||
if (key.xfb_enabled && device.UseAssemblyShaders()) {
|
if (key.xfb_enabled && device.UseAssemblyShaders()) {
|
||||||
GenerateTransformFeedbackState();
|
GenerateTransformFeedbackState();
|
||||||
}
|
}
|
||||||
auto func{[this, device, sources, sources_spirv,
|
const bool in_parallel = thread_worker != nullptr;
|
||||||
shader_notify](ShaderContext::Context*) mutable {
|
const auto backend = device.GetShaderBackend();
|
||||||
|
auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv),
|
||||||
|
shader_notify, backend, in_parallel](ShaderContext::Context*) mutable {
|
||||||
for (size_t stage = 0; stage < 5; ++stage) {
|
for (size_t stage = 0; stage < 5; ++stage) {
|
||||||
switch (device.GetShaderBackend()) {
|
switch (backend) {
|
||||||
case Settings::ShaderBackend::GLSL:
|
case Settings::ShaderBackend::GLSL:
|
||||||
if (!sources[stage].empty()) {
|
if (!sources[stage].empty()) {
|
||||||
source_programs[stage] = CreateProgram(sources[stage], Stage(stage));
|
source_programs[stage] = CreateProgram(sources[stage], Stage(stage));
|
||||||
|
@ -249,6 +251,10 @@ GraphicsPipeline::GraphicsPipeline(
|
||||||
case Settings::ShaderBackend::GLASM:
|
case Settings::ShaderBackend::GLASM:
|
||||||
if (!sources[stage].empty()) {
|
if (!sources[stage].empty()) {
|
||||||
assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage));
|
assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage));
|
||||||
|
if (in_parallel) {
|
||||||
|
// Make sure program is built before continuing when building in parallel
|
||||||
|
glGetString(GL_PROGRAM_ERROR_STRING_NV);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Settings::ShaderBackend::SPIRV:
|
case Settings::ShaderBackend::SPIRV:
|
||||||
|
@ -258,10 +264,20 @@ GraphicsPipeline::GraphicsPipeline(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in_parallel && backend != Settings::ShaderBackend::GLASM) {
|
||||||
|
// Make sure programs have built if we are building shaders in parallel
|
||||||
|
for (OGLProgram& program : source_programs) {
|
||||||
|
if (program.handle != 0) {
|
||||||
|
GLint status{};
|
||||||
|
glGetProgramiv(program.handle, GL_LINK_STATUS, &status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (shader_notify) {
|
if (shader_notify) {
|
||||||
shader_notify->MarkShaderComplete();
|
shader_notify->MarkShaderComplete();
|
||||||
}
|
}
|
||||||
is_built = true;
|
is_built = true;
|
||||||
|
built_condvar.notify_one();
|
||||||
}};
|
}};
|
||||||
if (thread_worker) {
|
if (thread_worker) {
|
||||||
thread_worker->QueueWork(std::move(func));
|
thread_worker->QueueWork(std::move(func));
|
||||||
|
@ -434,6 +450,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||||
|
|
||||||
|
if (!is_built.load(std::memory_order::relaxed)) {
|
||||||
|
WaitForBuild();
|
||||||
|
}
|
||||||
if (assembly_programs[0].handle != 0) {
|
if (assembly_programs[0].handle != 0) {
|
||||||
program_manager.BindAssemblyPrograms(assembly_programs, enabled_stages_mask);
|
program_manager.BindAssemblyPrograms(assembly_programs, enabled_stages_mask);
|
||||||
} else {
|
} else {
|
||||||
|
@ -545,4 +564,9 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
|
||||||
num_xfb_strides = static_cast<GLsizei>(current_stream - xfb_streams.data());
|
num_xfb_strides = static_cast<GLsizei>(current_stream - xfb_streams.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsPipeline::WaitForBuild() {
|
||||||
|
std::unique_lock lock{built_mutex};
|
||||||
|
built_condvar.wait(lock, [this] { return is_built.load(std::memory_order::relaxed); });
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -119,6 +119,8 @@ private:
|
||||||
|
|
||||||
void GenerateTransformFeedbackState();
|
void GenerateTransformFeedbackState();
|
||||||
|
|
||||||
|
void WaitForBuild();
|
||||||
|
|
||||||
TextureCache& texture_cache;
|
TextureCache& texture_cache;
|
||||||
BufferCache& buffer_cache;
|
BufferCache& buffer_cache;
|
||||||
Tegra::MemoryManager& gpu_memory;
|
Tegra::MemoryManager& gpu_memory;
|
||||||
|
@ -143,13 +145,16 @@ private:
|
||||||
|
|
||||||
bool use_storage_buffers{};
|
bool use_storage_buffers{};
|
||||||
bool writes_global_memory{};
|
bool writes_global_memory{};
|
||||||
std::atomic_bool is_built{false};
|
|
||||||
|
|
||||||
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
|
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
|
||||||
GLsizei num_xfb_attribs{};
|
GLsizei num_xfb_attribs{};
|
||||||
GLsizei num_xfb_strides{};
|
GLsizei num_xfb_strides{};
|
||||||
std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
|
std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
|
||||||
std::array<GLint, Maxwell::NumTransformFeedbackBuffers> xfb_streams{};
|
std::array<GLint, Maxwell::NumTransformFeedbackBuffers> xfb_streams{};
|
||||||
|
|
||||||
|
std::mutex built_mutex;
|
||||||
|
std::condition_variable built_condvar;
|
||||||
|
std::atomic_bool is_built{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
Loading…
Reference in a new issue