Work on rendering to FBO

This commit is contained in:
Kovid Goyal 2017-11-23 17:56:20 +05:30
parent f85c050235
commit ffff343e3d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
8 changed files with 101 additions and 30 deletions

11
kitty/blit_fragment.glsl Normal file
View File

@ -0,0 +1,11 @@
#version GLSL_VERSION
uniform sampler2D image;
in vec2 texcoord;
out vec4 color;
void main() {
color = texture(image, texcoord);
color = vec4(color.rgb / color.a, color.a);
}

30
kitty/blit_vertex.glsl Normal file
View File

@ -0,0 +1,30 @@
#version GLSL_VERSION
#define vleft -1.0
#define vtop 1.0
#define vright 1.0
#define vbottom -1.0
#define tleft 0
#define ttop 1
#define tright 1
#define tbottom 0
const vec2 viewport_xpos = vec2(vleft, vright);
const vec2 viewport_ypos = vec2(vtop, vbottom);
const vec2 texture_xpos = vec2(tleft, tright);
const vec2 texture_ypos = vec2(ttop, tbottom);
const uvec2 pos_map[] = uvec2[4](
uvec2(1, 0), // right, top
uvec2(1, 1), // right, bottom
uvec2(0, 1), // left, bottom
uvec2(0, 0) // left, top
);
out vec2 texcoord;
void main() {
uvec2 pos = pos_map[gl_VertexID];
gl_Position = vec4(viewport_xpos[pos[0]], viewport_ypos[pos[1]], 0, 1);
texcoord = vec2(texture_xpos[pos[0]], texture_ypos[pos[1]]);
}

View File

