天天看點

#DAYU200體驗官#在開發闆上,使用OpenGL相關API繪制基本圖形流程

DAYU200是一款支援OpenHarmony的富裝置,其硬體支援GPU,OpenHarmony的圖形架構也使能了GPU相關功能。DAYU200的GPU型号為Mali-G52,支援OpenGL ES 1.1/2.0/3.2,OpenCL 2.0,Vulkan 1.1。本文分享在DAYU200上,以OpenHarmony為平台,如何搭建OpenGL開發環境,及用最簡單的OpenGL API(C/C++語言)繪制基本圖形 —— 三角形。

本文能夠在OpenHarmony上采用OpenGL的API實作繪制基本圖形,參考了相關開源項目或文章,在此對相關作者表示感謝。

一、OpenHarmony圖形棧

OpenHarmony 圖形棧如下圖所示。OpenHarmony接口層,提供圖形的 Native API能力,包括:WebGL、Native Drawing的繪制能力、OpenGL指令級的繪制能力支撐等。

OpenHarmony應用開發是主要基于JS API,平時大家開發應用,基本用不到C/C++的方式。了解如何使用OpenHarmony的Native Drawing的繪制能力及OpenGL指令來繪制一些簡單圖形,對加深OpenHarmony圖形棧的認識頗有意義。

#DAYU200體驗官#在開發闆上,使用OpenGL相關API繪制基本圖形流程

二、開發環境搭建

