Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion Apps/UnitTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ if(APPLE)
set(ADDITIONAL_LIBRARIES PRIVATE ${JAVASCRIPTCORE_LIBRARY})
elseif(UNIX AND NOT ANDROID)
set(SOURCES ${SOURCES} "Source/App.X11.cpp")
set(ADDITIONAL_COMPILE_DEFINITIONS PRIVATE SKIP_EXTERNAL_TEXTURE_TESTS)
elseif(WIN32)
set(SOURCES ${SOURCES}
"Source/App.Win32.cpp"
Expand Down Expand Up @@ -89,6 +88,15 @@ if(GRAPHICS_API STREQUAL "D3D12")
target_compile_definitions(UnitTests PRIVATE SKIP_RENDER_TESTS)
endif()

if(GRAPHICS_API STREQUAL "OpenGL")
# The OpenGL ExternalTexture backend imports single-sample GL_TEXTURE_2D
# handles only, so run the basic GetInfo/Set/Get/Update tests on any OpenGL
# build (Linux, or the OpenGLWindowsDevOnly dev path). The render-path tests
# (pixel readback) and the array/layer-index test require GL test helpers and
# array-texture support that this backend does not implement yet.
target_compile_definitions(UnitTests PRIVATE SKIP_RENDER_TESTS SKIP_EXTERNAL_TEXTURE_ARRAY_TESTS)
endif()

add_test(NAME UnitTests COMMAND UnitTests)

# See https://gitlab.kitware.com/cmake/cmake/-/issues/23543
Expand Down
41 changes: 37 additions & 4 deletions Apps/UnitTests/Source/Helpers.OpenGL.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,51 @@
#include <gtest/gtest.h>
#include "Helpers.h"

#include <GLES3/gl3.h>

#include <stdexcept>

namespace Helpers
{
Babylon::Graphics::TextureT CreateTexture(Babylon::Graphics::DeviceT, uint32_t, uint32_t, uint32_t, bool, uint32_t)
// The OpenGL ExternalTexture backend imports single-sample, non-array
// GL_TEXTURE_2D handles. glGenTextures/glTexImage2D require a current GL
// context, which the single-threaded Graphics::Device makes current on the
// calling thread between StartRenderingCurrentFrame/FinishRenderingCurrentFrame
// (the same thread the tests create textures on).
Babylon::Graphics::TextureT CreateTexture(Babylon::Graphics::DeviceT, uint32_t width, uint32_t height, uint32_t arraySize, bool renderTarget, uint32_t samples)
{
throw std::runtime_error{"not implemented"};
// The array / render-target / MSAA variants are only exercised by the
// render-path tests, which are skipped on this backend (see CMakeLists.txt).
if (arraySize != 1 || renderTarget || samples != 1)
{
throw std::runtime_error{"Helpers::CreateTexture(OpenGL): only single-sample, non-array GL_TEXTURE_2D textures are supported"};
}

GLint previousBinding = 0;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previousBinding);

GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

// Allocate a single, texture-complete mip level. The pixel contents are
// never read back by the enabled tests; only the queried dimensions and
// internal format matter.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(previousBinding));

EXPECT_EQ(glGetError(), static_cast<GLenum>(GL_NO_ERROR));

return texture;
}

void DestroyTexture(Babylon::Graphics::TextureT)
void DestroyTexture(Babylon::Graphics::TextureT texture)
{
throw std::runtime_error{"not implemented"};
GLuint handle = texture;
glDeleteTextures(1, &handle);
}

Babylon::Graphics::TextureT CreateTextureArrayWithData(Babylon::Graphics::DeviceT, uint32_t, uint32_t, const Color*, uint32_t)
Expand Down
14 changes: 7 additions & 7 deletions Apps/UnitTests/Source/Tests.ExternalTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ TEST(ExternalTexture, Construction)
device.StartRenderingCurrentFrame();

auto nativeTexture = Helpers::CreateTexture(device.GetPlatformInfo().Device, 256, 256);
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture};
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture, {}, 256, 256};
Helpers::DestroyTexture(nativeTexture);

EXPECT_EQ(externalTexture.Width(), 256u);
Expand All @@ -43,7 +43,7 @@ TEST(ExternalTexture, CreateForJavaScript)
device.StartRenderingCurrentFrame();

auto nativeTexture = Helpers::CreateTexture(device.GetPlatformInfo().Device, 256, 256);
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture};
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture, {}, 256, 256};
Helpers::DestroyTexture(nativeTexture);

std::promise<void> done{};
Expand Down Expand Up @@ -82,7 +82,7 @@ TEST(ExternalTexture, Update)
device.StartRenderingCurrentFrame();

auto nativeTexture = Helpers::CreateTexture(device.GetPlatformInfo().Device, 256, 256);
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture};
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture, {}, 256, 256};
Helpers::DestroyTexture(nativeTexture);

EXPECT_EQ(externalTexture.Width(), 256u);
Expand All @@ -94,7 +94,7 @@ TEST(ExternalTexture, Update)
device.StartRenderingCurrentFrame();

auto nativeTexture2 = Helpers::CreateTexture(device.GetPlatformInfo().Device, 128, 128);
externalTexture.Update(nativeTexture2);
externalTexture.Update(nativeTexture2, {}, {}, 128, 128);
Helpers::DestroyTexture(nativeTexture2);