@ -601,7 +601,7 @@ render(double now) {
if (!w->num_tabs || !should_os_window_be_rendered(w)) continue; if (!w->num_tabs || !should_os_window_be_rendered(w)) continue;
make_os_window_context_current(w); make_os_window_context_current(w);
if (w->viewport_size_dirty) { if (w->viewport_size_dirty) {
update_surface_size(w->viewport_width, w->viewport_height); update_surface_size(w->viewport_width, w->viewport_height, w->offscreen_texture_id);
w->viewport_size_dirty = false; w->viewport_size_dirty = false;
} }
unsigned int active_window_id = 0; unsigned int active_window_id = 0;

View File

@ -63,8 +63,12 @@ gl_init() {
} }
void void
update_surface_size(int w, int h) { update_surface_size(int w, int h, GLuint offscreen_texture_id) {
glViewport(0, 0, w, h); glViewport(0, 0, w, h);
if (offscreen_texture_id) {
glBindTexture(GL_TEXTURE_2D, offscreen_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
} }
void void
@ -251,7 +255,7 @@ typedef struct {
ssize_t buffers[10]; ssize_t buffers[10];
} VAO; } VAO;
static VAO vaos[2*MAX_CHILDREN + 10] = {{0}}; static VAO vaos[4*MAX_CHILDREN + 10] = {{0}};
static ssize_t static ssize_t
create_vao() { create_vao() {

View File

@ -9,8 +9,8 @@
#include "fonts.h" #include "fonts.h"
#include <sys/sysctl.h> #include <sys/sysctl.h>
enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, CURSOR_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, NUM_PROGRAMS }; enum { CELL_PROGRAM, CELL_BG_PROGRAM, CELL_SPECIAL_PROGRAM, CELL_FG_PROGRAM, CURSOR_PROGRAM, BORDERS_PROGRAM, GRAPHICS_PROGRAM, BLIT_PROGRAM, NUM_PROGRAMS };
enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT }; enum { SPRITE_MAP_UNIT, GRAPHICS_UNIT, BLIT_UNIT };
// Sprites {{{ // Sprites {{{
typedef struct { typedef struct {
@ -142,6 +142,8 @@ typedef struct {
} CellProgramLayout; } CellProgramLayout;
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS]; static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
static GLuint offscreen_framebuffer = 0;
static ssize_t blit_vertex_array;
static void static void
init_cell_program() { init_cell_program() {
@ -158,7 +160,8 @@ init_cell_program() {
C(p, colors, 0); C(p, sprite_coords, 1); C(p, is_selected, 2); C(p, colors, 0); C(p, sprite_coords, 1); C(p, is_selected, 2);
} }
#undef C #undef C
glGenFramebuffers(1, &offscreen_framebuffer);
blit_vertex_array = create_vao();
} }
#define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer }; #define CELL_BUFFERS enum { cell_data_buffer, selection_buffer, uniform_buffer };
@ -278,7 +281,6 @@ static void
draw_graphics(ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) { draw_graphics(ssize_t vao_idx, ssize_t gvao_idx, ImageRenderData *data, GLuint start, GLuint count) {
bind_vertex_array(gvao_idx); bind_vertex_array(gvao_idx);
bind_program(GRAPHICS_PROGRAM); bind_program(GRAPHICS_PROGRAM);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
static bool graphics_constants_set = false; static bool graphics_constants_set = false;
if (!graphics_constants_set) { if (!graphics_constants_set) {
glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT); glUniform1i(glGetUniformLocation(program_id(GRAPHICS_PROGRAM), "image"), GRAPHICS_UNIT);
@ -312,34 +314,55 @@ draw_all_cells(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) {
} }
static void static void
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen) { draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window) {
(void)vao_idx; (void)gvao_idx; (void)screen; if (!os_window->offscreen_texture_id) {
/* bind_program(CELL_BACKGROUND_PROGRAM); */ glGenTextures(1, &os_window->offscreen_texture_id);
/* glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); */ glBindTexture(GL_TEXTURE_2D, os_window->offscreen_texture_id);
/* glEnable(GL_BLEND); */ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, os_window->viewport_width, os_window->viewport_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
/* glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
/* */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
/* if (screen->grman->num_of_negative_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs); */ }
/* */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, offscreen_framebuffer);
/* bind_program(CELL_SPECIAL_PROGRAM); */ glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, os_window->offscreen_texture_id, 0);
/* glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); */ /* if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fatal("offscreen framebuffer not complete"); */
/* */
/* bind_program(CELL_FOREGROUND_PROGRAM); */ bind_program(CELL_BG_PROGRAM);
/* glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns); */ glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
/* */ glEnable(GL_BLEND);
/* if (screen->grman->num_of_positive_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs); */ if (screen->grman->num_of_negative_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_negative_refs);
/* glDisable(GL_BLEND); */
bind_program(CELL_SPECIAL_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
bind_program(CELL_FG_PROGRAM);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
if (screen->grman->num_of_positive_refs) draw_graphics(vao_idx, gvao_idx, screen->grman->render_data, screen->grman->num_of_negative_refs, screen->grman->num_of_positive_refs);
glDisable(GL_BLEND);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Now render the framebuffer to the screen reversing alpha pre-multiplication
glEnable(GL_SCISSOR_TEST);
bind_program(BLIT_PROGRAM); bind_vertex_array(blit_vertex_array);
static bool blit_constants_set = false;
if (!blit_constants_set) {
glUniform1i(glGetUniformLocation(program_id(BLIT_PROGRAM), "image"), BLIT_UNIT);
blit_constants_set = true;
}
glActiveTexture(GL_TEXTURE0 + BLIT_UNIT);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_SCISSOR_TEST);
} }
void void
draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) { draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GLfloat dx, GLfloat dy, Screen *screen, OSWindow *os_window) {
cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy); cell_prepare_to_render(vao_idx, gvao_idx, screen, xstart, ystart, dx, dy);
GLfloat h = (GLfloat)screen->lines * dy; GLfloat w = (GLfloat)screen->columns * dx, h = (GLfloat)screen->lines * dy;
#define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x)) #define SCALE(w, x) ((GLfloat)(os_window->viewport_##w) * (GLfloat)(x))
glScissor( glScissor(
(GLint)(SCALE(width, (xstart + 1.0f) / 2.0f)), (GLint)(SCALE(width, (xstart + 1.0f) / 2.0f)),
(GLint)(SCALE(height, ((ystart - h) + 1.0f) / 2.0f)), (GLint)(SCALE(height, ((ystart - h) + 1.0f) / 2.0f)),
(GLsizei)(ceilf(SCALE(width, (float)screen->columns * dx / 2.0f))), (GLsizei)(ceilf(SCALE(width, w / 2.0f))),
(GLsizei)(ceilf(SCALE(height, h / 2.0f))) (GLsizei)(ceilf(SCALE(height, h / 2.0f)))
); );
#undef SCALE #undef SCALE
@ -350,7 +373,7 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL
cell_constants_set = true; cell_constants_set = true;
} }
bool needs_complex_rendering = screen->grman->num_of_negative_refs || (screen->grman->num_of_positive_refs && os_window->is_semi_transparent); bool needs_complex_rendering = screen->grman->num_of_negative_refs || (screen->grman->num_of_positive_refs && os_window->is_semi_transparent);
if (needs_complex_rendering) draw_cells_interleaved(vao_idx, gvao_idx, screen); if (needs_complex_rendering) draw_cells_interleaved(vao_idx, gvao_idx, screen, os_window);
else draw_all_cells(vao_idx, gvao_idx, screen); else draw_all_cells(vao_idx, gvao_idx, screen);
} }
// }}} // }}}
@ -527,7 +550,7 @@ static PyMethodDef module_methods[] = {
bool bool
init_shaders(PyObject *module) { init_shaders(PyObject *module) {
#define C(x) if (PyModule_AddIntConstant(module, #x, x) != 0) { PyErr_NoMemory(); return false; } #define C(x) if (PyModule_AddIntConstant(module, #x, x) != 0) { PyErr_NoMemory(); return false; }
C(CELL_PROGRAM); C(CELL_BG_PROGRAM); C(CELL_SPECIAL_PROGRAM); C(CELL_FG_PROGRAM); C(CURSOR_PROGRAM); C(BORDERS_PROGRAM); C(GRAPHICS_PROGRAM); C(CELL_PROGRAM); C(CELL_BG_PROGRAM); C(CELL_SPECIAL_PROGRAM); C(CELL_FG_PROGRAM); C(CURSOR_PROGRAM); C(BORDERS_PROGRAM); C(GRAPHICS_PROGRAM); C(BLIT_PROGRAM);
C(GLSL_VERSION); C(GLSL_VERSION);
C(GL_VERSION); C(GL_VERSION);
C(GL_VENDOR); C(GL_VENDOR);

View File

@ -174,6 +174,7 @@ destroy_os_window_item(OSWindow *w) {
remove_tab_inner(w, tab->id); remove_tab_inner(w, tab->id);
} }
Py_CLEAR(w->window_title); Py_CLEAR(w->tab_bar_render_data.screen); Py_CLEAR(w->window_title); Py_CLEAR(w->tab_bar_render_data.screen);
if (w->offscreen_texture_id) free_texture(&w->offscreen_texture_id);
remove_vao(w->tab_bar_render_data.vao_idx); remove_vao(w->tab_bar_render_data.vao_idx);
free(w->tabs); w->tabs = NULL; free(w->tabs); w->tabs = NULL;
} }

