static int compile_shader(struct gl_shader *shader, GLenum type, const char *source) { char msg[512]; GLint status = 1; GLuint s; s = glCreateShader(type); if (s == GL_NONE) { llog_warning(shader, "cannot allocate GL shader"); return GL_NONE; } glShaderSource(s, 1, &source, NULL); glCompileShader(s); glGetShaderiv(s, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { msg[0] = 0; glGetShaderInfoLog(s, sizeof(msg), NULL, msg); llog_warning(shader, "cannot compile shader: %s", msg); return GL_NONE; } return s; }
static void screen_write(struct tsm_screen *con, unsigned int x, unsigned int y, tsm_symbol_t ch, unsigned int len, const struct tsm_screen_attr *attr) { struct line *line; unsigned int i; if (!len) return; if (x >= con->size_x || y >= con->size_y) { llog_warning(con, "writing beyond buffer boundary"); return; } line = con->lines[y]; if ((con->flags & TSM_SCREEN_INSERT_MODE) && (int)x < ((int)con->size_x - len)) { line->age = con->age_cnt; memmove(&line->cells[x + len], &line->cells[x], sizeof(struct cell) * (con->size_x - len - x)); } line->cells[x].age = con->age_cnt; line->cells[x].ch = ch; line->cells[x].width = len; memcpy(&line->cells[x].attr, attr, sizeof(*attr)); for (i = 1; i < len && i + x < con->size_x; ++i) { line->cells[x + i].age = con->age_cnt; line->cells[x + i].width = 0; } }
void tsm_screen_draw(struct tsm_screen *con, tsm_screen_prepare_cb prepare_cb, tsm_screen_draw_cb draw_cb, tsm_screen_render_cb render_cb, void *data) { unsigned int cur_x, cur_y; unsigned int i, j, k; struct line *iter, *line = NULL; struct cell *cell; struct tsm_screen_attr attr; bool cursor_done = false; int ret, warned = 0; uint64_t time_prep = 0, time_draw = 0, time_rend = 0; const uint32_t *ch; size_t len; struct cell empty; if (!con || !draw_cb) return; cell_init(con, &empty); cur_x = con->cursor_x; if (con->cursor_x >= con->size_x) cur_x = con->size_x - 1; cur_y = con->cursor_y; if (con->cursor_y >= con->size_y) cur_y = con->size_y - 1; /* render preparation */ if (prepare_cb) { if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) shl_timer_reset(con->timer); ret = prepare_cb(con, data); if (ret) { llog_warning(con, "cannot prepare text-renderer for rendering"); return; } if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) time_prep = shl_timer_elapsed(con->timer); } else { time_prep = 0; } /* push each character into rendering pipeline */ if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) shl_timer_reset(con->timer); iter = con->sb_pos; k = 0; for (i = 0; i < con->size_y; ++i) { if (iter) { line = iter; iter = iter->next; } else { line = con->lines[k]; k++; } for (j = 0; j < con->size_x; ++j) { if (j < line->size) cell = &line->cells[j]; else cell = ∅ memcpy(&attr, &cell->attr, sizeof(attr)); if (k == cur_y + 1 && j == cur_x) { cursor_done = true; if (!(con->flags & TSM_SCREEN_HIDE_CURSOR)) attr.inverse = !attr.inverse; } /* TODO: do some more sophisticated inverse here. When * INVERSE mode is set, we should instead just select * inverse colors instead of switching background and * foreground */ if (con->flags & TSM_SCREEN_INVERSE) attr.inverse = !attr.inverse; ch = tsm_symbol_get(NULL, &cell->ch, &len); if (cell->ch == ' ' || cell->ch == 0) len = 0; ret = draw_cb(con, cell->ch, ch, len, j, i, &attr, data); if (ret && warned++ < 3) { llog_debug(con, "cannot draw glyph at %ux%u via text-renderer", j, i); if (warned == 3) llog_debug(con, "suppressing further warnings during this rendering round"); } } if (k == cur_y + 1 && !cursor_done) { cursor_done = true; if (!(con->flags & TSM_SCREEN_HIDE_CURSOR)) { if (!(con->flags & TSM_SCREEN_INVERSE)) attr.inverse = !attr.inverse; draw_cb(con, 0, NULL, 0, cur_x, i, &attr, data); } } } if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) time_draw = shl_timer_elapsed(con->timer); /* perform final rendering steps */ if (render_cb) { if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) shl_timer_reset(con->timer); ret = render_cb(con, data); if (ret) llog_warning(con, "cannot render via text-renderer"); if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) time_rend = shl_timer_elapsed(con->timer); } else { time_rend = 0; } if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING) llog_debug(con, "timing: sum: %" PRIu64 " prepare: %" PRIu64 " draw: %" PRIu64 " render: %" PRIu64, time_prep + time_draw + time_rend, time_prep, time_draw, time_rend); }
int gl_shader_new(struct gl_shader **out, const char *vert, const char *frag, char **attr, size_t attr_count, llog_submit_t llog) { struct gl_shader *shader; int ret, i; char msg[512]; GLint status = 1; if (!out || !vert || !frag) return -EINVAL; shader = malloc(sizeof(*shader)); if (!shader) return -ENOMEM; memset(shader, 0, sizeof(*shader)); shader->ref = 1; shader->llog = llog; llog_debug(shader, "new shader"); shader->vshader = compile_shader(shader, GL_VERTEX_SHADER, vert); if (shader->vshader == GL_NONE) { ret = -EFAULT; goto err_free; } shader->fshader = compile_shader(shader, GL_FRAGMENT_SHADER, frag); if (shader->fshader == GL_NONE) { ret = -EFAULT; goto err_vshader; } shader->program = glCreateProgram(); glAttachShader(shader->program, shader->vshader); glAttachShader(shader->program, shader->fshader); for (i = 0; i < attr_count; ++i) glBindAttribLocation(shader->program, i, attr[i]); glLinkProgram(shader->program); glGetProgramiv(shader->program, GL_LINK_STATUS, &status); if (status == GL_FALSE) { msg[0] = 0; glGetProgramInfoLog(shader->program, sizeof(msg), NULL, msg); llog_warning(shader, "cannot link shader: %s", msg); ret = -EFAULT; goto err_link; } if (gl_has_error(shader)) { llog_warning(shader, "shader creation failed"); ret = -EFAULT; goto err_link; } *out = shader; return 0; err_link: glDeleteProgram(shader->program); glDeleteShader(shader->fshader); err_vshader: glDeleteShader(shader->vshader); err_free: free(shader); return ret; }