如果使用OpenGL API直接繪制基本圖形,需要依賴OpenHarmony的接口層的相關API,如何友善使用,主要參考Gitee項目(https://gitee.com/honglianglin/glmark2_2)。
           

1、NativeWindow

将native_window_wrapper源碼及BUILD.gn,加入到OpenHarmony編譯後,生成libnative_window_wrapper.z.so庫,OpenGL應用程式,會調用該動态庫進行視窗的建立等。

#DAYU200體驗官#在開發闆上,使用OpenGL相關API繪制基本圖形流程

庫編譯好後,可以使用hdc_std指令,推送到開發闆端,參考指令如下:

hdc_std shell mount -o remount,rw /
hdc_std file send libnative_window_wrapper.z.so /system/lib
           

相關源碼見附件(native_window_wrapper.zip),其中native_window_wrapper.h頭檔案内容如下:

#ifndef NATIVE_WINDOW_WRAPPER
#define NATIVE_WINDOW_WRAPPER
#include <cstdint>

extern "C" {
    typedef struct {
        void* (*CreateWindowWrapper)();
        bool (*CreateWindow)(void* wrapper, uint32_t w, uint32_t h);
        void* (*GetNativeWindow)(void* wrapper);
        void (*SetVisibility)(void* wrapper, bool visible);
        void (*DestroyWindowWrapper)(void* wrapper);
    } WrapperFunc;
    bool GetWrapperFunc(WrapperFunc* funcs);    
}

#endif // NATIVE_WINDOW_WRAPPER
           

2、應用開發

為了便于直接開發使用OpenGL API的程式,環境基于glmark2,删除了其中benchmark相關代碼,精簡為一個基于Make建構的工程(工程源碼見附件:native_window_ohos.zip),便于在OpenHarmony平台,應用開發快速驗證OpenGL相關API,目錄結構如下,開發時執行make即可編譯。

.

├── include

│   └── native_window_wrapper.h

├── main.cpp

├── Makefile

└── src

├── canvas-generic.cpp

├── canvas-generic.h

├── canvas.h

├── glad

├── gl-headers.cpp

├── gl-headers.h

├── gl-state-egl.cpp

├── gl-state-egl.h

├── gl-state.h

├── gl-visual-config.cpp

├── gl-visual-config.h

├── include

├── libmatrix

├── native-state.h

├── native-state-ohos.cpp

├── native-state-ohos.h

├── ohos_wrapper_linker.cpp

├── ohos_wrapper_linker.h

├── options.cpp

├── options.h

├── shared-library.cpp

└── shared-library.h

Makefile核心内容:

OHOS_ROOT = /home/algoideas/openharmony/master
CC = $(OHOS_ROOT)/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang --sysroot=$(OHOS_ROOT)/out/a311d/obj/third_party/musl
CXX = $(OHOS_ROOT)/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang++ --sysroot=$(OHOS_ROOT)/out/a311d/obj/third_party/musl
AR = $(OHOS_ROOT)/prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-ar
LD = $(OHOS_ROOT)/prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-link
ARFLAG = -rcs

TARGET = native_main
PROJECT_PATH = $(shell pwd)

CFLAGS := -march=armv7-a \
	-mfloat-abi=softfp \
	-mtune=generic-armv7-a \
	-mfpu=neon \
	-mthumb \
	--target=arm-linux-ohosmusl \
	--sysroot=$(OHOS_ROOT)/out/rk3568/obj/third_party/musl

# Warning
CFLAGS += -Wno-c++11-narrowing

# Lib
CLIBS = -lm -ldl -lrt
CLIBS += -L$(OHOS_ROOT)/device/soc/rockchip/hardware/gpu/lib -lmali-bifrost-g52-g2p0-ohos
CLIBS += -L$(OHOS_ROOT)/out/rk3568/packages/phone/system/lib -lhilog -lsurface.z -lutils.z

CFLAGS += -DOHOS_USE_DRM -DOHOS_USE_GLESv2 -DOHOS_USE_EGL
INCLUDE_DIRS += \
    -I$(OHOS_ROOT)/third_party/EGL/api \
    -I$(OHOS_ROOT)/third_party/openGLES/api \
    -I$(OHOS_ROOT)/utils/native/base/include \
    -I$(OHOS_ROOT)/drivers/peripheral/base \
    -I$(OHOS_ROOT)/foundation/graphic/standard/interfaces/innerkits/common \
    -I$(OHOS_ROOT)/foundation/graphic/standard/interfaces/innerkits/surface \
    -I$(OHOS_ROOT)/foundation/graphic/standard/utils/buffer_handle/export \
    -I$(OHOS_ROOT)/foundation/communication/ipc/interfaces/innerkits/ipc_core/include \
    -I$(OHOS_ROOT)/foundation/aafwk/standard/frameworks/kits/ability/ability_runtime/include \
    -I$(OHOS_ROOT)/foundation/aafwk/standard/interfaces/innerkits/ability_manager/include  \
    -I$(OHOS_ROOT)/foundation/aafwk/standard/interfaces/innerkits/app_manager/include/appmgr  \
    -I$(OHOS_ROOT)/third_party/jsoncpp/include  \
    -I$(OHOS_ROOT)/third_party/json/include  \
    -I$(OHOS_ROOT)/foundation/windowmanager/interfaces/innerkits/wm \
    -I$(OHOS_ROOT)/foundation/graphic/standard/frameworks/surface \
    -I$(OHOS_ROOT)/foundation/graphic/standard/rosen/modules/render_service_base/include \
    -I$(OHOS_ROOT)/foundation/graphic/standard/rosen/modules/render_service_client/core \
    -I$(OHOS_ROOT)/foundation/graphic/standard/rosen/modules/render_service_client \
    -I$(OHOS_ROOT)/third_party/flutter/skia \
    -I$(OHOS_ROOT)/third_party/flutter/skia/include/core \
    -I$(OHOS_ROOT) \
    -I$(OHOS_ROOT)/third_party/skia

INCLUDE_DIRS += -I$(PROJECT_PATH)/include \
    -I$(PROJECT_PATH)/src/glad/include \
    -I$(PROJECT_PATH)/src/libmatrix \
    -I$(PROJECT_PATH)/src 

export CC CXX CFLAGS AR LD ARFLAG MODULE_SELECT

CPP_SOURCES = $(wildcard ./src/*.cpp)
CPP_OBJECTS = $(patsubst %.cpp,%.o,$(CPP_SOURCES))
           

三、繪制基本圖形

采用OpenGL API,繪制基本圖形 - 三角形的源碼如下,繪制流程部分參考知乎。

#include "gl-headers.h"
#include "options.h"
#include "log.h"
#include "util.h"

#include "canvas-generic.h"
#include "native-state-ohos.h"
#include "gl-state-egl.h"

using std::vector;
using std::string;

int main(int argc, char *argv[])
{
    if (!Options::parse_args(argc, argv))
        return 1;

    /* Initialize Log class */
    Log::init(Util::appname_from_path(argv[0]), Options::show_debug);

    if (Options::show_help) {
        Options::print_help();
        return 0;
    }

    /* Force 320x240 output for validation */
    if (Options::validate &&
        Options::size != std::pair<int,int>(320, 240))
    {
        Log::info("Ignoring custom size %dx%d for validation. Using 800x600.\n",
                  Options::size.first, Options::size.second);
        Options::size = std::pair<int,int>(320, 240);
    }

    // Create the canvas
    NativeStateOhos native_state;

    GLStateEGL gl_state;

    CanvasGeneric canvas(native_state, gl_state, Options::size.first, Options::size.second);

    canvas.offscreen(Options::offscreen);

    canvas.visual_config(Options::visual_config);

    if (!canvas.init()) {
        Log::error("%s: Could not initialize canvas\n", __FUNCTION__);
        return 1;
    }

    Log::info("=======================================================\n");
    canvas.print_info();
    Log::info("=======================================================\n");

    canvas.visible(true);

     /**
      ** 資料處理: 生成和綁定VBO, 設定屬性指針
      **/
    // 三角形的頂點資料, 規範化(x,y,z)都要映射到[-1,1]之間
    const float triangle[] = {
        // 位置
        -0.5f, -0.5f, 0.0f,  // 左下
         0.5f, -0.5f, 0.0f,  // 右下
         0.0f,  0.5f, 0.0f   // 正上
    };

    // 生成并綁定立方體的VBO
    GLuint vertex_buffer_object; // VBO
    glGenBuffers(1, &vertex_buffer_object);
    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_object);

    // 将頂點資料綁定到目前預設的緩沖中, 好處是不用将頂點資料一個一個地發送到顯示卡上, 可以借助VBO一次性發送所有頂點資料
    // GL_STATIC_DRAW表示頂點資料不會被改變
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle), triangle, GL_STATIC_DRAW);

    // 設定頂點屬性指針
    // 第一個參數0: 頂點着色器的位置值
    // 第二個參數3: 位置屬性是一個三分量的向量
    // 第三個參數: 頂點的類型
    // 第四個參數: 是否希望資料标準化,映射到[0,1]
    // 第五個參數: 步長,表示連續頂點屬性之間的間隔,下一組的資料再3個float之後
    // 第六個參數: 資料的偏移量, 位置屬性在開頭, 是以為0, 還需要強制類型轉換
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0); // 開啟0通道

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    /**
     ** 着色器: 頂點和片段着色器
     **/
    /* 着色器源碼 -> 生成并編譯着色器 -> 連結着色器到着色器程式 -> 删除着色器 */
    const char *vertex_shader_source =
            "attribute vec4 a_Position;\n" // 位置變量屬性設定為0
            "void main()\n"
            "{\n"
            "    gl_Position = a_Position;\n"
            "}\n\0";

    /* 設定片元像素的顔色為紅色, vec4(r,g,b,a) */
    const char *fragment_shader_source =
            "void main()\n"
            "{\n"
            "    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
            "}\n\0";

    /**
     ** 生成并編譯着色器 
     **/
    /* 頂點着色器 */
    int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
    glCompileShader(vertex_shader);

    int success;
    char info_log[512];

    /* 檢查着色器是否成功編譯, 如果編譯失敗, 列印錯誤資訊 */
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
    if(!success){
        glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
        Log::error("SHADER::VERTEX::COMPILATION_FAIILED %s\n", info_log);
    }

    /* 片元着色器 */
    int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
    glCompileShader(fragment_shader);

    /* 檢查着色器是否成功編譯, 如果編譯失敗, 列印錯誤資訊 */
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
    if(!success){
        glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
        Log::error("glGetShaderiv fragment_shader fail %s\n", info_log);
    }

    /* 連結頂點和片段着色器至一個着色器程式 */
    int shader_program = glCreateProgram();
    glAttachShader(shader_program, vertex_shader);
    glAttachShader(shader_program, fragment_shader);

    glLinkProgram(shader_program);

    /* 檢查着色器是否成功連結, 如果連結失敗, 列印錯誤資訊 */
    glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
    if(!success){
        glGetProgramInfoLog(shader_program, 512, NULL, info_log);
        Log::error("glGetShaderiv shader_program fail %s\n", info_log);
    }

    /* 删除頂點和片段着色器 */
    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);

    /**
     ** 渲染
     **/
    /* 清空顔色緩沖 */
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   // 用黑色背景色來清空
    glClear(GL_COLOR_BUFFER_BIT);

    /* 使用着色器程式 */
    glUseProgram(shader_program);

    /* 繪制三角形 */
    glDrawArrays(GL_TRIANGLES, 0, 3); // 繪制三角形, 繪制三角形, 頂點起始索引值, 繪制數量

    /* 更新交換緩沖 */
    canvas.update();

    glDeleteBuffers(1, &vertex_buffer_object);

    getchar();

    return 0;
}

           

四、運作效果展示

1、運作工程編譯出來的可執行程式native_main, 日志列印如下:

#DAYU200體驗官#在開發闆上,使用OpenGL相關API繪制基本圖形流程

2、界面顯示效果如下(左上角區域 320x240):

#DAYU200體驗官#在開發闆上,使用OpenGL相關API繪制基本圖形流程

附件連結:

native_window_ohos.zip(https://ost.51cto.com/resource/2014)

native_window_wrapper.zip(https://ost.51cto.com/resource/2012)

繼續閱讀