C

实现硬件层支持

实现硬件层支持

一些硬件平台支持层,这意味着您可以在多个独立的视觉层上绘制内容,并让硬件将它们混合在一起。硬件也可能允许您直接从闪存中的图像数据定义层内容。这应该有助于通过使用图像进行静态背景内容和使用帧缓冲区进行动态内容来减少易失性内存的使用。

本章解释了如果目标平台支持,硬件层支持如何实现。如果不支持,可以跳过本章的全部内容,并从平台代码中移除与层相关的代码路径。

层引擎接口

首先,重载由 Qt Quick Ultralite核心使用的 Qul::PlatformInterface::LayerEngine 接口,该接口用于分配、更新和释放平台层。

class ExampleLayerEngine : public PlatformInterface::LayerEngine
{
public:
    ItemLayer *allocateItemLayer(const PlatformInterface::Screen *,
                                 const ItemLayerProperties &props,
                                 SpriteLayer *spriteLayer = NULL) QUL_DECL_OVERRIDE;
    ImageLayer *allocateImageLayer(const PlatformInterface::Screen *,
                                   const ImageLayerProperties &props,
                                   SpriteLayer *spriteLayer = NULL) QUL_DECL_OVERRIDE;
    SpriteLayer *allocateSpriteLayer(const PlatformInterface::Screen *,
                                     const SpriteLayerProperties &props) QUL_DECL_OVERRIDE;

    void deallocateItemLayer(ItemLayer *layer) QUL_DECL_OVERRIDE;
    void deallocateImageLayer(ImageLayer *layer) QUL_DECL_OVERRIDE;
    void deallocateSpriteLayer(SpriteLayer *layer) QUL_DECL_OVERRIDE;

    void updateItemLayer(ItemLayer *layer, const ItemLayerProperties &props) QUL_DECL_OVERRIDE;
    void updateImageLayer(ImageLayer *layer, const ImageLayerProperties &props) QUL_DECL_OVERRIDE;
    void updateSpriteLayer(SpriteLayer *layer, const SpriteLayerProperties &props) QUL_DECL_OVERRIDE;

    static PlatformInterface::DrawingDevice *beginFrame(const PlatformInterface::LayerEngine::ItemLayer *,
                                                        const PlatformInterface::Rect &,
                                                        int refreshInterval);
    static void endFrame(const PlatformInterface::LayerEngine::ItemLayer *);
    static FrameStatistics presentFrame(const PlatformInterface::Screen *screen, const PlatformInterface::Rect &rect);

    static Qul::Platform::FramebufferFormat framebufferFormat(const PlatformInterface::LayerEngine::ItemLayer *layer);
};

示例类还包括对 PlatformContext::beginFramePlatformContext::endFramePlatformContext::presentFrame 的自定义实现。如果示例 platform_context.cpp 中将 enableLayerEngine 设置为,则这些函数将转发到 ExampleLayerEngine 版本而不是默认的非层实现。

为了使用 ExampleLayerEngine,需要在示例平台中启用层支持。必须将 enableLayerEngine 的值设置为 true (默认情况下为 false,如下所示)

const bool enableLayerEngine = false;

如果将 enableLayerEngine 设置为 true,则可以删除 PlatformContext::beginFramePlatformContext::endFramePlatformContext::presentFrame 方法中的跳过部分。

此外,必须实现 PlatformContext::layerEngine 方法以返回指向 Qul::PlatformInterface::LayerEngine 实例的指针。在这种情况下,是一个静态分配的 ExampleLayerEngine 实例

PlatformInterface::LayerEngine *ExamplePlatform::layerEngine()
{
    if (enableLayerEngine) {
        static ExampleLayerEngine layerEngine;
        return &layerEngine;
    } else {
        return NULL;
    }
}

层引擎接口的实现

为了实现层引擎接口,创建Qul::PlatformInterface::LayerEngine::ItemLayer、Qul::PlatformInterface::LayerEngine::ImageLayer和Qul::PlatformInterface::LayerEngine::SpriteLayer不可见类型的子类。这些子类可以用来存储平台特定层数据。

