Files
XCEngine/tests/NewEditor/test_native_window_ui_compositor.cpp

213 lines
7.4 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include "XCUIBackend/IWindowUICompositor.h"
#include "XCUIBackend/NativeWindowUICompositor.h"
#include "XCUIBackend/UITextureRegistration.h"
#include <XCEngine/UI/DrawData.h>
#include <array>
#include <cstdint>
#include <memory>
namespace {
using XCEngine::Editor::Platform::D3D12WindowRenderer;
using XCEngine::Editor::XCUIBackend::CreateNativeWindowUICompositor;
using XCEngine::Editor::XCUIBackend::IXCUITextAtlasProvider;
using XCEngine::Editor::XCUIBackend::IWindowUICompositor;
using XCEngine::Editor::XCUIBackend::NativeWindowUICompositor;
using XCEngine::Editor::XCUIBackend::UITextureRegistration;
using XCEngine::Editor::XCUIBackend::XCUINativeWindowPresentStats;
using XCEngine::Editor::XCUIBackend::XCUINativeWindowRenderPacket;
HWND MakeFakeHwnd() {
return reinterpret_cast<HWND>(static_cast<std::uintptr_t>(0x2345u));
}
class StubTextAtlasProvider final : public IXCUITextAtlasProvider {
public:
bool GetAtlasTextureView(PixelFormat preferredFormat, AtlasTextureView& outView) const override {
(void)preferredFormat;
outView = {};
return false;
}
std::size_t GetFontCount() const override {
return 0u;
}
FontHandle GetFont(std::size_t index) const override {
(void)index;
return {};
}
FontHandle GetDefaultFont() const override {
return {};
}
bool GetFontInfo(FontHandle font, FontInfo& outInfo) const override {
(void)font;
outInfo = {};
return false;
}
bool GetBakedFontInfo(FontHandle font, float fontSize, BakedFontInfo& outInfo) const override {
(void)font;
(void)fontSize;
outInfo = {};
return false;
}
bool FindGlyph(FontHandle font, float fontSize, std::uint32_t codepoint, GlyphInfo& outInfo) const override {
(void)font;
(void)fontSize;
(void)codepoint;
outInfo = {};
return false;
}
};
XCEngine::UI::UIDrawData MakeDrawData() {
XCEngine::UI::UIDrawData drawData = {};
drawData.EmplaceDrawList("NativeOverlay").AddFilledRect(
XCEngine::UI::UIRect(10.0f, 12.0f, 48.0f, 24.0f),
XCEngine::UI::UIColor(0.2f, 0.4f, 0.8f, 1.0f));
return drawData;
}
TEST(NativeWindowUICompositorTest, RenderPacketReportsDrawDataPresenceAndClearResetsPayload) {
XCUINativeWindowRenderPacket packet = {};
EXPECT_FALSE(packet.HasDrawData());
EXPECT_EQ(packet.textAtlasProvider, nullptr);
StubTextAtlasProvider atlasProvider = {};
packet.drawData = MakeDrawData();
packet.textAtlasProvider = &atlasProvider;
EXPECT_TRUE(packet.HasDrawData());
EXPECT_EQ(packet.drawData.GetDrawListCount(), 1u);
EXPECT_EQ(packet.drawData.GetTotalCommandCount(), 1u);
EXPECT_EQ(packet.textAtlasProvider, &atlasProvider);
packet.Clear();
EXPECT_FALSE(packet.HasDrawData());
EXPECT_EQ(packet.drawData.GetDrawListCount(), 0u);
EXPECT_EQ(packet.drawData.GetTotalCommandCount(), 0u);
EXPECT_EQ(packet.textAtlasProvider, nullptr);
}
TEST(NativeWindowUICompositorTest, SubmitAndClearPendingPacketTracksCopiedDrawDataAndAtlasProvider) {
NativeWindowUICompositor compositor = {};
StubTextAtlasProvider atlasProvider = {};
const XCEngine::UI::UIDrawData drawData = MakeDrawData();
compositor.SubmitRenderPacket(drawData, &atlasProvider);
ASSERT_TRUE(compositor.HasPendingRenderPacket());
const XCUINativeWindowRenderPacket& packet = compositor.GetPendingRenderPacket();
EXPECT_TRUE(packet.HasDrawData());
EXPECT_EQ(packet.drawData.GetDrawListCount(), 1u);
EXPECT_EQ(packet.drawData.GetTotalCommandCount(), 1u);
EXPECT_EQ(packet.textAtlasProvider, &atlasProvider);
compositor.ClearPendingRenderPacket();
EXPECT_FALSE(compositor.HasPendingRenderPacket());
EXPECT_FALSE(compositor.GetPendingRenderPacket().HasDrawData());
EXPECT_EQ(compositor.GetPendingRenderPacket().textAtlasProvider, nullptr);
}
TEST(NativeWindowUICompositorTest, InitializeAndShutdownResetStateAlongSafePaths) {
NativeWindowUICompositor compositor = {};
D3D12WindowRenderer renderer = {};
compositor.SubmitRenderPacket(MakeDrawData(), nullptr);
ASSERT_TRUE(compositor.HasPendingRenderPacket());
bool configureFontsCalled = false;
EXPECT_FALSE(compositor.Initialize(
nullptr,
renderer,
[&configureFontsCalled]() { configureFontsCalled = true; }));
EXPECT_FALSE(configureFontsCalled);
EXPECT_FALSE(compositor.HasPendingRenderPacket());
compositor.SubmitRenderPacket(MakeDrawData(), nullptr);
EXPECT_TRUE(compositor.Initialize(
MakeFakeHwnd(),
renderer,
[&configureFontsCalled]() { configureFontsCalled = true; }));
EXPECT_FALSE(configureFontsCalled);
EXPECT_FALSE(compositor.HasPendingRenderPacket());
compositor.Shutdown();
EXPECT_FALSE(compositor.HasPendingRenderPacket());
const XCUINativeWindowPresentStats& stats = compositor.GetLastPresentStats();
EXPECT_FALSE(stats.hadPendingPacket);
EXPECT_FALSE(stats.renderedNativeOverlay);
EXPECT_EQ(stats.submittedDrawListCount, 0u);
EXPECT_EQ(stats.submittedCommandCount, 0u);
}
TEST(NativeWindowUICompositorTest, RenderFrameWithUnpreparedRendererSkipsCallbacksAndKeepsPendingPacket) {
NativeWindowUICompositor compositor = {};
D3D12WindowRenderer renderer = {};
ASSERT_TRUE(compositor.Initialize(MakeFakeHwnd(), renderer, {}));
compositor.SubmitRenderPacket(MakeDrawData(), nullptr);
ASSERT_TRUE(compositor.HasPendingRenderPacket());
bool uiRendered = false;
bool beforeUiRendered = false;
bool afterUiRendered = false;
compositor.RenderFrame(
std::array<float, 4>{ 0.1f, 0.2f, 0.3f, 1.0f }.data(),
[&uiRendered]() { uiRendered = true; },
[&beforeUiRendered](const ::XCEngine::Rendering::RenderContext&, const ::XCEngine::Rendering::RenderSurface&) {
beforeUiRendered = true;
},
[&afterUiRendered](const ::XCEngine::Rendering::RenderContext&, const ::XCEngine::Rendering::RenderSurface&) {
afterUiRendered = true;
});
EXPECT_FALSE(uiRendered);
EXPECT_FALSE(beforeUiRendered);
EXPECT_FALSE(afterUiRendered);
EXPECT_TRUE(compositor.HasPendingRenderPacket());
const XCUINativeWindowPresentStats& stats = compositor.GetLastPresentStats();
EXPECT_FALSE(stats.hadPendingPacket);
EXPECT_FALSE(stats.renderedNativeOverlay);
EXPECT_EQ(stats.submittedDrawListCount, 0u);
EXPECT_EQ(stats.submittedCommandCount, 0u);
}
TEST(NativeWindowUICompositorTest, InterfaceFactoryReturnsSafeNativeCompositorDefaults) {
std::unique_ptr<IWindowUICompositor> compositor = CreateNativeWindowUICompositor();
ASSERT_NE(compositor, nullptr);
D3D12WindowRenderer renderer = {};
bool configureFontsCalled = false;
EXPECT_FALSE(compositor->Initialize(
nullptr,
renderer,
[&configureFontsCalled]() { configureFontsCalled = true; }));
EXPECT_FALSE(configureFontsCalled);
EXPECT_FALSE(compositor->HandleWindowMessage(MakeFakeHwnd(), WM_CLOSE, 0u, 0u));
UITextureRegistration registration = {};
EXPECT_FALSE(compositor->CreateTextureDescriptor(nullptr, nullptr, registration));
EXPECT_EQ(registration.texture.nativeHandle, 0u);
bool uiRendered = false;
compositor->RenderFrame(
std::array<float, 4>{ 0.0f, 0.0f, 0.0f, 1.0f }.data(),
[&uiRendered]() { uiRendered = true; },
{},
{});
EXPECT_FALSE(uiRendered);
compositor->Shutdown();
}
} // namespace