lvgl_SDL2_opengles显示驱动,用于缩放和色彩变化

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 */

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值