位于精灵层内部的图像和项层与根层中的图像和项层实施不同的实现。在示例平台中,使用ExampleImageLayerExampleImageSprite类分别代表根图像层和精灵图像层。类似地,ExampleItemLayerExampleItemSprite类代表项层,而ExampleSpriteLayer类代表精灵层。

以下代码片段显示了这些对象在示例平台中的分配情况。如果要支持多屏幕,必须考虑Qul::PlatformInterface::Screen指针以在正确的屏幕上显示层。

PlatformInterface::LayerEngine::ItemLayer *ExampleLayerEngine::allocateItemLayer(const PlatformInterface::Screen *,
                                                                                 const ItemLayerProperties &props,
                                                                                 SpriteLayer *spriteLayer)
{
    ItemLayer *layer;
    if (spriteLayer) {
        ExampleSpriteLayer *exampleSpriteLayer = static_cast<ExampleSpriteLayer *>(spriteLayer);
        layer = new ExampleItemSprite(props, exampleSpriteLayer);
    } else {
        layer = new ExampleItemLayer(props);
    }

    return layer;
}

PlatformInterface::LayerEngine::ImageLayer *ExampleLayerEngine::allocateImageLayer(const PlatformInterface::Screen *,
                                                                                   const ImageLayerProperties &props,
                                                                                   SpriteLayer *spriteLayer)
{
    ImageLayer *layer;
    if (spriteLayer) {
        ExampleSpriteLayer *exampleSpriteLayer = static_cast<ExampleSpriteLayer *>(spriteLayer);
        layer = new ExampleImageSprite(props, exampleSpriteLayer);
    } else {
        layer = new ExampleImageLayer(props);
    }

    return layer;
}

PlatformInterface::LayerEngine::SpriteLayer *ExampleLayerEngine::allocateSpriteLayer(const PlatformInterface::Screen *,
                                                                                     const SpriteLayerProperties &props)
{
    return new ExampleSpriteLayer(props);
}

为了安全地将Qul::PlatformInterface::LayerEngine::ImageLayer不可见类型向下转换,ExampleImageLayerExampleImageSprite类继承自ExampleImageLayerBase,而ExampleImageLayerBase又继承自Qul::PlatformInterface::LayerEngine::ImageLayer

struct ExampleImageLayerBase : public Qul::PlatformInterface::LayerEngine::ImageLayer
{
    virtual ~ExampleImageLayerBase() {}
    virtual void updateProperties(const Qul::PlatformInterface::LayerEngine::ImageLayerProperties &props) = 0;
};

它包含一个虚析构函数,以便调用正确的子类析构函数,以及一个当图像层属性发生变化时更新图像层属性的虚函数。

类似地,存在ExampleItemLayerBase,它是由ExampleItemLayerExampleSpriteLayer继承的。

struct ExampleItemLayerBase : public Qul::PlatformInterface::LayerEngine::ItemLayer
{
    ExampleItemLayerBase(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &props);

    virtual ~ExampleItemLayerBase() {}
    virtual void updateProperties(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &props) = 0;
    virtual unsigned char *getNextDrawBuffer() = 0;
    virtual void swap() = 0;

    Qul::PlatformInterface::DrawingDevice drawingDevice;

    unsigned int lastSwapFrame;
    unsigned int targetFrame;
};

除了虚析构函数和updateProperties方法外,还有获取下一绘制缓冲区和在一帧渲染完成后交换项层缓冲区的虚拟方法。还有变量以支持动态刷新间隔并跟踪项层更新所针对的帧。

使用虚析构函数,可以实施释放方法,通过向下转换为适当的平台类并调用delete实现。

void ExampleLayerEngine::deallocateItemLayer(PlatformInterface::LayerEngine::ItemLayer *layer)
{
    delete static_cast<ExampleItemLayerBase *>(layer);
}

