Files
XCEngine/new_editor/src/XCUIBackend/XCUIHostedPreviewPresenter.h

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