Skip to content

Commit

Permalink
Rework vertex buffer code to handle non-normalized integer attributes…
Browse files Browse the repository at this point in the history
… correctly (#1369)

Related PR on the Babylon.js side:
BabylonJS/Babylon.js#14862

- Add some visual tests that ensure interleaved buffers and updating
buffers work properly. See
[playground](https://playground.babylonjs.com/#AVFNTW#5).
- Add CesiumMan test which uses the same buffer for non-interleaved
attributes.
- Update playground runner script to support async `createScene`
functions.
- Update validation_native.js to support newer playgrounds, copied from
JS visual test code.
- Disable async shader compilation in validation (visual) tests.
- Update Babylon.js package to 6.46.1 which includes changes from the PR
noted at the top.
- Changed the `m_deviceId` and `m_deviceContext` to be more consistent
with all classes.
- Modified the index and vertex buffer code to handle errors better.
- Move all vertex buffer logic from vertex array into vertex buffer to
keep track of all promoted to float attributes.
- Update vertex buffer logic to handle promote to float and keep track
of the streams for setting and updating later.
  • Loading branch information
bghgary authored Mar 13, 2024
1 parent 39ce2bc commit 8d61e15
Show file tree
Hide file tree
Showing 22 changed files with 671 additions and 452 deletions.
1 change: 1 addition & 0 deletions Apps/Playground/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ endif()
set_property(TARGET Playground PROPERTY FOLDER Apps)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../node_modules PREFIX Scripts FILES ${BABYLON_SCRIPTS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/../Dependencies PREFIX Scripts FILES ${DEPENDENCIES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${REFERENCE_IMAGES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SCRIPTS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Playground)
Binary file added Apps/Playground/ReferenceImages/CesiumMan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 33 additions & 4 deletions Apps/Playground/Scripts/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,23 @@
"renderCount": 10,
"playgroundId": "#W7E7CF#12",
"referenceImage": "scissor-test.png",
"excludedGraphicsApis": ["D3D12"],
"excludedGraphicsApis": [ "D3D12" ],
"comment": "TODO: reenable D3D12 when automatica mip-maps issue is fixed in bgfx"
},
{
"title": "Scissor test with 0.9 hardware scaling",
"renderCount": 10,
"playgroundId": "#W7E7CF#27",
"referenceImage": "scissorTestWith0.9HardwareScaling.png",
"excludedGraphicsApis": ["D3D12"],
"excludedGraphicsApis": [ "D3D12" ],
"comment": "TODO: reenable D3D12 when automatica mip-maps issue is fixed in bgfx"
},
{
"title": "Scissor test with 1.5 hardware scaling",
"renderCount": 10,
"playgroundId": "#W7E7CF#28",
"referenceImage": "scissorTestWith1.5HardwareScaling.png",
"excludedGraphicsApis": ["D3D12"],
"excludedGraphicsApis": [ "D3D12" ],
"comment": "TODO: reenable D3D12 when automatica mip-maps issue is fixed in bgfx"
},
{
Expand Down Expand Up @@ -477,6 +477,35 @@
"title": "GLTF Alien",
"playgroundId": "#XN37SR#5",
"referenceImage": "gltfAlien.png"
},
{
"title": "Interleaved buffers test",
"playgroundId": "#AVFNTW#5",
"referenceImage": "interleaved-buffers-1.png"
},
{
"title": "Interleaved buffers test (integerPositionsAndNormals = true)",
"playgroundId": "#AVFNTW#5",
"replace": "//options//, integerPositionsAndNormals = true;",
"referenceImage": "interleaved-buffers-2.png"
},
{
"title": "Interleaved buffers test (updateUVs = true)",
"playgroundId": "#AVFNTW#5",
"replace": "//options//, updateUVs = true;",
"referenceImage": "interleaved-buffers-3.png"
},
{
"title": "Interleaved buffers test (updateUVs = true, updateAfterRender = true)",
"playgroundId": "#AVFNTW#5",
"replace": "//options//, updateUVs = true; updateAfterRender = true;",
"referenceImage": "interleaved-buffers-4.png",
"renderCount": 2
},
{
"title": "CesiumMan from Khronos Sample Assets",
"playgroundId": "#4GWX8M",
"referenceImage": "CesiumMan.png"
}
]
}
}
16 changes: 12 additions & 4 deletions Apps/Playground/Scripts/playground_runner.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
if (typeof createScene === "function") {
var engine = new BABYLON.NativeEngine({adaptToDeviceRatio: true});
var scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
}
if (scene.then) {
scene.then(function (scene) {
engine.runRenderLoop(function () {
scene.render();
});
})
} else {
engine.runRenderLoop(function () {
scene.render();
});
}
}
59 changes: 32 additions & 27 deletions Apps/Playground/Scripts/validation_native.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ function saveRenderedResult(test, renderData) {
}