void ExampleLayerEngine::deallocateImageLayer(PlatformInterface::LayerEngine::ImageLayer *layer)
{
    delete static_cast<ExampleImageLayerBase *>(layer);
}

void ExampleLayerEngine::deallocateSpriteLayer(PlatformInterface::LayerEngine::SpriteLayer *layer)
{
    delete static_cast<ExampleSpriteLayer *>(layer);
}

更新层属性的方法也以类似的方式实现,将消息转发到适当的子类。

void ExampleLayerEngine::updateItemLayer(PlatformInterface::LayerEngine::ItemLayer *layer,
                                         const ItemLayerProperties &props)
{
    static_cast<ExampleItemLayerBase *>(layer)->updateProperties(props);
}

void ExampleLayerEngine::updateImageLayer(PlatformInterface::LayerEngine::ImageLayer *layer,
                                          const ImageLayerProperties &props)
{
    static_cast<ExampleImageLayerBase *>(layer)->updateProperties(props);
}

void ExampleLayerEngine::updateSpriteLayer(PlatformInterface::LayerEngine::SpriteLayer *layer,
                                           const SpriteLayerProperties &props)
{
    static_cast<ExampleSpriteLayer *>(layer)->updateProperties(props);
}

硬件层基类

ExampleHardwareLayer类是ExampleItemLayerExampleImageLayerExampleSpriteLayer类的基类。它演示了如何初始化和更新根(非精灵)硬件层。

使用虚拟硬件加速API,构造函数可能如下所示

struct ExampleHardwareLayer
{
    Qul::PlatformInterface::LayerEngine::LayerPropertiesBase props;
    Qul::PlatformInterface::Size size;
    // hw_layer_t hwLayer;

    enum Type { SpriteLayer, FramebufferLayer };

    ExampleHardwareLayer(const Qul::PlatformInterface::LayerEngine::LayerPropertiesBase &p,
                         const Qul::PlatformInterface::Size &s,
                         HwPixelFormat pixelFormat,
                         Type type)
        : props(p)
        , size(s)
    {
        // hw_layer_create_data_t layerCreateData;
        // layerCreateData.opacity = p.opacity;
        // layerCreateData.x = p.position.x();
        // layerCreateData.y = p.position.y();
        // layerCreateData.z = p.z;
        // layerCreateData.width = size.width();
        // layerCreateData.height = size.height();
        // layerCreateData.pixelFormat = pixelFormat;
        // layerCreateData.type = type == SpriteLayer ? HW_LAYER_TYPE_SPRITE : HW_LAYER_TYPE_FRAMEBUFFER;

        // HW_LayerCreate(&hwLayer, &layerData);
    }

它设置了硬件层的所有属性,并调用了硬件层API函数以创建硬件层。

然后,updateProperties()根据所有不同层类型共有的基本属性(如大小、位置、不透明度和启用状态)更新硬件层。

void updateProperties(const Qul::PlatformInterface::LayerEngine::LayerPropertiesBase &p,
                      const Qul::PlatformInterface::Size &s)
{
    if (size != s) {
        // HW_LayerResize(&hwLayer, p.size.width(), p.size.height());
    }

    if (props.position != p.position || props.z != p.z) {
        // HW_LayerMove(&hwLayer, p.position.x(), p.position.y(), p.z);
    }

    if (props.opacity != p.opacity) {
        // HW_LayerSetOpacity(&hwLayer, p.opacity);
    }

    if (p.enabled != props.enabled) {
        if (p.enabled) {
            // HW_LayerEnable(&hwLayer);
        } else {
            // HW_LayerDisable(&hwLayer);
        }
    }

    size = s;
    props = p;
}

析构函数删除硬件层资源

~ExampleHardwareLayer()
{
    // HW_LayerDelete(&hwLayer);
}

项层类

首先,ExampleItemLayer类为指定的硬件层分配和销毁帧缓冲区

struct ExampleItemLayer : public ExampleItemLayerBase, public ExampleHardwareLayer
{
    ExampleItemLayer(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &props)
        : ExampleItemLayerBase(props)
        , ExampleHardwareLayer(props,
                               props.size,
                               toHwPixelFormat(props.colorDepth),
                               ExampleHardwareLayer::FramebufferLayer)
    {
        // Allocate double buffers for hardware framebuffer layer
        // HW_CreateFramebuffers(&hwLayer, props.size.width(), props.size.height(), toHwPixelFormat(props.colorFormat), 2);
    }

