Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asynchronous shader compilation #1209

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d7e1d16
Preliminary testing code.
Feb 24, 2023
143164a
Code for measuring render loop times.
Feb 24, 2023
6cad4f6
Fix test code.
Feb 24, 2023
8460274
Refactor experience.js.
Feb 28, 2023
38c273a
Preliminary code to separate out shader compilation from CreateProgram.
Feb 28, 2023
9257652
Force shader compilation in the test code.
Mar 1, 2023
1f04b1c
Make async code work + rename function.
Mar 1, 2023
ec25c68
Separate synchronous and asynchronous versions of CreateProgram.
Mar 2, 2023
f814deb
Assign the program handle on the Javascript thread.
Mar 3, 2023
77f5c19
Restore original experience.js.
Mar 3, 2023
1df96a2
Return both the program handle and VertexAttributeLocations from Crea…
Mar 4, 2023
209c34a
Throw a proper error after encountering an async shader compilation e…
Mar 6, 2023
d4401b7
Simplify error reporting.
Mar 6, 2023
678fb49
Preliminary code for movable ProgramData (not working yet).
Mar 7, 2023
5e66231
Use unique_ptr to make the Arcana return type work.
Mar 7, 2023
eb5a104
Initialize member variables in constructor.
Mar 8, 2023
f8c062d
Remove unnecessary release of unique_ptr.
Mar 8, 2023
089a278
Leave parameter of nulled operator anonymous.
Mar 8, 2023
e1872d5
Indent lambda captures.
Mar 8, 2023
2319953
Remove unused lambda capture.
Mar 8, 2023
654886c
Remove ProgramData.Disposed.
Mar 8, 2023
8f17fb7
Use pattern similar to CreateProgramAsync in CreateProgram.
Mar 8, 2023
4977f3e
Use BGFX_INVALID_HANDLE instead of bgfx::kInvalidHandle.
Mar 8, 2023
17666c0
Use brace initialization for BGFX handles.
Mar 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 60 additions & 19 deletions Plugins/NativeEngine/Source/NativeEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ namespace Babylon
InstanceMethod("updateDynamicVertexBuffer", &NativeEngine::UpdateDynamicVertexBuffer),

InstanceMethod("createProgram", &NativeEngine::CreateProgram),
InstanceMethod("createProgramAsync", &NativeEngine::CreateProgramAsync),
InstanceMethod("getUniforms", &NativeEngine::GetUniforms),
InstanceMethod("getAttributes", &NativeEngine::GetAttributes),

Expand Down Expand Up @@ -685,22 +686,9 @@ namespace Babylon
return vertexSource;
}

Napi::Value NativeEngine::CreateProgram(const Napi::CallbackInfo& info)
std::pair<bgfx::ProgramHandle,std::unordered_map<std::string,uint32_t>> NativeEngine::CreateProgramInternal(const std::string vertexSource, const std::string fragmentSource, ProgramData& program)
{
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();

ProgramData* program = new ProgramData{};
ShaderCompiler::BgfxShaderInfo shaderInfo{};

try
{
shaderInfo = m_shaderCompiler.Compile(ProcessShaderCoordinates(vertexSource), ProcessSamplerFlip(fragmentSource));
}
catch (const std::exception& ex)
{
throw Napi::Error::New(info.Env(), ex.what());
}
ShaderCompiler::BgfxShaderInfo shaderInfo = m_shaderCompiler.Compile(ProcessShaderCoordinates(vertexSource), ProcessSamplerFlip(fragmentSource));

static auto InitUniformInfos{
[](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) {
Expand All @@ -721,13 +709,66 @@ namespace Babylon
}};

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

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

return std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>>{bgfx::createProgram(vertexShader, fragmentShader, true), std::move(shaderInfo.VertexAttributeLocations)};
}

Napi::Value NativeEngine::CreateProgram(const Napi::CallbackInfo& info)
{
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();
ProgramData* program = new ProgramData{};
bghgary marked this conversation as resolved.
Show resolved Hide resolved
try
{
std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>> programInfo = CreateProgramInternal(vertexSource, fragmentSource, *program);
program->Handle = programInfo.first;
program->VertexAttributeLocations = std::move(programInfo.second);
}
catch (const std::exception& ex)
{
delete program;
throw Napi::Error::New(info.Env(), ex.what());
}
return Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
}

program->Handle = bgfx::createProgram(vertexShader, fragmentShader, true);
Napi::Value NativeEngine::CreateProgramAsync(const Napi::CallbackInfo& info)
{
const std::string vertexSource = info[0].As<Napi::String>().Utf8Value();
const std::string fragmentSource = info[1].As<Napi::String>().Utf8Value();
const Napi::Function onSuccess = info[2].As<Napi::Function>();
const Napi::Function onError = info[3].As<Napi::Function>();
ProgramData* program = new ProgramData{};
arcana::make_task(arcana::threadpool_scheduler, *m_cancellationSource,
[this, vertexSource, fragmentSource, program, cancellationSource{m_cancellationSource}]() -> std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>>
{
return CreateProgramInternal(vertexSource, fragmentSource, *program);
})
.then(m_runtimeScheduler, *m_cancellationSource, [program, onSuccessRef{Napi::Persistent(onSuccess)}, onErrorRef{Napi::Persistent(onError)}, cancellationSource{m_cancellationSource}](arcana::expected<std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>>, std::exception_ptr> result)
{
if (result.has_error())
{
try
{
std::rethrow_exception(result.error());
}
catch (const std::exception& ex)
{
onErrorRef.Call({Napi::Error::New(onErrorRef.Env(), ex.what()).Value()});
}
bghgary marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>> programInfo = result.value();
bghgary marked this conversation as resolved.
Show resolved Hide resolved
program->Handle = programInfo.first;
program->VertexAttributeLocations = std::move(programInfo.second);
bghgary marked this conversation as resolved.
Show resolved Hide resolved
onSuccessRef.Call({});
}
});
return Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
}

Expand Down
2 changes: 2 additions & 0 deletions Plugins/NativeEngine/Source/NativeEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ namespace Babylon
void DeleteVertexBuffer(NativeDataStream::Reader& data);
void RecordVertexBuffer(const Napi::CallbackInfo& info);
void UpdateDynamicVertexBuffer(const Napi::CallbackInfo& info);
std::pair<bgfx::ProgramHandle, std::unordered_map<std::string, uint32_t>> CreateProgramInternal(const std::string vertexSource, const std::string fragmentSource, ProgramData& program);
Napi::Value CreateProgram(const Napi::CallbackInfo& info);
Napi::Value CreateProgramAsync(const Napi::CallbackInfo& info);
Napi::Value GetUniforms(const Napi::CallbackInfo& info);
Napi::Value GetAttributes(const Napi::CallbackInfo& info);
void SetProgram(NativeDataStream::Reader& data);
Expand Down