opengl support dirty rect

This commit is contained in:
lixianjing 2019-11-07 11:34:01 +08:00
parent d464305472
commit b3ccb6a77d
4 changed files with 317 additions and 1 deletions

View File

@ -7,6 +7,7 @@
* 修改动态设置 default_paint 属性为 auto 时没有效果的问题(感谢大恒提供补丁)。
* slide_view 增加/删除,或者改变位置/大小时,没有同步更新的问题(感谢朝泽提供补丁)。
* auto_hide 动画时间设置错误,以及 auto_hide 之后设置 visible 不能显示的问题(感谢朝泽提供补丁)。
* OpenGL 模式支持脏矩形(感谢智明提供补丁)。
* 2019/11/06
* 修改 emitter 中的错误(感谢朝泽提供补丁)。

View File

@ -290,7 +290,7 @@ lcd_t* lcd_vgcanvas_init(wh_t w, wh_t h, vgcanvas_t* canvas) {
base->h = (wh_t)h;
base->ratio = canvas->ratio;
base->type = LCD_VGCANVAS;
base->support_dirty_rect = FALSE;
base->support_dirty_rect = TRUE;
system_info_set_lcd_w(info, base->w);
system_info_set_lcd_h(info, base->h);

View File

@ -45,6 +45,25 @@
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"
typedef struct _vgcanvas_nanovg_screen_shader_info_t {
GLuint program_object;
GLuint coord_loc;
GLuint position_loc;
GLuint screentexture_loc;
GLuint indexs[6];
GLuint vboIds[3];
} vgcanvas_nanovg_screen_shader_info_t;
typedef struct _vgcanvas_nanovg_offline_fb_t {
GLuint fbo;
GLuint last_fbo;
GLuint rbo;
GLuint textureId;
uint32_t width;
uint32_t height;
} vgcanvas_nanovg_offline_fb_t;
typedef struct _vgcanvas_nanovg_t {
vgcanvas_t base;
@ -53,9 +72,242 @@ typedef struct _vgcanvas_nanovg_t {
uint32_t text_align_v;
uint32_t text_align_h;
vgcanvas_nanovg_offline_fb_t* offline_fb;
vgcanvas_nanovg_screen_shader_info_t* shader_program;
native_window_t* window;
} vgcanvas_nanovg_t;
static const char* vgcanvas_nanovg_shader_header =
#if defined NANOVG_GL2
" #define NANOVG_GL2 1 \n"
#elif defined NANOVG_GL3
" #version 150 core \n"
" #define NANOVG_GL3 1 \n"
#elif defined NANOVG_GLES2
" #version 100 \n"
" #define NANOVG_GL2 1 \n"
#elif defined NANOVG_GLES3
" #version 300 es \n"
" #define NANOVG_GL3 1 \n"
#endif
;
static inline GLuint vgcanvas_create_LoadShader(const char* g_strShaderHeader,
const char* g_strVertexShader,
const char* g_strFragmentShader) {
#define INFO_LOG_CHAR_LENGTH 512
GLint is_Success = 0;
GLint vertex_shader = 0;
GLint shader_program = 0;
GLint framgent_shader = 0;
const char* strShaders[2] = {0};
char log[INFO_LOG_CHAR_LENGTH] = {0};
strShaders[0] = g_strShaderHeader != NULL ? g_strShaderHeader : "";
strShaders[1] = g_strVertexShader;
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 2, (const GLchar* const*)&strShaders, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &is_Success);
if (is_Success == 0) {
memset(log, 0, INFO_LOG_CHAR_LENGTH);
glGetShaderInfoLog(vertex_shader, INFO_LOG_CHAR_LENGTH, NULL, log);
log_debug("Compile Vertex Shager fail message : %s \r\n", log);
}
strShaders[1] = g_strFragmentShader;
framgent_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(framgent_shader, 2, (const GLchar* const*)&strShaders, NULL);
glCompileShader(framgent_shader);
glGetShaderiv(framgent_shader, GL_COMPILE_STATUS, &is_Success);
if (is_Success == 0) {
memset(log, 0, INFO_LOG_CHAR_LENGTH);
glGetShaderInfoLog(framgent_shader, INFO_LOG_CHAR_LENGTH, NULL, log);
log_debug("Compile Framgent Shader fail message : %s \r\n", log);
}
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, framgent_shader);
glLinkProgram(shader_program);
glDeleteShader(vertex_shader);
glDeleteShader(framgent_shader);
glGetProgramiv(shader_program, GL_LINK_STATUS, &is_Success);
if (is_Success == 0) {
memset(log, 0, INFO_LOG_CHAR_LENGTH);
glGetProgramInfoLog(shader_program, INFO_LOG_CHAR_LENGTH, NULL, log);
log_debug("Link Program fail message : %s \r\n", log);
glDeleteProgram(shader_program);
return 0;
}
return shader_program;
}
vgcanvas_nanovg_screen_shader_info_t* vgcanvas_create_init_screen_shader() {
const GLuint indexs[] = {0, 1, 3, 1, 2, 3};
const GLfloat vertexs[] = {
// Position
1.0f, 1.0f, 0.0f, // top right
1.0f, -1.0f, 0.0f, // bottm right
-1.0f, -1.0f, 0.0f, // bottm left
-1.0f, 1.0f, 0.0f // top left
};
const GLfloat tcoords[] = {
// texture coords
1.0f, 1.0f, // top right
1.0f, 0.0f, // bottm right
0.0f, 0.0f, // bottm left
0.0f, 1.0f // top left
};
const char* vertex_shader =
" #ifdef NANOVG_GL3 \n"
" in vec2 vertex; \n"
" in vec2 tcoord; \n"
" out vec2 ftcoord; \n"
" #else \n"
" attribute vec3 g_vPosition; \n"
" attribute vec2 tcoord; \n"
" varying vec2 ftcoord; \n"
" #endif \n"
" void main(void) { \n"
" ftcoord = tcoord; \n"
" gl_Position = vec4(g_vPosition.x, g_vPosition.y, g_vPosition.z, 1.0); \n"
// " gl_Position = vec4(g_vPosition.x, -g_vPosition.y, g_vPosition.z, 1.0); \n"
// " gl_Position = vec4(-g_vPosition.x, g_vPosition.y, g_vPosition.z, 1.0); \n"
// " gl_Position = vec4(-g_vPosition.x, -g_vPosition.y, g_vPosition.z, 1.0); \n"
" } \n";
const char* fragment_shader =
" #ifdef NANOVG_GL3 \n"
" out vec4 outColor; \n"
" #endif \n"
" uniform sampler2D screentexture; \n"
" varying vec2 ftcoord; \n"
" void main() { \n"
" #ifdef NANOVG_GL3 \n"
" outColor = texture(screentexture, ftcoord); \n"
" #else \n"
" gl_FragColor = texture2D(screentexture, ftcoord); \n"
" #endif \n"
" } \n";
vgcanvas_nanovg_screen_shader_info_t* shader_info =
(vgcanvas_nanovg_screen_shader_info_t*)TKMEM_ZALLOC(vgcanvas_nanovg_screen_shader_info_t);
return_value_if_fail(shader_info != NULL, NULL);
memcpy(shader_info->indexs, indexs, sizeof(indexs));
shader_info->program_object =
vgcanvas_create_LoadShader(vgcanvas_nanovg_shader_header, vertex_shader, fragment_shader);
if (shader_info->program_object == 0) {
TKMEM_FREE(shader_info);
return NULL;
}
shader_info->coord_loc = glGetAttribLocation(shader_info->program_object, "tcoord");
shader_info->position_loc = glGetAttribLocation(shader_info->program_object, "g_vPosition");
shader_info->screentexture_loc =
glGetUniformLocation(shader_info->program_object, "screentexture");
glGenBuffers(sizeof(shader_info->vboIds) / sizeof(GLuint), shader_info->vboIds);
glBindBuffer(GL_ARRAY_BUFFER, shader_info->vboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs), vertexs, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, shader_info->vboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(tcoords), tcoords, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, shader_info->vboIds[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(shader_info->indexs), shader_info->indexs, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
return shader_info;
}
static void vgcanvas_destroy_shader(vgcanvas_nanovg_screen_shader_info_t* shader_info) {
glDeleteBuffers(sizeof(shader_info->vboIds) / sizeof(GLuint), shader_info->vboIds);
glDeleteShader(shader_info->program_object);
TKMEM_FREE(shader_info);
}
static void vgcanvas_destroy_offline_fb(vgcanvas_nanovg_offline_fb_t* offline_fb) {
glDeleteFramebuffers(1, &offline_fb->fbo);
glDeleteRenderbuffers(1, &offline_fb->rbo);
glDeleteTextures(1, &offline_fb->textureId);
TKMEM_FREE(offline_fb);
}
static vgcanvas_nanovg_offline_fb_t* vgcanvas_create_offline_fb(uint32_t width, uint32_t height) {
GLenum status = 0;
GLint default_fbo = 0;
GLint default_rbo = 0;
GLint max_render_buffer_size = 0;
vgcanvas_nanovg_offline_fb_t* offline_fb =
(vgcanvas_nanovg_offline_fb_t*)TKMEM_ZALLOC(vgcanvas_nanovg_offline_fb_t);
return_value_if_fail(offline_fb != NULL, NULL);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &default_fbo);
glGetIntegerv(GL_RENDERBUFFER_BINDING, &default_rbo);
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &max_render_buffer_size);
if ((max_render_buffer_size <= width) || (max_render_buffer_size <= height)) {
log_debug("Cannot use framebuffer objects! \r\n");
TKMEM_FREE(offline_fb);
return NULL;
}
offline_fb->width = width;
offline_fb->height = height;
glGenFramebuffers(1, &offline_fb->fbo);
glGenRenderbuffers(1, &offline_fb->rbo);
glBindRenderbuffer(GL_RENDERBUFFER, offline_fb->rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
glGenTextures(1, &offline_fb->textureId);
glBindTexture(GL_TEXTURE_2D, offline_fb->textureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, offline_fb->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, offline_fb->textureId,
0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
offline_fb->rbo);
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
log_debug("Framebuffer object is not complete! \r\n");
return FALSE;
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
glBindRenderbuffer(GL_RENDERBUFFER, default_rbo);
return offline_fb;
}
#include "texture.inc"
#include "vgcanvas_nanovg_gl.inc"
#include "vgcanvas_nanovg.inc"
@ -88,5 +340,8 @@ vgcanvas_t* vgcanvas_create(uint32_t w, uint32_t h, uint32_t stride, bitmap_form
assert(!"OpenGL is not supported!");
}
nanovg->shader_program = vgcanvas_create_init_screen_shader();
nanovg->offline_fb = vgcanvas_create_offline_fb(w * info.ratio, h * info.ratio);
return &(nanovg->base);
}