    ~ExampleItemLayer()
    {
        // HW_DestroyFramebuffers(&hwLayer, props.size.width(), props.size.height(), toHwPixelFormat(props.colorFormat), 2);
    }

updateProperties方法转发到ExampleHardwareLayer基类的实现

virtual void updateProperties(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &props) QUL_DECL_OVERRIDE
{
    ExampleHardwareLayer::updateProperties(props, props.size);
}

getNextDrawBuffer等待后缓冲区准备就绪后返回其地址,而swap调用硬件层方法以交换前后缓冲区

virtual unsigned char *getNextDrawBuffer() QUL_DECL_OVERRIDE
{
    unsigned char *bits = NULL;
    do {
        // bits = HW_GetNextFramebuffer(&hwLayer);
    } while (!bits);
    return bits;
}

virtual void swap() QUL_DECL_OVERRIDE
{
    // HW_FinishRendering();
    // HW_SwapFramebuffers(&hwLayer);
}

假设精灵数据的地址可以是任何有效的指针,在示例平台中,ExampleItemSprite类手动分配和释放两个帧缓冲区

struct ExampleItemSprite : public ExampleItemLayerBase
{
    ExampleItemSprite(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &p, ExampleSpriteLayer *spriteLayer)
        : ExampleItemLayerBase(props)
        , props(p)
        , spriteLayer(spriteLayer)
        , didCreate(false)
        , frontBufferIndex(0)
    {
        // For item sprites we manually allocate the framebuffers
        for (int i = 0; i < 2; ++i)
            framebuffers[i] = (unsigned char *) qul_malloc(p.size.width() * p.size.height()
                                                           * bytesPerPixel(p.colorDepth));
    }

    ~ExampleItemSprite()
    {
        for (int i = 0; i < 2; ++i)
            qul_free(framebuffers[i]);

        if (didCreate) {
            // HW_SpriteDelete(&hwSprite);
        }
    }

需要更新的精灵相关属性包括位置和精灵是否启用。

virtual void updateProperties(const Qul::PlatformInterface::LayerEngine::ItemLayerProperties &p) QUL_DECL_OVERRIDE
{
    if (!didCreate)
        return;

    if (props.position != p.position || props.z != p.z) {
        // HW_SpriteMove(&hwSprite, p.position.x(), p.position.y(), p.z);
    }

    if (props.enabled != p.enabled) {
        if (p.enabled) {
            // HW_SpriteEnable(&hwSprite);
        } else {
            // HW_SpriteDisable(&hwSprite);
        }
    }

    props = p;
}

函数getNextDrawBuffer返回后缓冲区指针,而覆盖的swap函数会更新精灵数据,或者在尚未创建的情况下创建精灵。

virtual unsigned char *getNextDrawBuffer() QUL_DECL_OVERRIDE { return framebuffers[!frontBufferIndex]; }

virtual void swap() QUL_DECL_OVERRIDE
{
    // HW_FinishRendering();

    frontBufferIndex = !frontBufferIndex;

    if (didCreate) {
        // HW_SpriteSetData(&hwSprite, framebuffers[frontBufferIndex]);
    } else {
        create();
        didCreate = true;
    }
}

硬件精灵的创建可能如下所示:

void create()
{
    // hw_sprite_create_data_t spriteCreateData;
    // spriteCreateData.x = props.position.x();
    // spriteCreateData.y = props.position.y();
    // spriteCreateData.z = props.z;
    // spriteCreateData.width = props.size.width();
    // spriteCreateData.height = props.size.height();
    // spriteCreateData.pixelFormat = toHwPixelFormat(props.colorDepth);
    // spriteCreateData.data = framebuffers[frontBufferIndex];
    // spriteCreateData.layer = &spriteLayer->hwLayer;
    // HW_SpriteCreate(&hwSprite, &spriteLayer->hwLayer);
}

图像层类

ExampleImageLayer类依赖于基类ExampleHardwareLayer进行创建和属性更新,并且直接将纹理数据设置为帧缓冲区。

struct ExampleImageLayer : public ExampleImageLayerBase, public ExampleHardwareLayer
{
    ExampleImageLayer(const Qul::PlatformInterface::LayerEngine::ImageLayerProperties &p)
        : ExampleHardwareLayer(p,
                               p.texture.size(),
                               toHwPixelFormat(p.texture.format()),
                               ExampleHardwareLayer::FramebufferLayer)
    {
        // HW_LayerSetFramebuffer(&hwLayer, p.texture.data(), p.texture.bytesPerLine());
    }