EXPECT_EQ(externalTexture.Width(), 128u);
Expand All @@ -114,7 +114,7 @@ TEST(ExternalTexture, AddToContextAsyncAndUpdate)
device.StartRenderingCurrentFrame();

auto nativeTexture = Helpers::CreateTexture(device.GetPlatformInfo().Device, 256, 256);
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture};
Babylon::Plugins::ExternalTexture externalTexture{nativeTexture, {}, 256, 256};
Helpers::DestroyTexture(nativeTexture);

std::promise<void> addToContext{};
Expand Down Expand Up @@ -160,7 +160,7 @@ TEST(ExternalTexture, AddToContextAsyncAndUpdate)

// Update the external texture to a new texture.
auto nativeTexture2 = Helpers::CreateTexture(device.GetPlatformInfo().Device, 256, 256);
externalTexture.Update(nativeTexture2);
externalTexture.Update(nativeTexture2, {}, {}, 256, 256);
Helpers::DestroyTexture(nativeTexture2);

device.FinishRenderingCurrentFrame();
Expand All @@ -169,7 +169,7 @@ TEST(ExternalTexture, AddToContextAsyncAndUpdate)

TEST(ExternalTexture, AddToContextAsyncWithLayerIndex)
{
#ifdef SKIP_EXTERNAL_TEXTURE_TESTS
#if defined(SKIP_EXTERNAL_TEXTURE_TESTS) || defined(SKIP_EXTERNAL_TEXTURE_ARRAY_TESTS)
GTEST_SKIP();
#else
Babylon::Graphics::Device device{g_deviceConfig};
Expand Down
12 changes: 10 additions & 2 deletions Plugins/ExternalTexture/Include/Babylon/Plugins/ExternalTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ namespace Babylon::Plugins
class ExternalTexture final
{
public:
ExternalTexture(Graphics::TextureT, std::optional<Graphics::TextureFormatT> = {});
// width/height are required on the OpenGL/OpenGL ES backend and ignored on all
// others. BabylonNative's OpenGL renderer runs on an OpenGL ES 3.0 context, which
// provides no way to query a texture's dimensions from a bare handle
// (glGetTexLevelParameteriv was only added in ES 3.1). The caller that created the
// texture already knows its size, so it must supply it here. The D3D/Metal backends
// introspect the native texture and ignore these hints.
ExternalTexture(Graphics::TextureT, std::optional<Graphics::TextureFormatT> = {}, std::optional<uint32_t> width = {}, std::optional<uint32_t> height = {});
~ExternalTexture();

// Copy semantics
Expand Down Expand Up @@ -45,7 +51,9 @@ namespace Babylon::Plugins
Napi::Promise AddToContextAsync(Napi::Env, std::optional<uint16_t> layerIndex = {}) const;

// Updates to a new texture. If layerIndex is set, views only that array layer (single-slice).
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT> = {}, std::optional<uint16_t> layerIndex = {});
// width/height follow the same backend-specific contract as the constructor: required on
// OpenGL/OpenGL ES, ignored elsewhere.
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT> = {}, std::optional<uint16_t> layerIndex = {}, std::optional<uint32_t> width = {}, std::optional<uint32_t> height = {});

private:
class Impl;
Expand Down
6 changes: 3 additions & 3 deletions Plugins/ExternalTexture/Source/ExternalTexture_D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,16 @@ namespace Babylon::Plugins
{
public:
// Implemented in ExternalTexture_Shared.h
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>);
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint32_t>, std::optional<uint32_t>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>, std::optional<uint32_t>, std::optional<uint32_t>);

Graphics::TextureT Get() const
{
return m_ptr.get();
}

private:
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, Info& info)
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, std::optional<uint32_t> /*width*/, std::optional<uint32_t> /*height*/, Info& info)
{
winrt::com_ptr<ID3D11Resource> resource;
resource.copy_from(ptr);
Expand Down
6 changes: 3 additions & 3 deletions Plugins/ExternalTexture/Source/ExternalTexture_D3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,16 @@ namespace Babylon::Plugins
{
public:
// Implemented in ExternalTexture_Shared.h
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>);
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint32_t>, std::optional<uint32_t>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>, std::optional<uint32_t>, std::optional<uint32_t>);

Graphics::TextureT Get() const
{
return m_ptr.get();
}

private:
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, Info& info)
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, std::optional<uint32_t> /*width*/, std::optional<uint32_t> /*height*/, Info& info)
{
D3D12_RESOURCE_DESC desc = ptr->GetDesc();

Expand Down
6 changes: 3 additions & 3 deletions Plugins/ExternalTexture/Source/ExternalTexture_Metal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,16 +250,16 @@ namespace Babylon::Plugins
{
public:
// Implemented in ExternalTexture_Shared.h
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>);
Impl(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint32_t>, std::optional<uint32_t>);
void Update(Graphics::TextureT, std::optional<Graphics::TextureFormatT>, std::optional<uint16_t>, std::optional<uint32_t>, std::optional<uint32_t>);

Graphics::TextureT Get() const
{
return m_ptr.get();
}

private:
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, Info& info)
static void GetInfo(Graphics::TextureT ptr, std::optional<Graphics::TextureFormatT> overrideFormat, std::optional<uint32_t> /*width*/, std::optional<uint32_t> /*height*/, Info& info)
{
if (ptr->textureType() != MTL::TextureType2D && ptr->textureType() != MTL::TextureType2DMultisample)
{
Expand Down
Loading
Loading