鸿蒙南向开发实战:如何对接图形框架?

201 篇文章 1 订阅
126 篇文章 0 订阅

当前,小型系统图形模块以子系统的形式在 OpenHarmony 中运行。开发者只需适配实现OpenHarmony HDF 层 API 即可。

由于使用场景不同,图形子系统也支持在不同平台集成运行。例如,在 Windows/Mac 上开发应用程序时,可以使用 QT Creator 进行简单的页面布局、开发和调试。

此时,图形子系统已经适配到了 Windows/Mac 平台上运行。如果想要将图形子系统独立集成到现有项目中,则需要进行一些简单的适配工作,并分为以下几个主要部分:

  1. 引擎初始化
  2. 显示设备适配
  3. 输入设备适配
  4. 字体初始化
  5. 屏幕刷新对接

具体步骤如下,步骤最后有参考示例代码

图形引擎初始化

主要包括初始化 UI 任务、渲染模块、动画模块、默认样式等

// graphic_startup.h
GraphicStartUp::Init();

显示设备适配

主要包括设置屏幕大小,对接基础图元绘制,获取图形绘制的 buffer,把图形绘制的数据刷到屏幕上显示等。

显示层适配根据硬件绘制和软件绘制不同,需继承实现不同的类。其中 gfx_engine_manager.h 中的 BaseGfxEngine 类为纯虚实现,只定义了接口,不含任何实现,适合作为自行实现的硬件绘制的父类;soft_engine.h 中的 SoftEngine 继承自 BaseGfxEngine,对 BaseGfxEngine 的接口进行了软件层实现,适合作为软件绘制的父类。

BaseGfxEngine 类中有3类接口:

第一类:获取显存、申请缓存、释放缓存;

第二类:绘制类基础接口,例如:画线、Blit、Fill 等;

第三类:送显接口,调用该接口完成把绘制内容送显。

其中获取显存和送显接口为移植不同平台必须实现的,第二类接口,图形 UI 框架有默认软件实现,具体在 soft_engine.h 的 SoftEngine 中,软件绘制可继承 SoftEngine 进行功能拓展;不同平台如有硬件加速,例如 DMA2D,可继承 gfx_engine_manager.h 的 BaseGfxEngine,对其纯虚方法进行全部实现后,进行扩展性适配。

图形对接接口代码如下:

// gfx_engine_manager.h
virtual void DrawArc(BufferInfo& dst,
                        ArcInfo& arcInfo,
                        const Rect& mask,
                        const Style& style,
                        OpacityType opacity,
                        uint8_t cap) = 0;

virtual void DrawLine(BufferInfo& dst,
                        const Point& start,
                        const Point& end,
                        const Rect& mask,
                        int16_t width,
                        ColorType color,
                        OpacityType opacity) = 0;

virtual void DrawLetter(BufferInfo& gfxDstBuffer,
                        const uint8_t* fontMap,
                        const Rect& fontRect,
                        const Rect& subRect,
                        const uint8_t fontWeight,
                        const ColorType& color,
                        const OpacityType opa) = 0;

virtual void DrawCubicBezier(BufferInfo& dst,
                                const Point& start,
                                const Point& control1,
                                const Point& control2,
                                const Point& end,
                                const Rect& mask,
                                int16_t width,
                                ColorType color,
                                OpacityType opacity) = 0;

virtual void
    DrawRect(BufferInfo& dst, const Rect& rect, const Rect& dirtyRect, const Style& style, OpacityType opacity) = 0;

virtual void DrawTransform(BufferInfo& dst,
                            const Rect& mask,
                            const Point& position,
                            ColorType color,
                            OpacityType opacity,
                            const TransformMap& transMap,
                            const TransformDataInfo& dataInfo) = 0;

// x/y: center of a circle
virtual void ClipCircle(const ImageInfo* info, float x, float y, float radius) = 0;

virtual void Blit(BufferInfo& dst,
                    const Point& dstPos,
                    const BufferInfo& src,
                    const Rect& subRect,
                    const BlendOption& blendOption) = 0;

virtual void Fill(BufferInfo& dst, const Rect& fillArea, const ColorType color, const OpacityType opacity) = 0;

virtual void DrawPath(BufferInfo& dst,
                        void* param,
                        const Paint& paint,
                        const Rect& rect,
                        const Rect& invalidatedArea,
                        const Style& style) = 0;

virtual void FillPath(BufferInfo& dst,
                        void* param,
                        const Paint& paint,
                        const Rect& rect,
                        const Rect& invalidatedArea,
                        const Style& style) = 0;

virtual uint8_t* AllocBuffer(uint32_t size, uint32_t usage) = 0;

virtual void FreeBuffer(uint8_t* buffer, uint32_t usage) = 0;

