K230 GPU 应用实战 - VGLite 绘制酷炫图形
1.概念介绍
1.1 矢量图基础
矢量图形是用点、直线或者多边形等基于数学方程的几何图元表示的图像,矢量图形与使用像素表示图像的位图不同,可以无限放大而不失真。SVG是一种典型的矢量图格式,其本身是XML文本文件,描述各种图元的位置,通过浏览器打开即可看到渲染后的效果,如果你完全不了解 K230 GPU 使用的 VGLite API,可以把他看成是一个弱化版的 SVG。
K230 GPU 支持多种二维图元
- 直线
- 二次贝塞尔曲线
- 三次贝塞尔曲线
- 圆曲线(当然也可以用三次贝塞尔曲线拟合)
注意:这些图形都是线条,GPU 不能直接绘制线条,只能绘制由这些线条围成的闭合图形。
1.2 GPU 基础
在 K230 SDK 的小核 Linux 上,主要通过调用 VGLite API 来与 GPU 交互。VGLite 内部会维护一个 GPU 的命令队列,当需要完成绘制,或者队列满时会提交到 GPU 硬件进行渲染。命令队列的长度默认为65536,可以调用 vg_lite_set_command_buffer_size
函数进行修改。
注意:VGLite API 不支持在多线程上下文中使用,如果你的应用程序使用了多线程,请确保只有一个线程会使用VGLite API。
K230 GPU 是一个 memory-to-memory 设备,本身不具备显示输出能力,如果需要显示可以与 DRM 配合使用。
2.使用 VGLite API
2.1 开发环境准备
VGLite API 主要包含两个部分,头文件和库文件,其中头文件的位置在
<K230 SDK>/src/little/buildroot-ext/package/vg_lite/inc/vg_lite.h
将 K230 SDK 完整编译后,库文件会放在
<K230 SDK>/output/k230_evb_defconfig/little/buildroot-ext/target/usr/lib/libvg_lite.so
2.2.1 make
将代码的源文件放到 src
目录下,创建一个 Makefile 并将如下内容粘贴进去,设置K230SDK
环境变量为存放 K230 SDK 的路径(或者将第一行的 /path/to/k230_sdk
改为存放K230 SDK的路径),即可使用make
命令进行构建,构建 完成后将在 Makefile 同级目录下生成可执行文件,将其拷贝到小核 linux 上运行即可,也可以使用 make install
将其拷贝到 K230 SDK,再到 K230 SDK 目录下构建镜像,再烧录到 SD 卡或 eMMC 启动。
K230SDK ?= /path/to/k230_sdk
BIN := test-vglite
CC := "$(K230SDK)/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin/riscv64-unknown-linux-gnu-gcc"
CXX := "$(K230SDK)/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin/riscv64-unknown-linux-gnu-g++"
CFLAGS += -I"$(K230SDK)/src/little/buildroot-ext/package/vg_lite/inc" -I"$(K230SDK)/output/k230_evb_defconfig/little/buildroot-ext/host/riscv64-buildroot-linux-gnu/sysroot/usr/include"
CFLAGS += -L"$(K230SDK)/output/k230_evb_defconfig/little/buildroot-ext/target/usr/lib"
CFLAGS += -lvg_lite -lvg_lite_util -ldrm
CFLAGS += -Wall -g
CXXFLAGS := $(CFLAGS)
SRCDIR := ./src
OBJDIR := ./objs
SRCS := $(wildcard $(SRCDIR)/*.c) $(wildcard $(SRCDIR)/*.cpp)
OBJS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(filter %.c, $(SRCS))) \
$(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(filter %.cpp, $(SRCS)))
DEPS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.d,$(filter %.c, $(SRCS))) \
$(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.d,$(filter %.cpp, $(SRCS)))
all: $(BIN)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(BIN): $(OBJS)
$(CXX) $(CXXFLAGS) $(OBJS) -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(CC) $(CFLAGS) -MMD -c $< -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $(OBJDIR)
$(CXX) $(CXXFLAGS) -MMD -c $< -o $@
-include $(DEPS)
clean:
rm -rf $(OBJDIR) $(BIN)
install:
cp $(BIN) "$(K230SDK)/output/k230_evb_defconfig/little/buildroot-ext/target/usr/bin"
uninstall:
rm "$(K230SDK)/output/k230_evb_defconfig/little/buildroot-ext/target/usr/bin/$(BIN)"
.PHONY: all clean install
2.2.2 CMake
将代码的源文件放到 src
目录下,创建一个 CMakeLists.txt
文件并粘贴如下内容进去,将第三行的/path/to/k230_sdk
修改为存放 K230 SDK 的目录,即可使用 cmake 构建。
cmake_minimum_required(VERSION 3.0)
project(test-vglite)
set(K230SDK /path/to/k230_sdk)
set(CMAKE_C_COMPILER "${K230SDK}/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin/riscv64-unknown-linux-gnu-gcc")
set(CMAKE_CXX_COMPILER "${K230SDK}/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin/riscv64-unknown-linux-gnu-g++")
set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "-Wall")
include_directories(
"${K230SDK}/output/k230_evb_defconfig/little/buildroot-ext/host/riscv64-buildroot-linux-gnu/sysroot/usr/include"
"${K230SDK}/src/little/buildroot-ext/package/vg_lite/inc"
)
link_directories("${K230SDK}/output/k230_evb_defconfig/little/buildroot-ext/target/usr/lib")
link_libraries(vg_lite vg_lite_util drm)
file(GLOB SOURCES "src/*.c" "src/*.cpp")
add_executable(${PROJECT_NAME} ${SOURCES})
install(TARGETS ${PROJECT_NAME} DESTINATION "${K230SDK}/output/k230_evb_defconfig/little/buildroot-ext/target/usr/bin")
2.2 显示
K230 EVB 有一个1080x1920的显示屏,在小核linux上可以用 DRM 进行显示,让 GPU 驱动加载 DRM dumb buffer 可以减少内存拷贝,实现高效渲染。GPU+DRM 的相关代码可以参考 vglite_drm
这个 demo,读者可以将 drm.c
添加到自己的程序中。
需要注意截至 K230 SDK v0.8,linux 上的 DRM 驱动仍然不能独立工作,需要依赖大核对 SoC 视频输出模块的配置,可以通过在大核上执行 sample_vo.elf 3
来完成。
其次 DRM 的颜色格式枚举与 vg_lite_buffer_format_t
并不完全一致,例如 VGLITE_BGRA8888
表示的是红色在低8位,alpha在高8位的32位颜色,对应 DRM 中的 DRM_FORMAT_ARGB8888
。
如图是 vglite_drm 运行后屏幕正确显示的颜色:R(255)G(128)B(16)
一般来说为了实现同步显示会需要两张 buffer 进行 ping-pong 交替显示,但是为了简化演示代码这里就只用了一张,读者可以自行实现垂直同步的双重缓冲区进行连续渲染。
3.绘图
3.1 一些准备
首先需要初始化 VGLite,调用 vg_lite_init
来完成,它有两个参数 tessellation_width
和 tessellation_height
,用于渲染窗口的大小,越大的话效率越高,如果为0则表示不使用矢量绘制功能,只能 BLIT,通常会设置为最大 buffer 的大小。