    void updateProperties(const Qul::PlatformInterface::LayerEngine::ImageLayerProperties &p) QUL_DECL_OVERRIDE
    {
        ExampleHardwareLayer::updateProperties(p, p.texture.size());
        // HW_LayerSetFramebuffer(&hwLayer, p.texture.data(), p.texture.bytesPerLine());
    }

Qt Quick Ultralite核心将确保纹理数据在图像层可见的情况下保持有效。

对于ExampleImageSprite,硬件精灵可以在构造函数中立即创建,并在析构函数中销毁。

struct ExampleImageSprite : public ExampleImageLayerBase
{
    ExampleImageSprite(const Qul::PlatformInterface::LayerEngine::ImageLayerProperties &p,
                       ExampleSpriteLayer *spriteLayer)
        : props(p)
    {
        // hw_sprite_create_data_t spriteCreateData;
        // spriteCreateData.x = p.position.x();
        // spriteCreateData.y = p.position.y();
        // spriteCreateData.z = p.z;
        // spriteCreateData.width = p.size.width();
        // spriteCreateData.height = p.size.height();
        // spriteCreateData.pixelFormat = toHwPixelFormat(p.texture.format());
        // spriteCreateData.data = p.texture.data();
        // spriteCreateData.layer = &spriteLayer->hwLayer;

        // HW_SpriteCreate(&hwSprite, &spriteLayer->hwLayer);
    }

    ~ExampleImageSprite()
    {
        // HW_SpriteDelete(&hwSprite);
    }

覆盖的updateProperties函数与项目精灵的类似,不同之处在于纹理数据也可能发生变化。

void updateProperties(const Qul::PlatformInterface::LayerEngine::ImageLayerProperties &p) QUL_DECL_OVERRIDE
{
    if (props.texture.data() != p.texture.data()) {
        // HW_SpriteSetData(&hwSprite, p.texture.data());
    }

    if (props.position != p.position || props.z != p.z) {
        // HW_SpriteMove(&hwSprite, p.position.x(), p.position.y(), p.z);
    }

    if (props.enabled != p.enabled) {
        if (p.enabled) {
            // HW_SpriteEnable(&hwSprite);
        } else {
            // HW_SpriteDisable(&hwSprite);
        }
    }

    props = p;
}

精灵层类

精灵层是项和图像精灵的简单容器。ExampleSpriteLayer类不需要处理任何特定的事务,因为位置、不透明度和大小属性由基类ExampleHardwareLayer处理。

struct ExampleSpriteLayer : public Qul::PlatformInterface::LayerEngine::SpriteLayer, public ExampleHardwareLayer
{
    ExampleSpriteLayer(const Qul::PlatformInterface::LayerEngine::SpriteLayerProperties &props)
        : ExampleHardwareLayer(props, props.size, toHwPixelFormat(props.colorDepth), ExampleHardwareLayer::SpriteLayer)
    {}

