2026-04-05 13:24:14 +08:00
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
|
|
|
|
#include "panels/XCUIDemoPanel.h"
|
|
|
|
|
|
|
|
|
|
#include "XCUIBackend/XCUIHostedPreviewPresenter.h"
|
|
|
|
|
#include "XCUIBackend/XCUIPanelCanvasHost.h"
|
|
|
|
|
|
|
|
|
|
#include <imgui.h>
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <string_view>
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter;
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::IXCUIPanelCanvasHost;
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewFrame;
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::XCUIHostedPreviewStats;
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasRequest;
|
|
|
|
|
using XCEngine::Editor::XCUIBackend::XCUIPanelCanvasSession;
|
|
|
|
|
using XCEngine::NewEditor::XCUIDemoPanel;
|
|
|
|
|
|
|
|
|
|
class ImGuiContextScope {
|
|
|
|
|
public:
|
|
|
|
|
ImGuiContextScope() {
|
|
|
|
|
IMGUI_CHECKVERSION();
|
|
|
|
|
ImGui::CreateContext();
|
|
|
|
|
ImGui::StyleColorsDark();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ImGuiContextScope() {
|
|
|
|
|
ImGui::DestroyContext();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void PrepareImGui(float width = 1280.0f, float height = 900.0f) {
|
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
io.DisplaySize = ImVec2(width, height);
|
|
|
|
|
io.DeltaTime = 1.0f / 60.0f;
|
|
|
|
|
unsigned char* fontPixels = nullptr;
|
|
|
|
|
int fontWidth = 0;
|
|
|
|
|
int fontHeight = 0;
|
|
|
|
|
io.Fonts->GetTexDataAsRGBA32(&fontPixels, &fontWidth, &fontHeight);
|
|
|
|
|
io.Fonts->SetTexID(static_cast<ImTextureID>(1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class RecordingHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
|
|
|
|
public:
|
|
|
|
|
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
|
|
|
|
++presentCallCount;
|
|
|
|
|
lastCanvasRect = frame.canvasRect;
|
|
|
|
|
lastLogicalSize = frame.logicalSize;
|
|
|
|
|
lastDebugName = frame.debugName != nullptr ? frame.debugName : "";
|
|
|
|
|
|
|
|
|
|
m_lastStats = {};
|
|
|
|
|
if (frame.drawData == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastDrawListCount = frame.drawData->GetDrawListCount();
|
|
|
|
|
lastCommandCount = frame.drawData->GetTotalCommandCount();
|
|
|
|
|
m_lastStats.presented = true;
|
|
|
|
|
m_lastStats.submittedDrawListCount = lastDrawListCount;
|
|
|
|
|
m_lastStats.submittedCommandCount = lastCommandCount;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const XCUIHostedPreviewStats& GetLastStats() const override {
|
|
|
|
|
return m_lastStats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t presentCallCount = 0u;
|
|
|
|
|
XCEngine::UI::UIRect lastCanvasRect = {};
|
|
|
|
|
XCEngine::UI::UISize lastLogicalSize = {};
|
|
|
|
|
std::size_t lastDrawListCount = 0u;
|
|
|
|
|
std::size_t lastCommandCount = 0u;
|
|
|
|
|
std::string lastDebugName = {};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
XCUIHostedPreviewStats m_lastStats = {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class StubCanvasHost final : public IXCUIPanelCanvasHost {
|
|
|
|
|
public:
|
|
|
|
|
const char* GetDebugName() const override {
|
|
|
|
|
return "StubCanvasHost";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XCUIPanelCanvasSession BeginCanvas(const XCUIPanelCanvasRequest& request) override {
|
|
|
|
|
lastRequest = request;
|
|
|
|
|
++beginCanvasCallCount;
|
|
|
|
|
return session;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawFilledRect(
|
|
|
|
|
const XCEngine::UI::UIRect&,
|
|
|
|
|
const XCEngine::UI::UIColor&,
|
|
|
|
|
float) override {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawOutlineRect(
|
|
|
|
|
const XCEngine::UI::UIRect&,
|
|
|
|
|
const XCEngine::UI::UIColor&,
|
|
|
|
|
float,
|
|
|
|
|
float) override {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawText(
|
|
|
|
|
const XCEngine::UI::UIPoint&,
|
|
|
|
|
std::string_view,
|
|
|
|
|
const XCEngine::UI::UIColor&,
|
|
|
|
|
float) override {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EndCanvas() override {
|
|
|
|
|
++endCanvasCallCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t beginCanvasCallCount = 0u;
|
|
|
|
|
std::size_t endCanvasCallCount = 0u;
|
|
|
|
|
XCUIPanelCanvasRequest lastRequest = {};
|
|
|
|
|
XCUIPanelCanvasSession session = {
|
|
|
|
|
XCEngine::UI::UIRect(0.0f, 0.0f, 960.0f, 640.0f),
|
|
|
|
|
XCEngine::UI::UIRect(12.0f, 18.0f, 936.0f, 512.0f),
|
|
|
|
|
XCEngine::UI::UIPoint(120.0f, 140.0f),
|
|
|
|
|
true,
|
|
|
|
|
true,
|
|
|
|
|
true
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void RenderPanelFrame(XCUIDemoPanel& panel, ImGuiContextScope&) {
|
|
|
|
|
PrepareImGui();
|
|
|
|
|
ImGui::NewFrame();
|
|
|
|
|
panel.Render();
|
|
|
|
|
ImGui::Render();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(NewEditorXCUIDemoPanelTest, DefaultConstructionDoesNotAutoCreateHostedPreviewPresenter) {
|
|
|
|
|
ImGuiContextScope contextScope;
|
|
|
|
|
|
|
|
|
|
auto canvasHost = std::make_unique<StubCanvasHost>();
|
|
|
|
|
XCUIDemoPanel panel;
|
|
|
|
|
panel.SetCanvasHost(std::move(canvasHost));
|
|
|
|
|
|
|
|
|
|
RenderPanelFrame(panel, contextScope);
|
|
|
|
|
|
|
|
|
|
const XCUIHostedPreviewStats& stats = panel.GetLastPreviewStats();
|
|
|
|
|
EXPECT_FALSE(stats.presented);
|
|
|
|
|
EXPECT_FALSE(stats.queuedToNativePass);
|
|
|
|
|
EXPECT_EQ(stats.submittedDrawListCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.submittedCommandCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(NewEditorXCUIDemoPanelTest, ConstructorUsesGenericNullCanvasHostUntilOuterLayerInjectsOne) {
|
|
|
|
|
ImGuiContextScope contextScope;
|
|
|
|
|
|
|
|
|
|
auto previewPresenter = std::make_unique<RecordingHostedPreviewPresenter>();
|
|
|
|
|
RecordingHostedPreviewPresenter* previewPresenterPtr = previewPresenter.get();
|
|
|
|
|
|
|
|
|
|
XCUIDemoPanel panel(nullptr, std::move(previewPresenter));
|
|
|
|
|
RenderPanelFrame(panel, contextScope);
|
|
|
|
|
|
|
|
|
|
ASSERT_EQ(previewPresenterPtr->presentCallCount, 1u);
|
|
|
|
|
EXPECT_EQ(previewPresenterPtr->lastDebugName, "XCUI Demo");
|
|
|
|
|
EXPECT_FLOAT_EQ(previewPresenterPtr->lastCanvasRect.x, 0.0f);
|
|
|
|
|
EXPECT_GT(previewPresenterPtr->lastCanvasRect.y, 0.0f);
|
|
|
|
|
EXPECT_FLOAT_EQ(previewPresenterPtr->lastCanvasRect.width, 0.0f);
|
|
|
|
|
EXPECT_GT(previewPresenterPtr->lastCanvasRect.height, 0.0f);
|
|
|
|
|
EXPECT_FLOAT_EQ(previewPresenterPtr->lastLogicalSize.width, 0.0f);
|
|
|
|
|
EXPECT_FLOAT_EQ(
|
|
|
|
|
previewPresenterPtr->lastLogicalSize.height,
|
|
|
|
|
previewPresenterPtr->lastCanvasRect.height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(NewEditorXCUIDemoPanelTest, ClearingHostedPreviewPresenterDoesNotRestoreImGuiFallback) {
|
|
|
|
|
ImGuiContextScope contextScope;
|
|
|
|
|
|
|
|
|
|
auto previewPresenter = std::make_unique<RecordingHostedPreviewPresenter>();
|
|
|
|
|
RecordingHostedPreviewPresenter* previewPresenterPtr = previewPresenter.get();
|
|
|
|
|
auto canvasHost = std::make_unique<StubCanvasHost>();
|
|
|
|
|
|
|
|
|
|
XCUIDemoPanel panel(nullptr, std::move(previewPresenter));
|
|
|
|
|
panel.SetCanvasHost(std::move(canvasHost));
|
|
|
|
|
|
|
|
|
|
RenderPanelFrame(panel, contextScope);
|
|
|
|
|
ASSERT_EQ(previewPresenterPtr->presentCallCount, 1u);
|
|
|
|
|
EXPECT_TRUE(panel.GetLastPreviewStats().presented);
|
|
|
|
|
|
|
|
|
|
panel.SetHostedPreviewPresenter(nullptr);
|
|
|
|
|
RenderPanelFrame(panel, contextScope);
|
|
|
|
|
|
|
|
|
|
const XCUIHostedPreviewStats& stats = panel.GetLastPreviewStats();
|
|
|
|
|
EXPECT_FALSE(stats.presented);
|
|
|
|
|
EXPECT_FALSE(stats.queuedToNativePass);
|
|
|
|
|
EXPECT_EQ(stats.submittedDrawListCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.submittedCommandCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.flushedDrawListCount, 0u);
|
|
|
|
|
EXPECT_EQ(stats.flushedCommandCount, 0u);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 17:41:31 +08:00
|
|
|
TEST(NewEditorXCUIDemoPanelTest, ComposeFrameBuildsShellAgnosticFrameState) {
|
|
|
|
|
auto previewPresenter = std::make_unique<RecordingHostedPreviewPresenter>();
|
|
|
|
|
RecordingHostedPreviewPresenter* previewPresenterPtr = previewPresenter.get();
|
|
|
|
|
auto canvasHost = std::make_unique<StubCanvasHost>();
|
|
|
|
|
StubCanvasHost* canvasHostPtr = canvasHost.get();
|
|
|
|
|
|
|
|
|
|
XCUIDemoPanel panel(nullptr, std::move(previewPresenter));
|
|
|
|
|
panel.SetCanvasHost(std::move(canvasHost));
|
|
|
|
|
|
|
|
|
|
const XCEngine::NewEditor::XCUIDemoPanelFrameComposition& composition =
|
|
|
|
|
panel.ComposeFrame(XCEngine::NewEditor::XCUIDemoPanelFrameComposeOptions{
|
|
|
|
|
512.0f,
|
|
|
|
|
24.0f,
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
123456u,
|
|
|
|
|
"XCUIDemoTestCanvas"});
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(&composition, &panel.GetLastFrameComposition());
|
|
|
|
|
ASSERT_NE(composition.frame, nullptr);
|
|
|
|
|
EXPECT_TRUE(composition.hostedPreviewEnabled);
|
|
|
|
|
EXPECT_FALSE(composition.nativeHostedPreview);
|
|
|
|
|
EXPECT_FALSE(composition.hasHostedSurfaceDescriptor);
|
|
|
|
|
EXPECT_FALSE(composition.showHostedSurfaceImage);
|
|
|
|
|
EXPECT_EQ(composition.previewPathLabel, "hosted presenter");
|
|
|
|
|
EXPECT_EQ(composition.previewStateLabel, "live");
|
|
|
|
|
EXPECT_EQ(composition.inputSnapshot.timestampNanoseconds, 123456u);
|
|
|
|
|
EXPECT_EQ(composition.canvasSession.canvasRect.width, canvasHostPtr->session.canvasRect.width);
|
|
|
|
|
EXPECT_EQ(composition.canvasSession.canvasRect.height, canvasHostPtr->session.canvasRect.height);
|
|
|
|
|
EXPECT_EQ(composition.input.canvasRect.width, canvasHostPtr->session.canvasRect.width);
|
|
|
|
|
EXPECT_EQ(composition.input.canvasRect.height, canvasHostPtr->session.canvasRect.height);
|
|
|
|
|
EXPECT_EQ(canvasHostPtr->beginCanvasCallCount, 1u);
|
|
|
|
|
EXPECT_EQ(canvasHostPtr->endCanvasCallCount, 1u);
|
|
|
|
|
EXPECT_FLOAT_EQ(canvasHostPtr->lastRequest.height, 512.0f);
|
|
|
|
|
EXPECT_FLOAT_EQ(canvasHostPtr->lastRequest.topInset, 24.0f);
|
|
|
|
|
EXPECT_STREQ(canvasHostPtr->lastRequest.childId, "XCUIDemoTestCanvas");
|
|
|
|
|
EXPECT_EQ(previewPresenterPtr->presentCallCount, 1u);
|
|
|
|
|
EXPECT_EQ(previewPresenterPtr->lastDebugName, "XCUI Demo");
|
|
|
|
|
EXPECT_EQ(composition.previewStats.submittedDrawListCount, panel.GetLastPreviewStats().submittedDrawListCount);
|
|
|
|
|
EXPECT_EQ(composition.previewStats.submittedCommandCount, panel.GetLastPreviewStats().submittedCommandCount);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 13:24:14 +08:00
|
|
|
} // namespace
|