#pragma once #include #include #include #include #include #include #include #include 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(texture.width), renderedCanvasRect.y / static_cast(texture.height)); descriptor->image.uvMax = ::XCEngine::UI::UIPoint( (renderedCanvasRect.x + renderedCanvasRect.width) / static_cast(texture.width), (renderedCanvasRect.y + renderedCanvasRect.height) / static_cast(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& 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 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& GetQueuedFrames() const { return m_queuedFrames; } void SetLastDrainStats(const XCUIHostedPreviewDrainStats& stats) { m_lastDrainStats = stats; } const XCUIHostedPreviewDrainStats& GetLastDrainStats() const { return m_lastDrainStats; } private: std::vector 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 CreateQueuedNativeXCUIHostedPreviewPresenter( XCUIHostedPreviewQueue& queue, XCUIHostedPreviewSurfaceRegistry& surfaceRegistry) { return std::make_unique(queue, surfaceRegistry); } inline std::unique_ptr CreateNullXCUIHostedPreviewPresenter() { return std::make_unique(); } } // namespace XCUIBackend } // namespace Editor } // namespace XCEngine