Skip to content

Commit

Permalink
Fixed issue #923 by implementing 2D Texture Array to be used with Mor…
Browse files Browse the repository at this point in the history
…ph targets. (#981)

* Added support for Morph targets to use 2D texture arrays. Added check for uniforms array length to avoid memory overrun

* Code cleanup, moved array lenght check to after the null check

* Update Plugins/NativeEngine/Source/NativeEngine.h

Co-authored-by: Gary Hsu <[email protected]>

* Update Plugins/NativeEngine/Source/NativeEngine.cpp

Co-authored-by: Gary Hsu <[email protected]>

* Moved element size info to Babylon::UniformInfo. Changed business logic to allow usage of UniformInfo for size check at runtime

* Revert "Moved element size info to Babylon::UniformInfo. Changed business logic to allow usage of UniformInfo for size check at runtime"

This reverts commit 117c2e6.

* Reimplemented changes after reversing clang-format changes

* Cleanup unused parameters and added exception for not supported ones

* Update Plugins/NativeEngine/Source/NativeEngine.cpp

Co-authored-by: Gary Hsu <[email protected]>

Co-authored-by: Gary Hsu <[email protected]>
  • Loading branch information
SergioRZMasson and bghgary authored Jan 26, 2022
1 parent 8e21c9c commit 5b5ad20
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 25 deletions.
92 changes: 73 additions & 19 deletions Plugins/NativeEngine/Source/NativeEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ namespace Babylon
InstanceMethod("createTexture", &NativeEngine::CreateTexture),
InstanceMethod("loadTexture", &NativeEngine::LoadTexture),
InstanceMethod("loadRawTexture", &NativeEngine::LoadRawTexture),
InstanceMethod("loadRawTexture2DArray", &NativeEngine::LoadRawTexture2DArray),
InstanceMethod("loadCubeTexture", &NativeEngine::LoadCubeTexture),
InstanceMethod("loadCubeTextureWithMips", &NativeEngine::LoadCubeTextureWithMips),
InstanceMethod("getTextureWidth", &NativeEngine::GetTextureWidth),
Expand Down Expand Up @@ -701,29 +702,33 @@ namespace Babylon
throw Napi::Error::New(info.Env(), ex.what());
}

static auto InitUniformInfos{[](bgfx::ShaderHandle shader, const std::unordered_map<std::string, uint8_t>& uniformStages, std::unordered_map<std::string, UniformInfo>& uniformInfos) {
auto numUniforms = bgfx::getShaderUniforms(shader);
std::vector<bgfx::UniformHandle> uniforms{numUniforms};
bgfx::getShaderUniforms(shader, uniforms.data(), gsl::narrow_cast<uint16_t>(uniforms.size()));

for (uint8_t index = 0; index < numUniforms; index++)
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)
{
bgfx::UniformInfo info{};
bgfx::getUniformInfo(uniforms[index], info);
auto itStage = uniformStages.find(info.name);
uniformInfos.emplace(std::make_pair<std::string, UniformInfo>(info.name, {itStage == uniformStages.end() ? uint8_t{} : itStage->second, uniforms[index]}));
}
}};
auto numUniforms = bgfx::getShaderUniforms(shader);
std::vector<bgfx::UniformHandle> uniforms{numUniforms};
bgfx::getShaderUniforms(shader, uniforms.data(), gsl::narrow_cast<uint16_t>(uniforms.size()));

for (uint8_t index = 0; index < numUniforms; index++)
{
bgfx::UniformInfo info{};
uint16_t handleIndex = uniforms[index].idx;
bgfx::getUniformInfo(uniforms[index], info);
auto itStage = uniformStages.find(info.name);
auto& handle = uniforms[index];
uniformInfos.emplace(std::make_pair(handle.idx, UniformInfo{itStage == uniformStages.end() ? uint8_t{} : itStage->second, handle, info.num}));
uniformNameToIndex[info.name] = handleIndex;
}
}};

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

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

program->Handle = bgfx::createProgram(vertexShader, fragmentShader, true);

return Napi::Pointer<ProgramData>::Create(info.Env(), program, Napi::NapiPointerDeleter(program));
}

Expand All @@ -739,11 +744,18 @@ namespace Babylon
if (names[index].IsString())
{
const auto name{names[index].As<Napi::String>().Utf8Value()};
const auto itUniformInfo{program->UniformInfos.find(name)};
if (itUniformInfo != program->UniformInfos.end())

const auto itUniformIndex = program->UniformNameToIndex.find(name);

if (itUniformIndex != program->UniformNameToIndex.end())
{
uniforms[index] = Napi::Pointer<UniformInfo>::Create(info.Env(), &itUniformInfo->second);
continue;
const auto itUniformInfo{program->UniformInfos.find(itUniformIndex->second)};

if (itUniformInfo != program->UniformInfos.end())
{
uniforms[index] = Napi::Pointer<UniformInfo>::Create(info.Env(), &itUniformInfo->second);
continue;
}
}
}