    void updateProperties(const Qul::PlatformInterface::LayerEngine::SpriteLayerProperties &props)
    {
        ExampleHardwareLayer::updateProperties(props, props.size);
    }

    static void *operator new(std::size_t size) { return qul_malloc(size); }
    static void operator delete(void *ptr) { qul_free(ptr); }
};

平台beginFrameendFramepresentFrame API

当启用层支持时,PlatformContext::beginFrame方法将转交给ExampleLayerEngine::beginFrame,其实现如下:

PlatformInterface::DrawingDevice *ExampleLayerEngine::beginFrame(const PlatformInterface::LayerEngine::ItemLayer *layer,
                                                                 const PlatformInterface::Rect &,
                                                                 int refreshInterval)
{
    ExampleItemLayerBase *itemLayer = const_cast<ExampleItemLayerBase *>(
        static_cast<const ExampleItemLayerBase *>(layer));

    if (itemLayer->lastSwapFrame == currentFrame) {
        // waitForVblank();
    }

    if (refreshInterval == -1)
        itemLayer->targetFrame = currentFrame + 1;
    else
        itemLayer->targetFrame = itemLayer->lastSwapFrame + refreshInterval;

    unsigned char *bits = itemLayer->getNextDrawBuffer();
    // Tell the HW drawing API which framebuffer to render to
    // HW_FramebufferSet(bits, drawingDevice.width(), drawingDevice.height(), toHwPixelFormat(drawingDevice.format()));

    // The drawing device also needs the framebuffer pointer for the CPU rendering fallbacks to work
    itemLayer->drawingDevice.setBits(bits);

    return &itemLayer->drawingDevice;
}

beginFrame方法确保后缓冲区准备好渲染。它检查自上次缓冲区交换以来是否发生了垂直刷新,并根据刷新间隔设置下一次交换的目标帧。它还获取准备就绪的后缓冲区指针,并让硬件API和Qul::PlatformInterface::DrawingDevice在该地址上进行渲染。

接下来,PlatformContext::endFrame方法将转交给ExampleLayerEngine::endFrame,其实现如下:

bool waitingForTargetFrame(ExampleItemLayerBase *layer)
{
    const unsigned int delta = layer->targetFrame - currentFrame;

    // guard against wrap-around (swap intervals above 0x100 are unlikely)
    return delta != 0 && delta < 0x100;
}

void ExampleLayerEngine::endFrame(const PlatformInterface::LayerEngine::ItemLayer *layer)
{
    ExampleItemLayerBase *itemLayer = const_cast<ExampleItemLayerBase *>(
        static_cast<const ExampleItemLayerBase *>(layer));
    while (waitingForTargetFrame(itemLayer))
        ;
    itemLayer->swap();
    itemLayer->lastSwapFrame = currentFrame;
}

它在调用swap方法交换项层的前后缓冲区之前,会等待目标帧的层更新完成。

最后,PlatformContext::presentFrame方法将转交给ExampleLayerEngine::presentFrame,如下所示:

FrameStatistics ExampleLayerEngine::presentFrame(const PlatformInterface::Screen *screen,
                                                 const PlatformInterface::Rect &rect)
{
    static unsigned int lastFrame = 0xffffffff;
    while (currentFrame == lastFrame) {
        // The device may yield or go into sleep mode
    }
    lastFrame = currentFrame;

    PlatformInterface::Rgba32 color = screen->backgroundColor();
    // HW_SetScreenBackgroundColor(color.red(), color.blue(), color.green());

    // No frame skip compensation implemented for layers
    return FrameStatistics();
}

它确保即使在没有任何项层正在渲染的情况下,更新也被限制在屏幕的更新率上。此外,它使用硬件API设置屏幕的背景颜色。

要计算在多个层正在动画时的帧统计信息,将返回默认构造的Qul::Platform::FrameStatistics对象以在Qt Quick Ultralite核心中禁用帧跳过补偿。

适用于某些Qt许可证。
了解详情。