lvgl_SDL2_opengles显示驱动移植说明
前提说明
本文编写于2022年末,lvgl 9未发布的时候,若lvgl 9 发布后可能其自身就带有类似的功能。本文的思路来源于显示摄像头画面,这里将lvgl输出的画面当成摄像头数数据处理。
1.简介
本文所构建的lvgl工程添加了一个opengles的显示驱动,用于通过使用gpu处理最终的ui画面,来降低cpu占用率。其诞生的原因是lvgl v8在无法多线程生成ui画面,也没有专用的gpu加速ui生成,结果单核性能瓶颈导致画面卡顿(卡顿的典型情况:全屏滑动卡顿)。其主要用于对最终画面进行缩放,旋转,以及rgb565转argb。此外,由于opengles本身的特点,还可以对输出画面进行其他二次处理,或者模仿一些纹理优化操作,进行分区域渲染。
2.使用环境
本文搭建的的lvgl工程,基于sdl2和opengles2.0。工程的测试环境为wayland+SDL2+opengles2.0。
3.依赖的库
额外依赖epoxy,SDL2,pthread,具体依赖情况可以参考cmake里的配置
4.移植说明
4.1 添加文件
将sdl_gles.c和sdl_gles.h添加到目录lv_drivers/sdl里
4.2 修改lvgl源码
修改lv_drivers/sdl/sdl_gles.h
修改为
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if USE_SDL || USE_SDL_GPU || USE_SDL_GLES
#ifndef SDL_INCLUDE_PATH
#define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
#endif
#include SDL_INCLUDE_PATH
修改lv_drv_conf.h
修改为
/* Hardware accelerated SDL driver */
#ifndef USE_SDL_GPU
# define USE_SDL_GPU 0
#endif
#ifndef USE_SDL_GLES
# define USE_SDL_GLES 1
#endif
#if USE_SDL || USE_SDL_GPU || USE_SDL_GLES
# define SDL_HOR_RES 1920
# define SDL_VER_RES 1200
# define SDL_HOR_RES_ZOOM 1920
# define SDL_VER_RES_ZOOM 1200
/* Scale window by this factor (useful when simulating small screens) */
# define SDL_ZOOM 1
修改lvgl/src/core/lv_refr.c
修改为
/*Save only if this area is not in one of the saved areas*/
uint16_t i;
for(i = 0; i < disp->inv_p; i++) {
if(_lv_area_is_in(&com_area, &disp->inv_areas[i], 0) != false) return;
}
/*Save the area*/
// if(disp->inv_p < LV_INV_BUF_SIZE) {
// lv_area_copy(&disp->inv_areas[disp->inv_p], &com_area);
// }
// else { /*If no place for the area add the screen*/
disp->inv_p = 0;
lv_area_copy(&disp->inv_areas[disp->inv_p], &scr_area);
// }
disp->inv_p++;
if(disp->refr_timer) lv_timer_resume(disp->refr_timer);
该修改是为了使lvgl始终保持全局刷新,目前所写的opengles驱动并不支持局部刷新
5.使用说明
5.1 缩放
修改lv_drv_conf.h里的配置:
SDL_HOR_RES和SDL_VER_RES为lvgl输出buffer的长宽;
SDL_HOR_RES_ZOOM和SDL_VER_RES_ZOOM为需要输出屏幕的长宽;
#if USE_SDL || USE_SDL_GPU || USE_SDL_GLES
# define SDL_HOR_RES 1920
# define SDL_VER_RES 1200
# define SDL_HOR_RES_ZOOM 1920
# define SDL_VER_RES_ZOOM 1200
5.2 色彩设置
在lv_conf.h里设置,同lvgl的色彩设置,目前lvgl生成的ui为rgb565,opengl输出为rgba。
这里设置16,及rgb565
/*====================
COLOR SETTINGS
*====================*/
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16
6.源码
这个提供核心两个文件的源码,外部的一些变化可以参考另外一篇移植opengles的文章,opengles的操作我也是从那边模仿来的。我操作的环境应该是lvgl 8.3
https://forum.lvgl.io/t/opengl-es-2-0-implementation-of-lvgl/8729
sdl_gles.c
/**
* @file sdl.h
*
*/
/*********************
* INCLUDES
*********************/
#include "sdl_gles.h"
#if USE_SDL_GLES
#include <epoxy/egl.h>
#if LV_USE_GPU_SDL
# error "LV_USE_GPU_SDL must not be enabled"
#endif
#if USE_MONITOR
# warning "MONITOR is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_KEYBOARD
# warning "KEYBOARD is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MOUSE
# warning "MOUSE is deprecated, use SDL instead. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MOUSEWHEEL
# warning "MOUSEWHEEL is deprecated, use SDL instead that. See lv_drivers/sdl/sdl.c"
#endif
#if USE_MONITOR && USE_SDL
# error "Cannot enable both MONITOR and SDL at the same time. "
#endif
#if USE_MONITOR
# define SDL_HOR_RES MONITOR_HOR_RES
# define SDL_VER_RES MONITOR_VER_RES
# define SDL_ZOOM MONITOR_ZOOM
# define SDL_DOUBLE_BUFFERED MONITOR_DOUBLE_BUFFERED
# define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
# define SDL_VIRTUAL_MACHINE MONITOR_VIRTUAL_MACHINE
# define SDL_DUAL_DISPLAY MONITOR_DUAL
#endif
#ifndef SDL_FULLSCREEN
# define SDL_FULLSCREEN 0
#endif
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include SDL_INCLUDE_PATH
/*********************
* DEFINES
*********************/
#ifndef KEYBOARD_BUFFER_SIZE
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
SDL_Window * window;
// SDL_Renderer * renderer;
// SDL_Texture * texture;
SDL_GLContext *context;
GLuint program;
GLint position_location;
GLint uv_location;
GLuint texture;
GLuint framebuffer;
volatile bool sdl_refr_qry;
#if SDL_DOUBLE_BUFFERED
uint32_t * tft_fb_act;
#else
uint32_t * tft_fb;
#endif
}monitor_t;
typedef float vec2[2];
typedef float vec3[3];
typedef float vec4[4];
typedef vec4 mat4[4];
typedef struct lv_draw_gles_context_internals_t {
lv_coord_t hor;
lv_coord_t ver;
mat4 projection;
GLuint plain_rect_shader;
GLint plain_rect_shader_pos_location;
GLint plain_rect_shader_projection_location;
GLint plain_rect_shader_model_location;
GLint plain_rect_shader_color_location;
GLuint simple_img_shader;
GLint simple_img_shader_pos_location;
GLint simple_img_shader_uv_location;
GLint simple_img_shader_projection_location;
GLint simple_img_shader_model_location;
GLint simple_img_shader_color_location;
GLint simple_img_shader_texture_location;
} lv_draw_gles_context_internals_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void window_create(monitor_t * m);
static void window_update(monitor_t * m);
static void monitor_sdl_clean_up(void);
static void sdl_gles_event_handler(lv_timer_t * t);
static void monitor_sdl_gles_refr(lv_timer_t * t);
/***********************
* GLOBAL PROTOTYPES
***********************/
/**********************
* STATIC VARIABLES
**********************/
monitor_t monitor;
lv_draw_gles_context_internals_t internals;
#if SDL_DUAL_DISPLAY
monitor_t monitor2;
#endif
static volatile bool sdl_inited = false;
static bool left_button_down = false;
static int16_t last_x = 0;
static int16_t last_y = 0;
static int16_t wheel_diff = 0;
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
static char buf[KEYBOARD_BUFFER_SIZE];
static char vertex_shader_str[] =
"attribute vec2 a_position; \n"
"attribute vec2 a_texcoord; \n"
"varying vec2 v_texcoord; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); \n"
" v_texcoord = a_texcoord; \n"
"} \n";
static char fragment_shader_str[] =
"precision mediump float; \n"
"varying vec2 v_texcoord; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D(s_texture, v_texcoord );\n"
"} \n";
#define PLAIN_RECT_VERTEX_SHADER_SRC \
"attribute vec2 a_position;" \
"uniform mat4 u_projection;"\
"uniform mat4 u_model;"\
"void main()"\
"{"\
" gl_Position = u_projection * u_model * vec4(a_position.x, a_position.y, 0.0, 1.0);"\
"}"
#define PLAIN_RECT_FRAGMENT_SHADER_SRC \
"precision mediump float;" \
"uniform vec4 u_color;" \
"void main()" \
"{" \
" gl_FragColor = u_color;" \
"}"
#define SIMPLE_IMG_VERTEX_SHADER_SRC \
"attribute vec2 a_position;" \
"attribute vec2 a_uv;" \
"varying vec2 v_uv;" \
"uniform mat4 u_projection;" \
"uniform mat4 u_model;" \
"void main()" \
"{" \
" gl_Position = vec4(a_position.x * 2.0 - 1.0, -(a_position.y * 2.0) + 1.0, 0.0, 1.0);" \
" v_uv = a_uv;" \
"}"
#if LV_COLOR_DEPTH == 16
#define SIMPLE_IMG_FRAGMENT_SHADER_SRC \
"precision mediump float;" \
"varying vec2 v_uv;" \
"uniform sampler2D s_texture;" \
"uniform vec4 u_color;" \
"void main()" \
"{" \
" vec4 texture_color = texture2D(s_texture, v_uv);" \
" gl_FragColor = vec4(texture_color.r, texture_color.g, texture_color.b, texture_color.a);" \
"}"
#else
#define SIMPLE_IMG_FRAGMENT_SHADER_SRC \
"precision mediump float;" \
"varying vec2 v_uv;" \
"uniform sampler2D s_texture;" \
"uniform vec4 u_color;" \
"void main()" \
"{" \
" vec4 texture_color = texture2D(s_texture, v_uv);" \
" gl_FragColor = vec4(texture_color.b, texture_color.g, texture_color.r, texture_color.a);" \
"}"
#endif
static GLfloat vertices[] = {
-1.0f, 1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_gles_math_mat4_zero(mat4 m)
{
lv_memset_00(m, sizeof(mat4));
}
void lv_draw_gles_math_mat4_identity(mat4 m)
{
lv_memset_00(m, sizeof(mat4));
m[0][0] = 1.0f;
m[1][1] = 1.0f;
m[2][2] = 1.0f;
m[3][3] = 1.0f;
}
void lv_draw_gles_math_ortho(float left, float right, float bottom, float top, float near, float far, mat4 res)
{
lv_draw_gles_math_mat4_zero(res);
res[0][0] = 2.0f/(right - left);
res[1][1] = 2.0f/(top - bottom);
res[2][2] = 2.0f/(near - far);
res[3][3] = 1.0f;
res[3][0] = (right + left) / (left - right);
res[3][1] = (top + bottom) / (bottom - top);
res[3][2] = (far + near) / (near - far);
}
void lv_color_to_vec4_color_with_opacity(const lv_color_t * in, lv_opa_t opa, vec4 out)
{
// out[0] = (float)in->ch.red/255.0f;
// out[1] = (float)in->ch.green/255.0f;
// out[2] = (float)in->ch.blue/255.0f;
// out[3] = (float)opa/255.0f;
}
void lv_draw_gles_math_mat4_copy(mat4 m, mat4 res)
{
lv_memcpy(res, m, sizeof(mat4));
}
void lv_draw_gles_math_mat4_mul(mat4 m1, mat4 m2, mat4 res)
{
mat4 tmp;
tmp[0][0] = m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3];
tmp[0][1] = m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3];
tmp[0][2] = m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3];
tmp[0][3] = m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3];
tmp[1][0] = m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3];
tmp[1][1] = m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3];
tmp[1][2] = m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3];
tmp[1][3] = m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3];
tmp[2][0] = m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3];
tmp[2][1] = m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3];
tmp[2][2] = m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3];
tmp[2][3] = m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3];
tmp[3][0] = m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3];
tmp[3][1] = m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3];
tmp[3][2] = m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3];
tmp[3][3] = m1[0][3] * m2[3][0] + m1[1][3] * m2[3][1] + m1[2][3] * m2[3][2] + m1[3][3] * m2[3][3];
lv_memcpy(res, tmp, sizeof(mat4));
}
void lv_draw_gles_math_translate(mat4 m, vec3 v)
{
mat4 tmp;
lv_draw_gles_math_mat4_identity(tmp);
tmp[3][0] = v[0];
tmp[3][1] = v[1];
tmp[3][2] = v[2];
lv_draw_gles_math_mat4_mul(m, tmp, m);
}
void lv_draw_gles_math_scale(mat4 m, vec3 v)
{
mat4 tmp;
lv_draw_gles_math_mat4_zero(tmp);
tmp[0][0] = v[0];
tmp[1][1] = v[1];
tmp[2][2] = v[2];
tmp[3][3] = 1.0f;
lv_draw_gles_math_mat4_mul(m, tmp, m);
}
void sdl_gles_init(void)
{
/*Initialize the SDL*/
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
window_create(&monitor);
lv_timer_create(sdl_gles_event_handler, 10, NULL);
}
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_gles_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
uint32_t start = lv_tick_get();
volatile uint32_t elaps = 0;
printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2);
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if SDL_DOUBLE_BUFFERED
monitor.tft_fb_act = (uint32_t *)color_p;
#else /*SDL_DOUBLE_BUFFERED*/
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
// for(y = area->y1; y <= area->y2 && y < vres; y++) {
// for(x = area->x1; x <= area->x2; x++) {
// monitor.tft_fb[y * hres + x] = lv_color_to32(*color_p);
// color_p++;
// }
// }
#else
uint32_t w = lv_area_get_width(area);
// for(y = area->y1; y <= area->y2 && y < vres; y++) {
// memcpy(&monitor.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
// color_p += w;
// }
// for(y = area->y1; y <= area->y2 && y < vres; y++) {
// for(uint32_t x = area->x1; x <= area->x2 && x < hres; x++) {
// uint8_t *pix = &monitor.tft_fb[y * hres + area->x1 + x];
// *(pix) = color_p->ch.red;
// *(pix + 1) = color_p->ch.green;
// *(pix + 2) = color_p->ch.blue;
// *(pix + 3) = color_p->ch.alpha;
// color_p += 1;
// }
// }
// elaps = lv_tick_elaps(start);
// printf("mem copy, elaps: %d\n", elaps);
#endif
#endif /*SDL_DOUBLE_BUFFERED*/
/* test draw rect start*/
// lv_color_t bg_color = *color_p;
// vec4 color;
// lv_color_to_vec4_color_with_opacity(&bg_color, 255, color);
// static GLfloat vertices[] = {
// 0.0f, 1.0f,
// 1.0f, 0.0f,
// 0.0f, 0.0f,
// 0.0f, 1.0f,
// 1.0f, 1.0f,
// 1.0f, 0.0f,
// };
// mat4 model;
// lv_draw_gles_math_mat4_identity(model);
// lv_draw_gles_math_translate(model, (vec3) {area->x1, area->y1});
// lv_draw_gles_math_scale(model, (vec3) {area->x2 - area->x1, area->y2 - area->y1});
// printf("coords: x1 :%d x2: %d y1 : %d y2 : %d\n",
// area->x1,
// area->x2,
// area->y1,
// area->y2);
// glBindFramebuffer(GL_FRAMEBUFFER, monitor.framebuffer);
// glUseProgram(internals.plain_rect_shader);
// glUniform4f(internals.plain_rect_shader_color_location, color[0], color[1], color[2], color[3]);
// glUniformMatrix4fv(internals.plain_rect_shader_model_location, 1, GL_FALSE, &model[0][0]);
// glVertexAttribPointer(internals.plain_rect_shader_pos_location, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vertices);
// glEnableVertexAttribArray(internals.plain_rect_shader_pos_location);
// glDrawArrays(GL_TRIANGLES, 0, 6);
// glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* test draw rect end */
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
/* test draw img start*/
static GLuint texture = 0;
GLuint *p_texture = &texture;
static uint8_t flag = 0;
if(flag == 0) {
glGenTextures(1, p_texture);
glBindTexture(GL_TEXTURE_2D, *p_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
flag = 1;
} else {
glBindTexture(GL_TEXTURE_2D, *p_texture);
}
#if LV_COLOR_DEPTH == 16
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SDL_HOR_RES, SDL_VER_RES, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, color_p);
#elif LV_COLOR_DEPTH == 24
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SDL_HOR_RES, SDL_VER_RES, 0, GL_RGB, GL_UNSIGNED_BYTE, color_p);
#elif LV_COLOR_DEPTH == 32
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SDL_HOR_RES, SDL_VER_RES, 0, GL_RGBA, GL_UNSIGNED_BYTE, color_p);
#endif
elaps = lv_tick_elaps(start);
printf("Textures, elaps: %d\n", elaps);
vec2 uv;
vec2 uv2;
// uv[0] = (float)(clipped_area.x1 - zoomed_cords.x1) / (float)(texture_width);
// uv[1] = (float)(clipped_area.y1 - zoomed_cords.y1) / (float)(texture_height);
// uv2[0] = 1.0f - (float)(zoomed_cords.x1 - clipped_area.x1) / (float)(texture_width);
// uv2[1] = 1.0f - (float)(zoomed_cords.y2 - clipped_area.y2) / (float)(texture_height);
// GLfloat vertices[] = {
// 0.0f, 1.0f, uv[0], uv2[1],
// 1.0f, 0.0f, uv2[0], uv[1],
// 0.0f, 0.0f, uv[0], uv[1],
// 0.0f, 1.0f, uv[0], uv2[1],
// 1.0f, 1.0f, uv2[0], uv2[1],
// 1.0f, 0.0f, uv2[0], uv[1]
// };
GLfloat vertices[] = {
0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f,
1.0f, 0.0f, 1.0f, 1.0f
};
mat4 model;
lv_draw_gles_math_mat4_identity(model);
lv_draw_gles_math_translate(model, (vec3) {area->x1, area->y1});
lv_draw_gles_math_scale(model, (vec3) {area->x2 - area->x1, area->y2 - area->y1});
glBindFramebuffer(GL_FRAMEBUFFER, monitor.framebuffer);
glUseProgram(internals.simple_img_shader);
glUniformMatrix4fv(internals.simple_img_shader_model_location, 1, GL_FALSE, &model[0][0]);
glUniform1i(internals.simple_img_shader_texture_location, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform4f(internals.simple_img_shader_color_location, 0.0f, 0.0f, 0.0f, 0.0f);
glVertexAttribPointer(internals.simple_img_shader_pos_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices);
glEnableVertexAttribArray(internals.simple_img_shader_pos_location);
glVertexAttribPointer(internals.simple_img_shader_uv_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), &vertices[2]);
glEnableVertexAttribArray(internals.simple_img_shader_uv_location);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
elaps = lv_tick_elaps(start);
printf("fbo, elaps: %d\n", elaps);
/* test draw img end*/
monitor.sdl_refr_qry = true;
monitor_sdl_gles_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
}
#if SDL_DUAL_DISPLAY
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
const lv_coord_t hres = disp_drv->physical_hor_res == -1 ? disp_drv->hor_res : disp_drv->physical_hor_res;
const lv_coord_t vres = disp_drv->physical_ver_res == -1 ? disp_drv->ver_res : disp_drv->physical_ver_res;
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if SDL_DOUBLE_BUFFERED
monitor2.tft_fb_act = (uint32_t *)color_p;
monitor2.sdl_refr_qry = true;
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#else
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
for(y = area->y1; y <= area->y2 && y < vres; y++) {
for(x = area->x1; x <= area->x2; x++) {
monitor2.tft_fb[y * hres + x] = lv_color_to32(*color_p);
color_p++;
}
}
#else
uint32_t w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2 && y < vres; y++) {
memcpy(&monitor2.tft_fb[y * hres + area->x1], color_p, w * sizeof(lv_color_t));
color_p += w;
}
#endif
monitor2.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor_sdl_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#endif
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void sdl_gles_event_handler(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
SDL_Event event;
while(SDL_PollEvent(&event)) {
mouse_handler(&event);
mousewheel_handler(&event);
keyboard_handler(&event);
if((&event)->type == SDL_WINDOWEVENT) {
switch((&event)->window.event) {
#if SDL_VERSION_ATLEAST(2, 0, 5)
case SDL_WINDOWEVENT_TAKE_FOCUS:
#endif
case SDL_WINDOWEVENT_EXPOSED:
window_update(&monitor);
#if SDL_DUAL_DISPLAY
window_update(&monitor2);
#endif
break;
default:
break;
}
}
}
/*Run until quit event not arrives*/
if(sdl_quit_qry) {
monitor_sdl_clean_up();
exit(0);
}
}
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void monitor_sdl_gles_refr(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
if(monitor.sdl_refr_qry != false) {
monitor.sdl_refr_qry = false;
window_update(&monitor);
}
#if SDL_DUAL_DISPLAY
if(monitor2.sdl_refr_qry != false) {
monitor2.sdl_refr_qry = false;
window_update(&monitor2);
}
#endif
}
static void monitor_sdl_clean_up(void)
{
SDL_DestroyWindow(monitor.window);
#if SDL_DUAL_DISPLAY
SDL_DestroyTexture(monitor2.texture);
SDL_DestroyRenderer(monitor2.renderer);
SDL_DestroyWindow(monitor2.window);
#endif
// SDL_Quit();
}
static GLuint shader_create(GLenum type, const char *src)
{
GLint success = 0;
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success)
{
GLint info_log_len = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_len);
char *info_log = malloc(info_log_len+1);
info_log[info_log_len] = '\0';
glGetShaderInfoLog(shader, info_log_len, NULL, info_log);
fprintf(stderr, "Failed to compile shader : %s", info_log);
free(info_log);
}
return shader;
}
static GLuint gl_shader_program_create(const char *vertex_src,
const char *fragment_src)
{
GLuint vertex = shader_create(GL_VERTEX_SHADER, vertex_src);
GLuint fragment = shader_create(GL_FRAGMENT_SHADER, fragment_src);
GLuint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
glDeleteShader(vertex);
glDeleteShader(fragment);
return program;
}
static void window_create(monitor_t * m)
{
m->window = SDL_CreateWindow("lvgl-opengl",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
// SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM,
SDL_HOR_RES_ZOOM, SDL_VER_RES_ZOOM,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
m->context = SDL_GL_CreateContext(m->window);
printf( "GL version : %s\n", glGetString(GL_VERSION));
printf( "GL vendor : %s\n", glGetString(GL_VENDOR));
printf( "GL renderer : %s\n", glGetString(GL_RENDERER));
fflush(stdout);
m->program = gl_shader_program_create(vertex_shader_str, fragment_shader_str);
glUseProgram(m->program);
m->position_location = glGetAttribLocation(m->program, "a_position");
m->uv_location = glGetAttribLocation(m->program, "a_texcoord");
glGenTextures(1, &m->texture);
glBindTexture(GL_TEXTURE_2D, m->texture);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SDL_HOR_RES_ZOOM, SDL_VER_RES_ZOOM, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &m->framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m->framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m->texture, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/*Initialize the frame buffer to gray (77 is an empirical value) */
#if SDL_DOUBLE_BUFFERED
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, SDL_HOR_RES * sizeof(uint32_t));
#else
m->tft_fb = (uint32_t *)malloc(sizeof(uint32_t) * SDL_HOR_RES * SDL_VER_RES);
memset(m->tft_fb, 0x44, SDL_HOR_RES * SDL_VER_RES * sizeof(uint32_t));
#endif
m->sdl_refr_qry = true;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// add shader
// internals.hor = SDL_HOR_RES;
// internals.ver = SDL_VER_RES;
internals.hor = SDL_HOR_RES;
internals.ver = SDL_VER_RES;
mat4 projection;
lv_draw_gles_math_mat4_identity(projection);
lv_draw_gles_math_ortho(0.0f,
(float)internals.hor,
(float)internals.ver,
0.0f,
-1.0f, 1.0f,
projection);
lv_draw_gles_math_mat4_copy(projection, internals.projection);
internals.plain_rect_shader = gl_shader_program_create(PLAIN_RECT_VERTEX_SHADER_SRC, PLAIN_RECT_FRAGMENT_SHADER_SRC);
glUseProgram(internals.plain_rect_shader);
internals.plain_rect_shader_pos_location = glGetAttribLocation(internals.plain_rect_shader, "a_position");
internals.plain_rect_shader_projection_location = glGetUniformLocation(internals.plain_rect_shader, "u_projection");
internals.plain_rect_shader_model_location = glGetUniformLocation(internals.plain_rect_shader, "u_model");
internals.plain_rect_shader_color_location = glGetUniformLocation(internals.plain_rect_shader, "u_color");
glUniformMatrix4fv(internals.plain_rect_shader_projection_location, 1, GL_FALSE, &internals.projection[0][0]);
glUseProgram(0);
internals.simple_img_shader = gl_shader_program_create(SIMPLE_IMG_VERTEX_SHADER_SRC, SIMPLE_IMG_FRAGMENT_SHADER_SRC);
glUseProgram(internals.simple_img_shader);
internals.simple_img_shader_pos_location = glGetAttribLocation(internals.simple_img_shader, "a_position");
internals.simple_img_shader_uv_location = glGetAttribLocation(internals.simple_img_shader, "a_uv");
internals.simple_img_shader_projection_location = glGetUniformLocation(internals.simple_img_shader, "u_projection");
internals.simple_img_shader_model_location = glGetUniformLocation(internals.simple_img_shader, "u_model");
internals.simple_img_shader_color_location = glGetUniformLocation(internals.simple_img_shader, "u_color");
internals.simple_img_shader_texture_location = glGetUniformLocation(internals.simple_img_shader, "s_texture");
glUniformMatrix4fv(internals.simple_img_shader_projection_location, 1, GL_FALSE, &internals.projection[0][0]);
glUseProgram(0);
}
static void window_update(monitor_t * m)
{
uint32_t start = lv_tick_get();
volatile uint32_t elaps = 0;
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(m->program);
glBindTexture(GL_TEXTURE_2D, m->texture);
glVertexAttribPointer(m->position_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), vertices);
glEnableVertexAttribArray(m->position_location);
glVertexAttribPointer(m->uv_location, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), &vertices[2]);
glEnableVertexAttribArray(m->uv_location);
glDrawArrays(GL_TRIANGLES, 0, 6);
elaps = lv_tick_elaps(start);
printf("window_update, elaps: %d\n", elaps);
SDL_GL_SwapWindow(m->window);
}
#endif /*USE_SDL_GLES*/
sdl_gles.h
/**
* @file sdl.h
*
*/
#ifndef SDL_H
#define SDL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_SDL_GLES
#include "sdl_common.h"
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize SDL to be used as display, mouse and mouse wheel drivers.
*/
void sdl_gles_init(void);
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_gles_display_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**
* Flush a buffer to the marked area
* @param disp_drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixels to copy to the `area` part of the screen
*/
void sdl_display_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**
* Get the current position and state of the mouse
* @param indev_drv pointer to the related input device driver
* @param data store the mouse data here
*/
void sdl_mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get encoder (i.e. mouse wheel) ticks difference and pressed state
* @param indev_drv pointer to the related input device driver
* @param data store the read data here
*/
void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/**
* Get input from the keyboard.
* @param indev_drv pointer to the related input device driver
* @param data store the red data here
*/
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/*For backward compatibility. Will be removed.*/
#define monitor_init sdl_gles_init
#define monitor_flush sdl_display_flush
#define monitor_flush2 sdl_display_flush2
/**********************
* MACROS
**********************/
#endif /* USE_MONITOR || USE_SDL */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SDL_H */