virtual BufferInfo* GetFBBufferInfo()
{
    return nullptr;
}

virtual void AdjustLineStride(BufferInfo& info) {}

virtual void Flush(const Rect& flushRect) {}

virtual uint16_t GetScreenWidth()
{
    return screenWidth_;
}

virtual uint16_t GetScreenHeight()
{
    return screenHeight_;
}

virtual void SetScreenShape(ScreenShape screenShape)
{
    screenShape_ = screenShape;
}

virtual ScreenShape GetScreenShape()
{
    return screenShape_;
}

输入设备适配

图形框架支持触摸、按键和旋转设备。当前所有输入设备都需要继承 InputDevice 实现 Read 接口。

触摸输入继承 PointerInputDevice 类实现 Read 接口,需要返回 x/y 坐标和按压状态;

按键输入继承 KeyInputDevice 类实现 Read 接口,需要设置 keyId 和按键状态;

旋转输入继承 RotateInputDevice 类实现 Read 接口,需要设置 rotate 值。

InputDevice 设备对接实例代码如下:

// input_device.h Read 接口
/**
 * @brief Read data from hardware.User should override this to set data *
 * @param [out] input device data. *
 * @returns no more data to read if true.
 */
virtual bool Read(DeviceData& data) = 0;

// 继承实现 InputDevice 基类的 Read 接口,以触摸事件对接为例,示例代码如下:
class TouchInput : public OHOS::PointerInputDevice {
public:
    TouchInput() {}
    virtual TouchInput() {}
    // implements read fouction
    bool Read(OHOS::DeviceData& data) override
    {
        // set position and state, you should update the value when touch
        data.point.x = g_lastX;
        data.point.y = g_lastY;
        data.state = g_leftButtonDown ? STATE_PRESS : STATE_RELEASE;
        return false;
    }
};

字体初始化

字体分为点阵字体和矢量字体。

点阵字体:需要使用字体打包工具生成对应字体 font.bin 文件,工具支持打包中英文字体,详细支持字号和 fontId 可以在工具生成的 ui_text_language.h 中查看。

矢量字体:默认注册了 DEFAULT_VECTOR_FONT_FILENAME,假如想使用其他字体,可以调用 RegisterFontInfo 注册其他字体文件。矢量字体解析和布局需要依赖三方开源软件 freetype 和 icu,假如想支持阿拉伯语等复杂语言需要依赖三软件 harfbuzz,同时打开 ENABLE_SHAPING 和 ENABLE_ICU。

字体初始化接口代码如下:

// graphic_config.h
#define DEFAULT_VECTOR_FONT_FILENAME      "SourceHanSansSC-Regular.otf"
// 矢量字体开关
#define ENABLE_VECTOR_FONT                1
// 点阵字体开关
#define ENABLE_BITMAP_FONT                0
#define ENABLE_ICU                        0
#define ENABLE_SHAPING                    0

// ui_font.h
uint8_t RegisterFontInfo(const char* ttfName, uint8_t shaping = 0)

// graphic_startup.h
static void InitFontEngine(uintptr_t psramAddr, uint32_t psramLen, const char* dPath, const char* ttfName);

屏幕刷新对接

根据屏幕硬件刷新信号(类似 Vsync 信号),周期性回调 TaskHandler

屏幕刷新对接接口代码如下:

TaskManager::GetInstance()->TaskHandler();

图形适配示例代码

对接相关宏定义说明如下:

// graphic_config.h
// 默认定义了不同级别设备宏定义,轻设备请启动 VERSION_LITE 宏
/**
 * Defines three graphics library versions: lightweight, standard, and extended versions.
 * The three versions have different requirements on the memory and hardware.
 * The standard version is enabled by default.
 *
 * The macros of the versions are defined as follows:
 * Name                | Version Description
 * ------------------- | ----------
 * VERSION_LITE        | Lightweight version
 * VERSION_STANDARD    | Standard version
 * VERSION_EXTENDED    | Extended version
 */
#ifdef _LITEOS
#define VERSION_LITE
#elif defined _WIN32 || defined __APPLE__
#define VERSION_LITE
#else
#define VERSION_STANDARD
#endif

// 关闭窗口合成,打开需要依赖 wms 窗口合成服务
/**
 * @brief Multi-window, which is disabled by default on WIN32.
 */
#define ENABLE_WINDOW                     0

// 关闭 png、jpeg 格式图片支持,打开需要引入三方库
#define ENABLE_JPEG_AND_PNG               0

// 硬件加速,关闭默认走CPU软绘制,可以先关闭,界面显示后再打开适配硬件能力
/**
 * @brief Graphics rendering hardware acceleration, which is disabled by default on WIN32.
 */
#define ENABLE_HARDWARE_ACCELERATION     0

