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
5 changes: 5 additions & 0 deletions Apps/UnitTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ set(SOURCES
"Source/Utils.h"
"Source/Utils.${GRAPHICS_API}.${BABYLON_NATIVE_PLATFORM_IMPL_EXT}")

if(GRAPHICS_API STREQUAL "D3D11" OR GRAPHICS_API STREQUAL "D3D12")
set(SOURCES ${SOURCES}
"Source/Tests.Device.cpp")
endif()

if(GRAPHICS_API STREQUAL "D3D11")
set(SOURCES ${SOURCES}
"Source/Tests.Device.${GRAPHICS_API}.cpp"
Expand Down
52 changes: 52 additions & 0 deletions Apps/UnitTests/Source/Tests.Device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <gtest/gtest.h>

#include <Babylon/Graphics/Device.h>

#include "Utils.h"

extern Babylon::Graphics::Configuration g_deviceConfig;

// Verifies UpdateDevice replaces the active graphics device after a DisableRendering / EnableRendering cycle.
TEST(Device, UpdateDevice)
{
Babylon::Graphics::DeviceT deviceA = CreateTestGraphicsDevice();
ASSERT_NE(deviceA, nullptr);

Babylon::Graphics::DeviceT deviceB = nullptr;

{
// Inherit Window / Width / Height from the App layer's config so bgfx can manage its own
// swap chain on the HWND. We deliberately do NOT set BackBufferColor here -- the
// caller-provided-BackBuffer flow is a separate concern covered by TEST(Device, BackBuffer).
Babylon::Graphics::Configuration config = g_deviceConfig;
config.Device = deviceA;

Babylon::Graphics::Device device{config};

// Drive a frame to force EnableRendering -> bgfx::init with deviceA.
device.StartRenderingCurrentFrame();
device.FinishRenderingCurrentFrame();

EXPECT_EQ(device.GetPlatformInfo().Device, deviceA);

deviceB = CreateTestGraphicsDevice();
ASSERT_NE(deviceB, nullptr);

// Tear bgfx down before pointing the device at the new graphics device.
device.DisableRendering();

device.UpdateDevice(deviceB);

// Drive another frame to force EnableRendering -> bgfx::init with deviceB.
device.StartRenderingCurrentFrame();
device.FinishRenderingCurrentFrame();

EXPECT_EQ(device.GetPlatformInfo().Device, deviceB);
// Note: no EXPECT_NE(deviceB, deviceA). On D3D12 with WARP, D3D12CreateDevice returns the
// same singleton pointer on successive calls so distinctness is not assertable. On D3D11
// distinctness holds but exercising it does not add value over the EXPECT_EQ above.
} // Babylon::Graphics::Device destructs here, calling DisableRendering on deviceB.

DestroyTestGraphicsDevice(deviceB);
DestroyTestGraphicsDevice(deviceA);
}
25 changes: 25 additions & 0 deletions Apps/UnitTests/Source/Utils.D3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,28 @@ void DestroyTestTexture(Babylon::Graphics::TextureT texture)
{
texture->Release();
}

Babylon::Graphics::DeviceT CreateTestGraphicsDevice()
{
ID3D11Device* device = nullptr;
EXPECT_HRESULT_SUCCEEDED(D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_WARP,
nullptr,
0,
nullptr,
0,
D3D11_SDK_VERSION,
&device,
nullptr,
nullptr));
return device;
}

void DestroyTestGraphicsDevice(Babylon::Graphics::DeviceT device)
{
if (device != nullptr)
{
device->Release();
}
}
25 changes: 25 additions & 0 deletions Apps/UnitTests/Source/Utils.D3D12.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <gtest/gtest.h>
#include "Utils.h"

#include <dxgi1_4.h>
#include <winrt/base.h>

Babylon::Graphics::TextureT CreateTestTexture(Babylon::Graphics::DeviceT device, uint32_t width, uint32_t height, uint32_t arraySize)
{
D3D12_RESOURCE_DESC desc{};
Expand Down Expand Up @@ -39,3 +42,25 @@ void DestroyTestTexture(Babylon::Graphics::TextureT texture)
{
texture->Release();
}

Babylon::Graphics::DeviceT CreateTestGraphicsDevice()
{
winrt::com_ptr<IDXGIFactory4> factory;
winrt::check_hresult(CreateDXGIFactory1(IID_PPV_ARGS(factory.put())));

winrt::com_ptr<IDXGIAdapter> warpAdapter;
winrt::check_hresult(factory->EnumWarpAdapter(IID_PPV_ARGS(warpAdapter.put())));

ID3D12Device* device = nullptr;
winrt::check_hresult(D3D12CreateDevice(warpAdapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device)));

return device;
}

void DestroyTestGraphicsDevice(Babylon::Graphics::DeviceT device)
{
if (device != nullptr)
{
device->Release();
}
}
14 changes: 14 additions & 0 deletions Apps/UnitTests/Source/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,17 @@

Babylon::Graphics::TextureT CreateTestTexture(Babylon::Graphics::DeviceT device, uint32_t width, uint32_t height, uint32_t arraySize = 1);
void DestroyTestTexture(Babylon::Graphics::TextureT texture);

// Returns a graphics device suitable for use as Babylon::Graphics::Configuration::Device. The
// returned handle is owned by the caller and must be released with DestroyTestGraphicsDevice.
//
// Defined only on D3D11 and D3D12 -- the Tests.Device.cpp test that consumes these helpers is
// gated to those backends. On D3D11 returns an ID3D11Device created via D3D11CreateDevice(WARP);
// on D3D12 returns an ID3D12Device created via D3D12CreateDevice on the WARP DXGI adapter.
//
// Note: on D3D12, D3D12CreateDevice(WARP) returns the same singleton pointer on successive calls
// in the same process, so two calls in a row may return equal handles. D3D11CreateDevice(WARP)
// does return distinct handles per call.
Babylon::Graphics::DeviceT CreateTestGraphicsDevice();

void DestroyTestGraphicsDevice(Babylon::Graphics::DeviceT device);
Loading