View File

@ -8,6 +8,60 @@ static ret_t vgcanvas_nanovg_reinit(vgcanvas_t* vg, uint32_t w, uint32_t h, uint
return RET_OK;
}
static inline void vgcanvas_nanovg_set_offline_fb(vgcanvas_nanovg_t* canvas, float w, float h) {
vgcanvas_nanovg_offline_fb_t* offline_fb = canvas->offline_fb;
if (offline_fb != NULL) {
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &offline_fb->last_fbo);
if (offline_fb->width != w || offline_fb->height != h) {
vgcanvas_destroy_offline_fb(canvas->offline_fb);
canvas->offline_fb = vgcanvas_create_offline_fb(w, h);
offline_fb = canvas->offline_fb;
}
glBindFramebuffer(GL_FRAMEBUFFER, offline_fb->fbo);
glViewport(0, 0, w, h);
// glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
}
static inline void vgcanvas_nanovg_offline_fb_flush(vgcanvas_nanovg_t* canvas) {
system_info_t* info = system_info();
vgcanvas_nanovg_offline_fb_t* offline_fb = canvas->offline_fb;
vgcanvas_nanovg_screen_shader_info_t* shader_info = canvas->shader_program;
if (offline_fb != NULL && shader_info != NULL) {
glBindFramebuffer(GL_FRAMEBUFFER, offline_fb->last_fbo);
glViewport(0, 0, info->lcd_w * info->device_pixel_ratio,
info->lcd_h * info->device_pixel_ratio);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glUseProgram(shader_info->program_object);
glBindBuffer(GL_ARRAY_BUFFER, shader_info->vboIds[0]);
glVertexAttribPointer(shader_info->position_loc, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(shader_info->position_loc);
glBindBuffer(GL_ARRAY_BUFFER, shader_info->vboIds[1]);
glVertexAttribPointer(shader_info->coord_loc, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(shader_info->coord_loc);
// Bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, offline_fb->textureId);
glUniform1i(shader_info->screentexture_loc, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, shader_info->vboIds[2]);
glDrawElements(GL_TRIANGLES, sizeof(shader_info->indexs) / sizeof(GLuint), GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(shader_info->position_loc);
glDisableVertexAttribArray(shader_info->coord_loc);
}
}
static ret_t vgcanvas_nanovg_begin_frame(vgcanvas_t* vgcanvas, rect_t* dirty_rect) {
float_t angle = 0.0f;
float_t anchor_x = 0.0f;
@ -18,6 +72,9 @@ static ret_t vgcanvas_nanovg_begin_frame(vgcanvas_t* vgcanvas, rect_t* dirty_rec
native_window_gl_make_current(canvas->window);
vgcanvas_nanovg_set_offline_fb(canvas, info->lcd_w * info->device_pixel_ratio,
info->lcd_h * info->device_pixel_ratio);
nvgBeginFrame(canvas->vg, info->lcd_w, info->lcd_h, info->device_pixel_ratio);
switch (info->lcd_orientation) {
@ -59,6 +116,9 @@ static ret_t vgcanvas_nanovg_end_frame(vgcanvas_t* vgcanvas) {
nvgRestore(vg);
nvgEndFrame(vg);
vgcanvas_nanovg_offline_fb_flush(canvas);
native_window_swap_buffer(canvas->window);
return RET_OK;