对接示例代码如下:

using namespace OHOS;

int main(int argc, char** argv)
{
    // init graphic
    GraphicStartUp::Init();

    // init display/input device
    InitHal();

    // init font engine
    InitFontEngine();

    // run your app code
    RunApp();

    // use while loop to simulate hardware flush callback
    // you should call *TaskHandler* in screen flush signal callback(like Vsync).
    while (1) {
        TaskManager::GetInstance()->TaskHandler();
        Sleep(DEFAULT_TASK_PERIOD);
    }
    return 0;
}

// assuming below are the memory pool
static uint8_t g_fontPsramBaseAddr[MIN_FONT_PSRAM_LENGTH];
#if ENABLE_SHAPING
static uint8_t g_shapePsramBaseAddr[MIN_SHAPING_PSRAM_LENGTH];
#else
static uint8_t* g_shapePsramBaseAddr = nullptr;
#endif

static void InitFontEngine()

{
#if ENABLE_VECTOR_FONT
    GraphicStartUp::InitFontEngine(reinterpret_cast<uintptr_t>(g_fontMemBaseAddr), MIN_FONT_PSRAM_LENGTH, VECTOR_FONT_DIR, DEFAULT_VECTOR_FONT_FILENAME);
#else
    BitmapFontInit();
    std::string dPath(_pgmptr);
    size_t len = dPath.size();
    size_t pos = dPath.find_last_of('\\');
    dPath.replace((pos + 1), (len - pos), "..\\..\\simulator\\font\\font.bin");
    GraphicStartUp::InitFontEngine(reinterpret_cast<uintptr_t>(g_fontMemBaseAddr), MIN_FONT_PSRAM_LENGTH, dPath.c_str(), nullptr);
#endif

#if ENABLE_ICU
    GraphicStartUp::InitLineBreakEngine(reinterpret_cast<uintptr_t>(g_icuMemBaseAddr), SHAPING_WORD_DICT_LENGTH,
 VECTOR_FONT_DIR, DEFAULT_LINE_BREAK_RULE_FILENAME);
#endif
}

// display adaptor
class SDLMonitorGfxEngine : public BaseGfxEngine {
public:
    BufferInfo* GetFBBufferInfo() override
    {
        static BufferInfo* bufferInfo = nullptr;
        if (bufferInfo == nullptr) {
            bufferInfo = new BufferInfo;
            bufferInfo->rect = {0, 0, HORIZONTAL_RESOLUTION - 1, VERTICAL_RESOLUTION - 1};
            bufferInfo->mode = ARGB8888;
            bufferInfo->color = 0x44;
            bufferInfo->virAddr = GetFramBuff();
            bufferInfo->phyAddr = bufferInfo->virAddr;
            // 4: bpp
            bufferInfo->stride = HORIZONTAL_RESOLUTION * 4;
            bufferInfo->width = HORIZONTAL_RESOLUTION;
            bufferInfo->height = VERTICAL_RESOLUTION;
        }

        return bufferInfo;
    }

    void Flush() override
    {
        MonitorRenderFinish();
    }
};

class TouchInput : public OHOS::PointerInputDevice {
public:
    TouchInput() {}
    virtual TouchInput() {}

    // implements read function
    bool Read(OHOS::DeviceData& data) override
    {
        // set position x,y and state, you should update the
        // g_lastX/g_lastY/g_leftButtonDown when touch
        data.point.x = g_lastX;
        data.point.y = g_lastY;
        data.state = g_leftButtonDown ? STATE_PRESS : STATE_RELEASE;

        return false;
    }
};

class KeyInput : public OHOS::KeyInputDevice {
public:
    KeyInput();
    virtual ~KeyInput() {}

    // implements read fouction
    bool Read(OHOS::DeviceData& data) override
    {
        data.keyId = g_lastKeyId;
        data.state = g_lastState;
        g_lastState = INVALID_KEY_STATE;
        return false;
    }
};

// other device if you need to add
class XXInput : public OHOS::XXInputDevice {
public:
    KeyInput();
    virtual ~KeyInput() {}

    // implements read fouction
    bool Read(OHOS::DeviceData& data) override
    {
        // set device data info
    }
};

static void InitHal()
{
    // Setup gfxengine
    BaseGfxEngine::GetInstance()->InitEngine(new SDLMonitorGfxEngine());

    // Setup touch device
    TouchInput* touch = new TouchInput();
    InputDeviceManager::GetInstance()->Add(touch);

    // Setup key device if you need
    KeyInput* key = new KeyInput();
    InputDeviceManager::GetInstance()->Add(key);

    // Setup xx device if you need
    XXInput* inputXX = new XXInput();
    InputDeviceManager::GetInstance()->Add(inputXX);
}

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料

 获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

 有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值