Add XCUI new editor sandbox phase 1
This commit is contained in:
349
new_editor/src/XCUIBackend/XCUIHostedPreviewPresenter.h
Normal file
349
new_editor/src/XCUIBackend/XCUIHostedPreviewPresenter.h
Normal file
@@ -0,0 +1,349 @@
|
||||
#pragma once
|
||||
|
||||
#include "XCUIBackend/ImGuiTransitionBackend.h"
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
struct ImDrawList;
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace XCUIBackend {
|
||||
|
||||
struct XCUIHostedPreviewFrame {
|
||||
const ::XCEngine::UI::UIDrawData* drawData = nullptr;
|
||||
ImDrawList* targetDrawList = nullptr;
|
||||
::XCEngine::UI::UIRect canvasRect = {};
|
||||
::XCEngine::UI::UISize logicalSize = {};
|
||||
const char* debugName = nullptr;
|
||||
const char* debugSource = nullptr;
|
||||
};
|
||||
|
||||
struct XCUIHostedPreviewStats {
|
||||
bool presented = false;
|
||||
bool queuedToNativePass = false;
|
||||
std::size_t submittedDrawListCount = 0;
|
||||
std::size_t submittedCommandCount = 0;
|
||||
std::size_t flushedDrawListCount = 0;
|
||||
std::size_t flushedCommandCount = 0;
|
||||
};
|
||||
|
||||
struct XCUIHostedPreviewQueuedFrame {
|
||||
std::string debugName = {};
|
||||
std::string debugSource = {};
|
||||
::XCEngine::UI::UIRect canvasRect = {};
|
||||
::XCEngine::UI::UISize logicalSize = {};
|
||||
::XCEngine::UI::UIDrawData drawData = {};
|
||||
};
|
||||
|
||||
struct XCUIHostedPreviewSurfaceImage {
|
||||
ImTextureID textureId = {};
|
||||
ImVec2 uvMin = ImVec2(0.0f, 0.0f);
|
||||
ImVec2 uvMax = ImVec2(1.0f, 1.0f);
|
||||
::XCEngine::UI::UIRect renderedCanvasRect = {};
|
||||
std::uint32_t surfaceWidth = 0;
|
||||
std::uint32_t surfaceHeight = 0;
|
||||
|
||||
bool IsValid() const {
|
||||
return textureId != ImTextureID{} && surfaceWidth > 0u && surfaceHeight > 0u;
|
||||
}
|
||||
};
|
||||
|
||||
struct XCUIHostedPreviewDrainStats {
|
||||
std::size_t queuedFrameCount = 0;
|
||||
std::size_t queuedDrawListCount = 0;
|
||||
std::size_t queuedCommandCount = 0;
|
||||
std::size_t renderedFrameCount = 0;
|
||||
std::size_t renderedDrawListCount = 0;
|
||||
std::size_t renderedCommandCount = 0;
|
||||
std::size_t skippedFrameCount = 0;
|
||||
std::size_t skippedCommandCount = 0;
|
||||
};
|
||||
|
||||
struct XCUIHostedPreviewSurfaceDescriptor {
|
||||
std::string debugName = {};
|
||||
std::string debugSource = {};
|
||||
::XCEngine::UI::UIRect canvasRect = {};
|
||||
::XCEngine::UI::UISize logicalSize = {};
|
||||
std::size_t queuedFrameIndex = 0;
|
||||
std::size_t submittedDrawListCount = 0;
|
||||
std::size_t submittedCommandCount = 0;
|
||||
bool queuedThisFrame = false;
|
||||
XCUIHostedPreviewSurfaceImage image = {};
|
||||
};
|
||||
|
||||
class XCUIHostedPreviewSurfaceRegistry {
|
||||
public:
|
||||
void BeginFrame() {
|
||||
for (XCUIHostedPreviewSurfaceDescriptor& descriptor : m_descriptors) {
|
||||
descriptor.queuedThisFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RecordQueuedFrame(
|
||||
const XCUIHostedPreviewQueuedFrame& queuedFrame,
|
||||
std::size_t queuedFrameIndex = 0u) {
|
||||
if (queuedFrame.debugName.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
XCUIHostedPreviewSurfaceDescriptor* descriptor = FindMutableDescriptor(queuedFrame.debugName);
|
||||
if (descriptor == nullptr) {
|
||||
XCUIHostedPreviewSurfaceDescriptor newDescriptor = {};
|
||||
newDescriptor.debugName = queuedFrame.debugName;
|
||||
m_descriptors.push_back(std::move(newDescriptor));
|
||||
descriptor = &m_descriptors.back();
|
||||
}
|
||||
|
||||
descriptor->debugSource = queuedFrame.debugSource;
|
||||
descriptor->canvasRect = queuedFrame.canvasRect;
|
||||
descriptor->logicalSize = queuedFrame.logicalSize;
|
||||
descriptor->queuedFrameIndex = queuedFrameIndex;
|
||||
descriptor->submittedDrawListCount = queuedFrame.drawData.GetDrawListCount();
|
||||
descriptor->submittedCommandCount = queuedFrame.drawData.GetTotalCommandCount();
|
||||
descriptor->queuedThisFrame = true;
|
||||
}
|
||||
|
||||
void UpdateSurface(
|
||||
const std::string& debugName,
|
||||
ImTextureID textureId,
|
||||
std::uint32_t surfaceWidth,
|
||||
std::uint32_t surfaceHeight,
|
||||
const ::XCEngine::UI::UIRect& renderedCanvasRect) {
|
||||
if (debugName.empty() || textureId == ImTextureID{} || surfaceWidth == 0u || surfaceHeight == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
XCUIHostedPreviewSurfaceDescriptor* descriptor = FindMutableDescriptor(debugName);
|
||||
if (descriptor == nullptr) {
|
||||
XCUIHostedPreviewSurfaceDescriptor newDescriptor = {};
|
||||
newDescriptor.debugName = debugName;
|
||||
m_descriptors.push_back(std::move(newDescriptor));
|
||||
descriptor = &m_descriptors.back();
|
||||
}
|
||||
|
||||
descriptor->image.textureId = textureId;
|
||||
descriptor->image.surfaceWidth = surfaceWidth;
|
||||
descriptor->image.surfaceHeight = surfaceHeight;
|
||||
descriptor->image.renderedCanvasRect = renderedCanvasRect;
|
||||
descriptor->image.uvMin = ImVec2(
|
||||
renderedCanvasRect.x / static_cast<float>(surfaceWidth),
|
||||
renderedCanvasRect.y / static_cast<float>(surfaceHeight));
|
||||
descriptor->image.uvMax = ImVec2(
|
||||
(renderedCanvasRect.x + renderedCanvasRect.width) / static_cast<float>(surfaceWidth),
|
||||
(renderedCanvasRect.y + renderedCanvasRect.height) / static_cast<float>(surfaceHeight));
|
||||
}
|
||||
|
||||
bool TryGetSurfaceDescriptor(
|
||||
const char* debugName,
|
||||
XCUIHostedPreviewSurfaceDescriptor& outDescriptor) const {
|
||||
outDescriptor = {};
|
||||
if (debugName == nullptr || debugName[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const XCUIHostedPreviewSurfaceDescriptor& descriptor : m_descriptors) {
|
||||
if (descriptor.debugName == debugName) {
|
||||
outDescriptor = descriptor;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryGetSurfaceImage(const char* debugName, XCUIHostedPreviewSurfaceImage& outImage) const {
|
||||
outImage = {};
|
||||
XCUIHostedPreviewSurfaceDescriptor descriptor = {};
|
||||
if (!TryGetSurfaceDescriptor(debugName, descriptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outImage = descriptor.image;
|
||||
return outImage.IsValid();
|
||||
}
|
||||
|
||||
const std::vector<XCUIHostedPreviewSurfaceDescriptor>& GetDescriptors() const {
|
||||
return m_descriptors;
|
||||
}
|
||||
|
||||
private:
|
||||
XCUIHostedPreviewSurfaceDescriptor* FindMutableDescriptor(const std::string& debugName) {
|
||||
for (XCUIHostedPreviewSurfaceDescriptor& descriptor : m_descriptors) {
|
||||
if (descriptor.debugName == debugName) {
|
||||
return &descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<XCUIHostedPreviewSurfaceDescriptor> m_descriptors = {};
|
||||
};
|
||||
|
||||
class XCUIHostedPreviewQueue {
|
||||
public:
|
||||
void BeginFrame() {
|
||||
m_queuedFrames.clear();
|
||||
}
|
||||
|
||||
bool Submit(const XCUIHostedPreviewFrame& frame, XCUIHostedPreviewStats* outStats = nullptr) {
|
||||
XCUIHostedPreviewStats stats = {};
|
||||
if (frame.drawData == nullptr) {
|
||||
if (outStats != nullptr) {
|
||||
*outStats = stats;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
XCUIHostedPreviewQueuedFrame queuedFrame = {};
|
||||
if (frame.debugName != nullptr) {
|
||||
queuedFrame.debugName = frame.debugName;
|
||||
}
|
||||
if (frame.debugSource != nullptr) {
|
||||
queuedFrame.debugSource = frame.debugSource;
|
||||
}
|
||||
queuedFrame.canvasRect = frame.canvasRect;
|
||||
queuedFrame.logicalSize = frame.logicalSize.width > 0.0f && frame.logicalSize.height > 0.0f
|
||||
? frame.logicalSize
|
||||
: ::XCEngine::UI::UISize(frame.canvasRect.width, frame.canvasRect.height);
|
||||
queuedFrame.drawData = *frame.drawData;
|
||||
|
||||
stats.presented = true;
|
||||
stats.queuedToNativePass = true;
|
||||
stats.submittedDrawListCount = queuedFrame.drawData.GetDrawListCount();
|
||||
stats.submittedCommandCount = queuedFrame.drawData.GetTotalCommandCount();
|
||||
m_queuedFrames.push_back(std::move(queuedFrame));
|
||||
|
||||
if (outStats != nullptr) {
|
||||
*outStats = stats;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<XCUIHostedPreviewQueuedFrame>& GetQueuedFrames() const {
|
||||
return m_queuedFrames;
|
||||
}
|
||||
|
||||
void SetLastDrainStats(const XCUIHostedPreviewDrainStats& stats) {
|
||||
m_lastDrainStats = stats;
|
||||
}
|
||||
|
||||
const XCUIHostedPreviewDrainStats& GetLastDrainStats() const {
|
||||
return m_lastDrainStats;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<XCUIHostedPreviewQueuedFrame> m_queuedFrames = {};
|
||||
XCUIHostedPreviewDrainStats m_lastDrainStats = {};
|
||||
};
|
||||
|
||||
class IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
virtual ~IXCUIHostedPreviewPresenter() = default;
|
||||
|
||||
virtual bool Present(const XCUIHostedPreviewFrame& frame) = 0;
|
||||
virtual const XCUIHostedPreviewStats& GetLastStats() const = 0;
|
||||
virtual bool IsNativeQueued() const { return false; }
|
||||
virtual bool TryGetSurfaceImage(
|
||||
const char* debugName,
|
||||
XCUIHostedPreviewSurfaceImage& outImage) const {
|
||||
outImage = {};
|
||||
return false;
|
||||
}
|
||||
virtual bool TryGetSurfaceDescriptor(
|
||||
const char* debugName,
|
||||
XCUIHostedPreviewSurfaceDescriptor& outDescriptor) const {
|
||||
outDescriptor = {};
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class ImGuiXCUIHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
||||
m_lastStats = {};
|
||||
if (frame.drawData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_backend.BeginFrame();
|
||||
m_backend.Submit(*frame.drawData);
|
||||
m_lastStats.submittedDrawListCount = m_backend.GetPendingDrawListCount();
|
||||
m_lastStats.submittedCommandCount = m_backend.GetPendingCommandCount();
|
||||
m_lastStats.presented = m_backend.EndFrame(frame.targetDrawList);
|
||||
m_lastStats.flushedDrawListCount = m_backend.GetLastFlushedDrawListCount();
|
||||
m_lastStats.flushedCommandCount = m_backend.GetLastFlushedCommandCount();
|
||||
return m_lastStats.presented;
|
||||
}
|
||||
|
||||
const XCUIHostedPreviewStats& GetLastStats() const override {
|
||||
return m_lastStats;
|
||||
}
|
||||
|
||||
private:
|
||||
ImGuiTransitionBackend m_backend = {};
|
||||
XCUIHostedPreviewStats m_lastStats = {};
|
||||
};
|
||||
|
||||
class QueuedNativeXCUIHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
||||
public:
|
||||
QueuedNativeXCUIHostedPreviewPresenter(
|
||||
XCUIHostedPreviewQueue& queue,
|
||||
XCUIHostedPreviewSurfaceRegistry& surfaceRegistry)
|
||||
: m_queue(queue)
|
||||
, m_surfaceRegistry(surfaceRegistry) {
|
||||
}
|
||||
|
||||
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
||||
m_lastStats = {};
|
||||
return m_queue.Submit(frame, &m_lastStats);
|
||||
}
|
||||
|
||||
const XCUIHostedPreviewStats& GetLastStats() const override {
|
||||
return m_lastStats;
|
||||
}
|
||||
|
||||
bool IsNativeQueued() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryGetSurfaceImage(
|
||||
const char* debugName,
|
||||
XCUIHostedPreviewSurfaceImage& outImage) const override {
|
||||
return m_surfaceRegistry.TryGetSurfaceImage(debugName, outImage);
|
||||
}
|
||||
|
||||
bool TryGetSurfaceDescriptor(
|
||||
const char* debugName,
|
||||
XCUIHostedPreviewSurfaceDescriptor& outDescriptor) const override {
|
||||
return m_surfaceRegistry.TryGetSurfaceDescriptor(debugName, outDescriptor);
|
||||
}
|
||||
|
||||
private:
|
||||
XCUIHostedPreviewQueue& m_queue;
|
||||
XCUIHostedPreviewSurfaceRegistry& m_surfaceRegistry;
|
||||
XCUIHostedPreviewStats m_lastStats = {};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<IXCUIHostedPreviewPresenter> CreateImGuiXCUIHostedPreviewPresenter() {
|
||||
return std::make_unique<ImGuiXCUIHostedPreviewPresenter>();
|
||||
}
|
||||
|
||||
inline std::unique_ptr<IXCUIHostedPreviewPresenter> CreateQueuedNativeXCUIHostedPreviewPresenter(
|
||||
XCUIHostedPreviewQueue& queue,
|
||||
XCUIHostedPreviewSurfaceRegistry& surfaceRegistry) {
|
||||
return std::make_unique<QueuedNativeXCUIHostedPreviewPresenter>(queue, surfaceRegistry);
|
||||
}
|
||||
|
||||
} // namespace XCUIBackend
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user