function evaluate(test, resultCanvas, result, referenceImage, index, waitRing, done, compareFunction) {
/*var canvasImageData =*/ engine._engine.getFrameBufferData(function (screenshot) {
engine._engine.getFrameBufferData(function (screenshot) {
var testRes = true;
// Visual check

if (!test.onlyVisual) {

var defaultErrorRatio = 2.5
var defaultErrorRatio = 2.5;

if (compareFunction(test, screenshot, referenceImage, test.threshold || 25, test.errorRatio || defaultErrorRatio)) {
testRes = false;
Expand All @@ -93,11 +93,11 @@ function processCurrentScene(test, resultCanvas, result, renderImage, index, wai
currentScene.useConstantAnimationDeltaTime = true;
var renderCount = test.renderCount || 1;

currentScene.executeWhenReady(function() {
currentScene.executeWhenReady(function () {
if (currentScene.activeCamera && currentScene.activeCamera.useAutoRotationBehavior) {
currentScene.activeCamera.useAutoRotationBehavior = false;
}
engine.runRenderLoop(function() {
engine.runRenderLoop(function () {
try {
currentScene.render();
renderCount--;
Expand Down Expand Up @@ -129,9 +129,7 @@ function loadPlayground(test, done, index, referenceImage, compareFunction) {
}
else if (test.playgroundId) {
if (test.playgroundId[0] !== "#" || test.playgroundId.indexOf("#", 1) === -1) {
console.error("Invalid playground id");
done(false);
return;
test.playgroundId += "#0";
}

var snippetUrl = "https://snippet.babylonjs.com";
Expand Down Expand Up @@ -163,18 +161,23 @@ function loadPlayground(test, done, index, referenceImage, compareFunction) {
xmlHttp.onreadystatechange = null;
var snippet = JSON.parse(xmlHttp.responseText);
var code = JSON.parse(snippet.jsonPayload).code.toString();
code = code.replace(/\/textures\//g, pgRoot + "/textures/");
code = code.replace(/"textures\//g, "\"" + pgRoot + "/textures/");
code = code.replace(/\/scenes\//g, pgRoot + "/scenes/");
code = code.replace(/"scenes\//g, "\"" + pgRoot + "/scenes/");
code = code
.replace(/"\/textures\//g, '"' + pgRoot + "/textures/")
.replace(/"textures\//g, '"' + pgRoot + "/textures/")
.replace(/\/scenes\//g, pgRoot + "/scenes/")
.replace(/"scenes\//g, '"' + pgRoot + "/scenes/")
.replace(/"\.\.\/\.\.https/g, '"' + "https")
.replace("http://", "https://");

if (test.replace) {
var split = test.replace.split(",");
for (var i = 0; i < split.length; i += 2) {
var source = split[i].trim();
var destination = split[i + 1].trim();
const split = test.replace.split(",");
for (let i = 0; i < split.length; i += 2) {
const source = split[i].trim();
const destination = split[i + 1].trim();
code = code.replace(source, destination);
}
}

currentScene = eval(code + "\r\ncreateScene(engine)");
var resultCanvas = 0;
var result;
Expand Down Expand Up @@ -282,11 +285,11 @@ function runTest(index, done) {

seed = 1;

let onLoadFileError = function(request, exception) {
let onLoadFileError = function (request, exception) {
console.error("Failed to retrieve " + url + ".", exception);
done(false);
};
var onload = function(data, responseURL) {
var onload = function (data, responseURL) {
if (typeof (data) === "string") {
throw new Error("Decode Image from string data not yet implemented.");
}
Expand All @@ -306,7 +309,7 @@ function runTest(index, done) {
}

engine = new BABYLON.NativeEngine();
canvas = window;
engine.getCaps().parallelShaderCompile = undefined;

engine.getRenderingCanvas = function () {
return window;
Expand All @@ -316,15 +319,17 @@ engine.getInputElement = function () {
return 0;
}

OffscreenCanvas = function(width, height) {
canvas = window;

OffscreenCanvas = function (width, height) {
return {
width: width
, height: height
, getContext: function(type) {
, getContext: function (type) {
return {
fillRect: function(x, y, w, h) { }
, measureText: function(text) { return 8; }
, fillText: function(text, x, y) { }
fillRect: function (x, y, w, h) { }
, measureText: function (text) { return 8; }
, fillText: function (text, x, y) { }
};
}
};
Expand All @@ -343,14 +348,14 @@ document = {
var xhr = new XMLHttpRequest();
xhr.open("GET", "app:///Scripts/config.json", true);

xhr.addEventListener("readystatechange", function() {
xhr.addEventListener("readystatechange", function () {
if (xhr.status === 200) {
config = JSON.parse(xhr.responseText);

// Run tests
var index = 0;
var recursiveRunTest = function(i) {
runTest(i, function(status) {
var recursiveRunTest = function (i) {
runTest(i, function (status) {
if (!status) {
TestUtils.exit(-1);
return;
Expand Down
28 changes: 23 additions & 5 deletions Apps/Playground/Win32/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
#include <Windowsx.h>
#include <Shlwapi.h>
#include <filesystem>
#include <stdio.h>
#include <iostream>
#include <optional>
#include <sstream>

#include <Babylon/AppRuntime.h>
#include <Babylon/Graphics/Device.h>
Expand Down Expand Up @@ -47,6 +48,21 @@ INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

namespace
{
const char* GetLogLevelString(Babylon::Polyfills::Console::LogLevel logLevel)
{
switch (logLevel)
{
case Babylon::Polyfills::Console::LogLevel::Log:
return "Log";
case Babylon::Polyfills::Console::LogLevel::Warn:
return "Warn";
case Babylon::Polyfills::Console::LogLevel::Error:
return "Error";
default:
return "";
}
}

std::string GetUrlFromPath(const std::filesystem::path& path)
{
char url[1024];
Expand Down Expand Up @@ -126,11 +142,13 @@ namespace
runtime->Dispatch([hWnd](Napi::Env env) {
device->AddToJavaScript(env);

Babylon::Polyfills::Console::Initialize(env, [](const char* message, auto) {
OutputDebugStringA(message);
Babylon::Polyfills::Console::Initialize(env, [](const char* message, Babylon::Polyfills::Console::LogLevel logLevel) {
std::ostringstream ss{};
ss << "[" << GetLogLevelString(logLevel) << "] " << message << std::endl;
OutputDebugStringA(ss.str().data());

printf("%s", message);
fflush(stdout);
std::cout << ss.str();
std::cout.flush();
});

Babylon::Polyfills::Window::Initialize(env);
Expand Down
Loading

0 comments on commit 8d61e15

Please sign in to comment.