337 lines
11 KiB
C++
337 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <XCEngine/UI/DrawData.h>
|
|
#include <XCEngine/UI/Types.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace XCEngine {
|
|
namespace Editor {
|
|
namespace XCUIBackend {
|
|
|
|
struct XCUIHostedPreviewFrame {
|
|
const ::XCEngine::UI::UIDrawData* drawData = 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 {
|
|
::XCEngine::UI::UITextureHandle texture = {};
|
|
::XCEngine::UI::UIPoint uvMin = {};
|
|
::XCEngine::UI::UIPoint uvMax = ::XCEngine::UI::UIPoint(1.0f, 1.0f);
|
|
::XCEngine::UI::UIRect renderedCanvasRect = {};
|
|
std::uint32_t surfaceWidth = 0;
|
|
std::uint32_t surfaceHeight = 0;
|
|
|
|
bool IsValid() const {
|
|
return texture.IsValid() && 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,
|
|
const ::XCEngine::UI::UITextureHandle& texture,
|
|
const ::XCEngine::UI::UIRect& renderedCanvasRect) {
|
|
if (debugName.empty() || !texture.IsValid()) {
|
|
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.texture = texture;
|
|
descriptor->image.surfaceWidth = texture.width;
|
|
descriptor->image.surfaceHeight = texture.height;
|
|
descriptor->image.renderedCanvasRect = renderedCanvasRect;
|
|
descriptor->image.uvMin = ::XCEngine::UI::UIPoint(
|
|
renderedCanvasRect.x / static_cast<float>(texture.width),
|
|
renderedCanvasRect.y / static_cast<float>(texture.height));
|
|
descriptor->image.uvMax = ::XCEngine::UI::UIPoint(
|
|
(renderedCanvasRect.x + renderedCanvasRect.width) / static_cast<float>(texture.width),
|
|
(renderedCanvasRect.y + renderedCanvasRect.height) / static_cast<float>(texture.height));
|
|
}
|
|
|
|
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 NullXCUIHostedPreviewPresenter final : public IXCUIHostedPreviewPresenter {
|
|
public:
|
|
bool Present(const XCUIHostedPreviewFrame& frame) override {
|
|
m_lastStats = {};
|
|
if (frame.drawData == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
m_lastStats.submittedDrawListCount = frame.drawData->GetDrawListCount();
|
|
m_lastStats.submittedCommandCount = frame.drawData->GetTotalCommandCount();
|
|
return false;
|
|
}
|
|
|
|
const XCUIHostedPreviewStats& GetLastStats() const override {
|
|
return m_lastStats;
|
|
}
|
|
|
|
private:
|
|
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> CreateQueuedNativeXCUIHostedPreviewPresenter(
|
|
XCUIHostedPreviewQueue& queue,
|
|
XCUIHostedPreviewSurfaceRegistry& surfaceRegistry) {
|
|
return std::make_unique<QueuedNativeXCUIHostedPreviewPresenter>(queue, surfaceRegistry);
|
|
}
|
|
|
|
inline std::unique_ptr<IXCUIHostedPreviewPresenter> CreateNullXCUIHostedPreviewPresenter() {
|
|
return std::make_unique<NullXCUIHostedPreviewPresenter>();
|
|
}
|
|
|
|
} // namespace XCUIBackend
|
|
} // namespace Editor
|
|
} // namespace XCEngine
|