Expand Down Expand Up @@ -1102,6 +1114,48 @@ namespace Babylon
LoadTextureFromImage(texture, image, false);
}

void NativeEngine::LoadRawTexture2DArray(const Napi::CallbackInfo& info)
{
const auto texture{info[0].As<Napi::Pointer<TextureData>>().Get()};
const auto data = info[1].As<Napi::TypedArray>();
const auto width{static_cast<uint16_t>(info[2].As<Napi::Number>().Uint32Value())};
const auto height{static_cast<uint16_t>(info[3].As<Napi::Number>().Uint32Value())};
const auto depth{static_cast<uint16_t>(info[4].As<Napi::Number>().Int32Value())};
const auto format{static_cast<bimg::TextureFormat::Enum>(info[5].As<Napi::Number>().Uint32Value())};
const auto generateMips = info[6].As<Napi::Boolean>().Value();
const auto invertY = info[7].As<Napi::Boolean>().Value();

if (generateMips)
{
throw std::runtime_error{"Texture 2D array currently do not support mipmaps."};
}

if (invertY)
{
throw std::runtime_error{"Texture 2D array currently do not support invert Y."};
}

texture->Width = width;
texture->Height = height;
texture->CreationFlags = BGFX_TEXTURE_NONE;
texture->Flags = BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE | BGFX_CAPS_TEXTURE_2D_ARRAY;
texture->Handle = bgfx::createTexture2D(width, height, generateMips, depth, Cast(format), texture->Flags);
texture->OwnsHandle = true;

if (!data.IsNull())
{
if (data.ByteLength() != bimg::imageGetSize(nullptr, width, height, 1, false, false, depth, format))
{
throw std::runtime_error{"The data size does not match width, height, depth and format"};
}

uint8_t* dataPtr = static_cast<uint8_t*>(data.ArrayBuffer().Data()) + data.ByteOffset();
uint32_t dataSize = static_cast<uint32_t>(data.ByteLength());
const bgfx::Memory* dataCopy = bgfx::copy(dataPtr, dataSize); // This is required since BGFX must manage the data the memory.
bgfx::updateTexture2D(texture->Handle, 0, 0, 0, 0, width, height, dataCopy);
}
}

void NativeEngine::LoadCubeTexture(const Napi::CallbackInfo& info)
{
const auto texture = info[0].As<Napi::Pointer<TextureData>>().Get();
Expand Down
23 changes: 17 additions & 6 deletions Plugins/NativeEngine/Source/NativeEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ namespace Babylon
{
struct UniformInfo final
{
UniformInfo(uint8_t stage, bgfx::UniformHandle handle) :
Stage{stage},
Handle{handle}
UniformInfo(uint8_t stage, bgfx::UniformHandle handle, size_t maxElementLength)
: Stage{stage}
, Handle{handle}
, MaxElementLength{maxElementLength}
{
}

uint8_t Stage{};
bgfx::UniformHandle Handle{bgfx::kInvalidHandle};
size_t MaxElementLength{};
};

struct ProgramData final
Expand All @@ -60,9 +62,6 @@ namespace Babylon
Disposed = true;
}

std::unordered_map<std::string, uint32_t> VertexAttributeLocations{};
std::unordered_map<std::string, UniformInfo> UniformInfos{};

bgfx::ProgramHandle Handle{bgfx::kInvalidHandle};
bool Disposed{false};

Expand All @@ -73,10 +72,21 @@ namespace Babylon
};

std::unordered_map<uint16_t, UniformValue> Uniforms{};
std::unordered_map<std::string, uint16_t> UniformNameToIndex{};
std::unordered_map<uint16_t, UniformInfo> UniformInfos{};
std::unordered_map<std::string, uint32_t> VertexAttributeLocations{};

void SetUniform(bgfx::UniformHandle handle, gsl::span<const float> data, size_t elementLength = 1)
{
UniformValue& value = Uniforms[handle.idx];

const auto itUniformInfo{UniformInfos.find(handle.idx)};

if (itUniformInfo != UniformInfos.end())
{
elementLength = std::min(itUniformInfo->second.MaxElementLength, elementLength);
}

value.Data.assign(data.begin(), data.end());
value.ElementLength = static_cast<uint16_t>(elementLength);
}
Expand Down Expand Up @@ -143,6 +153,7 @@ namespace Babylon
void LoadTexture(const Napi::CallbackInfo& info);
void CopyTexture(const Napi::CallbackInfo& info);
void LoadRawTexture(const Napi::CallbackInfo& info);
void LoadRawTexture2DArray(const Napi::CallbackInfo& info);
void LoadCubeTexture(const Napi::CallbackInfo& info);
void LoadCubeTextureWithMips(const Napi::CallbackInfo& info);
Napi::Value GetTextureWidth(const Napi::CallbackInfo& info);
Expand Down

0 comments on commit 5b5ad20

Please sign in to comment.