Skip to content

Commit 754029e

Browse files
authored
Asynchronous shader compilation (#1209)
1 parent 83e8acc commit 754029e

File tree

2 files changed

+86
-22
lines changed

2 files changed

+86
-22
lines changed

Plugins/NativeEngine/Source/NativeEngine.cpp

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ namespace Babylon
458458
InstanceMethod("updateDynamicVertexBuffer", &NativeEngine::UpdateDynamicVertexBuffer),
459459

460460
InstanceMethod("createProgram", &NativeEngine::CreateProgram),
461+
InstanceMethod("createProgramAsync", &NativeEngine::CreateProgramAsync),
461462
InstanceMethod("getUniforms", &NativeEngine::GetUniforms),
462463
InstanceMethod("getAttributes", &NativeEngine::GetAttributes),
463464

@@ -687,22 +688,11 @@ namespace Babylon
687688
return vertexSource;
688689
}
689690

690-
Napi::Value NativeEngine::CreateProgram(const Napi::CallbackInfo& info)
691+
std::unique_ptr<ProgramData> NativeEngine::CreateProgramInternal(const std::string vertexSource, const std::string fragmentSource)
691692
{
692-
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
693-
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();
693+
ShaderCompiler::BgfxShaderInfo shaderInfo = m_shaderCompiler.Compile(ProcessShaderCoordinates(vertexSource), ProcessSamplerFlip(fragmentSource));
694694

695-
ProgramData* program = new ProgramData{};
696-
ShaderCompiler::BgfxShaderInfo shaderInfo{};
697-
698-
try
699-
{
700-
shaderInfo = m_shaderCompiler.Compile(ProcessShaderCoordinates(vertexSource), ProcessSamplerFlip(fragmentSource));
701-
}
702-
catch (const std::exception& ex)
703-
{
704-
throw Napi::Error::New(info.Env(), ex.what());
705-
}
695+
std::unique_ptr<ProgramData> program = std::make_unique<ProgramData>();
706696

707697
static auto InitUniformInfos{
708698
[](bgfx::ShaderHandle shader, const std::unordered_map<std::string, uint8_t>& uniformStages, std::unordered_map<uint16_t, UniformInfo>& uniformInfos, std::unordered_map<std::string, uint16_t>& uniformNameToIndex) {
@@ -724,13 +714,67 @@ namespace Babylon
724714

725715
auto vertexShader = bgfx::createShader(bgfx::copy(shaderInfo.VertexBytes.data(), static_cast<uint32_t>(shaderInfo.VertexBytes.size())));
726716
InitUniformInfos(vertexShader, shaderInfo.UniformStages, program->UniformInfos, program->UniformNameToIndex);
727-
program->VertexAttributeLocations = std::move(shaderInfo.VertexAttributeLocations);
728717

729718
auto fragmentShader = bgfx::createShader(bgfx::copy(shaderInfo.FragmentBytes.data(), static_cast<uint32_t>(shaderInfo.FragmentBytes.size())));
730719
InitUniformInfos(fragmentShader, shaderInfo.UniformStages, program->UniformInfos, program->UniformNameToIndex);
731720

732721
program->Handle = bgfx::createProgram(vertexShader, fragmentShader, true);
733-
return Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
722+
program->VertexAttributeLocations = std::move(shaderInfo.VertexAttributeLocations);
723+
724+
return program;
725+
}
726+
727+
Napi::Value NativeEngine::CreateProgram(const Napi::CallbackInfo& info)
728+
{
729+
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
730+
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();
731+
ProgramData* program = new ProgramData{};
732+
Napi::Value jsProgram = Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
733+
try
734+
{
735+
*program = std::move(*CreateProgramInternal(vertexSource, fragmentSource));
736+
}
737+
catch (const std::exception& ex)
738+
{
739+
throw Napi::Error::New(info.Env(), ex.what());
740+
}
741+
return jsProgram;
742+
}
743+
744+
Napi::Value NativeEngine::CreateProgramAsync(const Napi::CallbackInfo& info)
745+
{
746+
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
747+
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();
748+
const Napi::Function onSuccess = info[2].As<Napi::Function>();
749+
const Napi::Function onError = info[3].As<Napi::Function>();
750+
751+
ProgramData* program = new ProgramData{};
752+
Napi::Value jsProgram = Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
753+
754+
arcana::make_task(arcana::threadpool_scheduler, *m_cancellationSource,
755+
[this, vertexSource, fragmentSource, cancellationSource{m_cancellationSource}]() -> std::unique_ptr<ProgramData>
756+
{
757+
return CreateProgramInternal(vertexSource, fragmentSource);
758+
})
759+
.then(m_runtimeScheduler, *m_cancellationSource,
760+
[program,
761+
jsProgramRef{Napi::Persistent(jsProgram)},
762+
onSuccessRef{Napi::Persistent(onSuccess)},
763+
onErrorRef{Napi::Persistent(onError)},
764+
cancellationSource{m_cancellationSource}](const arcana::expected<std::unique_ptr<ProgramData>, std::exception_ptr>& result)
765+
{
766+
if (result.has_error())
767+
{
768+
onErrorRef.Call({Napi::Error::New(onErrorRef.Env(), result.error()).Value()});
769+
}
770+
else
771+
{
772+
*program = std::move(*result.value());
773+
onSuccessRef.Call({});
774+
}
775+
});
776+
777+
return jsProgram;
734778
}
735779

736780
Napi::Value NativeEngine::GetUniforms(const Napi::CallbackInfo& info)

Plugins/NativeEngine/Source/NativeEngine.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,29 @@ namespace Babylon
4343
struct ProgramData final
4444
{
4545
ProgramData() = default;
46-
ProgramData(ProgramData&& other) = delete;
4746
ProgramData(const ProgramData&) = delete;
48-
ProgramData& operator=(ProgramData&& other) = delete;
49-
ProgramData& operator=(const ProgramData& other) = delete;
47+
ProgramData& operator=(const ProgramData&) = delete;
48+
49+
ProgramData(ProgramData&& other) noexcept:
50+
Handle{other.Handle},
51+
Uniforms{std::move(other.Uniforms)},
52+
UniformNameToIndex{std::move(other.UniformNameToIndex)},
53+
UniformInfos{std::move(other.UniformInfos)},
54+
VertexAttributeLocations{std::move(other.VertexAttributeLocations)}
55+
{
56+
other.Handle = BGFX_INVALID_HANDLE;
57+
}
58+
59+
ProgramData& operator=(ProgramData&& other) noexcept
60+
{
61+
Handle = std::move(other.Handle);
62+
other.Handle = BGFX_INVALID_HANDLE;
63+
Uniforms = std::move(other.Uniforms);
64+
UniformNameToIndex = std::move(other.UniformNameToIndex);
65+
UniformInfos = std::move(other.UniformInfos);
66+
VertexAttributeLocations = std::move(other.VertexAttributeLocations);
67+
return *this;
68+
}
5069

5170
~ProgramData()
5271
{
@@ -55,15 +74,14 @@ namespace Babylon
5574

5675
void Dispose()
5776
{
58-
if (!Disposed && bgfx::isValid(Handle))
77+
if (bgfx::isValid(Handle))
5978
{
6079
bgfx::destroy(Handle);
80+
Handle = BGFX_INVALID_HANDLE;
6181
}
62-
Disposed = true;
6382
}
6483

6584
bgfx::ProgramHandle Handle{bgfx::kInvalidHandle};
66-
bool Disposed{false};
6785

6886
struct UniformValue
6987
{
@@ -120,7 +138,9 @@ namespace Babylon
120138
void DeleteVertexBuffer(NativeDataStream::Reader& data);
121139
void RecordVertexBuffer(const Napi::CallbackInfo& info);
122140
void UpdateDynamicVertexBuffer(const Napi::CallbackInfo& info);
141+
std::unique_ptr<ProgramData> CreateProgramInternal(const std::string vertexSource, const std::string fragmentSource);
123142
Napi::Value CreateProgram(const Napi::CallbackInfo& info);
143+
Napi::Value CreateProgramAsync(const Napi::CallbackInfo& info);
124144
Napi::Value GetUniforms(const Napi::CallbackInfo& info);
125145
Napi::Value GetAttributes(const Napi::CallbackInfo& info);
126146
void SetProgram(NativeDataStream::Reader& data);

0 commit comments

Comments
 (0)