View File

@ -103,6 +103,7 @@ typedef struct {
double last_resize_at; double last_resize_at;
bool has_pending_resizes; bool has_pending_resizes;
bool is_semi_transparent; bool is_semi_transparent;
uint32_t offscreen_texture_id;
} OSWindow; } OSWindow;
@ -159,7 +160,7 @@ ssize_t create_graphics_vao();
ssize_t create_border_vao(); ssize_t create_border_vao();
void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *); void draw_cells(ssize_t, ssize_t, float, float, float, float, Screen *, OSWindow *);
void draw_cursor(CursorRenderInfo *, bool); void draw_cursor(CursorRenderInfo *, bool);
void update_surface_size(int, int); void update_surface_size(int, int, uint32_t);
void free_texture(uint32_t*); void free_texture(uint32_t*);
void send_image_to_gpu(uint32_t*, const void*, int32_t, int32_t, bool, bool); void send_image_to_gpu(uint32_t*, const void*, int32_t, int32_t, bool, bool);
void send_sprite_to_gpu(unsigned int, unsigned int, unsigned int, uint8_t*); void send_sprite_to_gpu(unsigned int, unsigned int, unsigned int, uint8_t*);

View File

@ -12,7 +12,7 @@ from .constants import (
ScreenGeometry, WindowGeometry, appname, get_boss, wakeup ScreenGeometry, WindowGeometry, appname, get_boss, wakeup
) )
from .fast_data_types import ( from .fast_data_types import (
BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_BG_PROGRAM, BLIT_PROGRAM, BRACKETED_PASTE_END, BRACKETED_PASTE_START, CELL_BG_PROGRAM,
CELL_FG_PROGRAM, CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CURSOR_PROGRAM, CELL_FG_PROGRAM, CELL_PROGRAM, CELL_SPECIAL_PROGRAM, CURSOR_PROGRAM,
GRAPHICS_PROGRAM, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen, GRAPHICS_PROGRAM, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE, Screen,
add_window, compile_program, glfw_post_empty_event, init_cell_program, add_window, compile_program, glfw_post_empty_event, init_cell_program,
@ -54,6 +54,7 @@ def calculate_gl_geometry(window_geometry, viewport_width, viewport_height, cell
def load_shader_programs(semi_transparent=0): def load_shader_programs(semi_transparent=0):
v, f = load_shaders('cell') v, f = load_shaders('cell')
compile_program(GRAPHICS_PROGRAM, *load_shaders('graphics')) compile_program(GRAPHICS_PROGRAM, *load_shaders('graphics'))
compile_program(BLIT_PROGRAM, *load_shaders('blit'))
for which, p in { for which, p in {
'SIMPLE': CELL_PROGRAM, 'SIMPLE': CELL_PROGRAM,
'BACKGROUND': CELL_BG_PROGRAM, 'BACKGROUND': CELL_BG_PROGRAM,