213 lines
7.4 KiB
C++
213 lines
7.4 KiB
C++
#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
|