int uterm_drm3d_display_fill(struct uterm_display *disp, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, unsigned int width, unsigned int height) { struct uterm_drm3d_video *v3d; unsigned int sw, sh, tmp, i; float mat[16]; float vertices[6 * 2], colors[6 * 4]; int ret; v3d = uterm_drm_video_get_data(disp->video); ret = uterm_drm3d_display_use(disp, NULL); if (ret) return ret; ret = init_shaders(disp->video); if (ret) return ret; sw = uterm_drm_mode_get_width(disp->current_mode); sh = uterm_drm_mode_get_height(disp->current_mode); for (i = 0; i < 6; ++i) { colors[i * 4 + 0] = r / 255.0; colors[i * 4 + 1] = g / 255.0; colors[i * 4 + 2] = b / 255.0; colors[i * 4 + 3] = 1.0; } vertices[0] = -1.0; vertices[1] = -1.0; vertices[2] = -1.0; vertices[3] = +1.0; vertices[4] = +1.0; vertices[5] = +1.0; vertices[6] = -1.0; vertices[7] = -1.0; vertices[8] = +1.0; vertices[9] = +1.0; vertices[10] = +1.0; vertices[11] = -1.0; tmp = x + width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; tmp = y + height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; /* Caution: * opengl uses a coordinate system with the origin at _lower-left_ corner * and positive y-axis up, while other parts uses a coordinate system * with the origin at _upper-left_ corner and positive y-axis down. */ y = sh - y; // invert y-axis y -= height; // move origin to lower left corner glViewport(x, y, width, height); glDisable(GL_BLEND); gl_shader_use(v3d->fill_shader); gl_m4_identity(mat); glUniformMatrix4fv(v3d->uni_fill_proj, 1, GL_FALSE, mat); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); if (gl_has_error(v3d->fill_shader)) { log_warning("GL error"); return -EFAULT; } return 0; }
static int display_blend(struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y, uint8_t fr, uint8_t fg, uint8_t fb, uint8_t br, uint8_t bg, uint8_t bb) { struct uterm_drm3d_video *v3d; unsigned int sw, sh, tmp, width, height, i; float mat[16]; float vertices[6 * 2], texpos[6 * 2], fgcol[3], bgcol[3]; int ret; uint8_t *packed, *src, *dst; if (!buf || buf->format != UTERM_FORMAT_GREY) return -EINVAL; v3d = uterm_drm_video_get_data(disp->video); ret = uterm_drm3d_display_use(disp, NULL); if (ret) return ret; ret = init_shaders(disp->video); if (ret) return ret; sw = uterm_drm_mode_get_width(disp->current_mode); sh = uterm_drm_mode_get_height(disp->current_mode); vertices[0] = -1.0; vertices[1] = -1.0; vertices[2] = -1.0; vertices[3] = +1.0; vertices[4] = +1.0; vertices[5] = +1.0; vertices[6] = -1.0; vertices[7] = -1.0; vertices[8] = +1.0; vertices[9] = +1.0; vertices[10] = +1.0; vertices[11] = -1.0; texpos[0] = 0.0; texpos[1] = 1.0; texpos[2] = 0.0; texpos[3] = 0.0; texpos[4] = 1.0; texpos[5] = 0.0; texpos[6] = 0.0; texpos[7] = 1.0; texpos[8] = 1.0; texpos[9] = 0.0; texpos[10] = 1.0; texpos[11] = 1.0; fgcol[0] = fr / 255.0; fgcol[1] = fg / 255.0; fgcol[2] = fb / 255.0; bgcol[0] = br / 255.0; bgcol[1] = bg / 255.0; bgcol[2] = bb / 255.0; tmp = x + buf->width; if (tmp < x || x >= sw) return -EINVAL; if (tmp > sw) width = sw - x; else width = buf->width; tmp = y + buf->height; if (tmp < y || y >= sh) return -EINVAL; if (tmp > sh) height = sh - y; else height = buf->height; glViewport(x, sh - y - height, width, height); glDisable(GL_BLEND); gl_shader_use(v3d->blend_shader); gl_m4_identity(mat); glUniformMatrix4fv(v3d->uni_blend_proj, 1, GL_FALSE, mat); glUniform3fv(v3d->uni_blend_fgcol, 1, fgcol); glUniform3fv(v3d->uni_blend_bgcol, 1, bgcol); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, v3d->tex); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (v3d->supports_rowlen) { glPixelStorei(GL_UNPACK_ROW_LENGTH, buf->stride); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf->data); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } else if (buf->stride == width) { glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf->data); } else { packed = malloc(width * height); if (!packed) return -ENOMEM; src = buf->data; dst = packed; for (i = 0; i < height; ++i) { memcpy(dst, src, width); dst += width; src += buf->stride; } glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, packed); free(packed); } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glUniform1i(v3d->uni_blend_tex, 0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texpos); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glDrawArrays(GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); if (gl_has_error(v3d->blend_shader)) { log_warning("GL error"); return -EFAULT; } return 0; }
static int set_outputs(struct uterm_video *video) { struct uterm_display *iter; int j, ret; struct gl_shader *shader; struct uterm_screen *screen; ret = gl_shader_new(&shader); if (ret) { log_err("Cannot create shader: %d", ret); return ret; } j = 0; iter = uterm_video_get_displays(video); for ( ; iter; iter = uterm_display_next(iter)) { log_notice("Activating display %d %p...", j, iter); ret = uterm_display_activate(iter, NULL); if (ret) log_err("Cannot activate display %d: %d", j, ret); else log_notice("Successfully activated display %d", j); ret = uterm_display_set_dpms(iter, UTERM_DPMS_ON); if (ret) log_err("Cannot set DPMS to ON: %d", ret); ++j; } iter = uterm_video_get_displays(video); for ( ; iter; iter = uterm_display_next(iter)) { if (uterm_display_get_state(iter) != UTERM_DISPLAY_ACTIVE) continue; ret = uterm_screen_new_single(&screen, iter); if (ret) { log_err("Cannot create temp-screen object: %d", ret); continue; } ret = uterm_screen_use(screen); if (ret) { log_err("Cannot use screen: %d", ret); uterm_screen_unref(screen); continue; } glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, uterm_screen_width(screen), uterm_screen_height(screen)); gl_shader_draw_def(shader, d_vert, d_col, 6); if (gl_has_error()) log_err("GL error occurred"); ret = uterm_screen_swap(screen); if (ret) { log_err("Cannot swap screen: %d", ret); uterm_screen_unref(screen); continue; } log_notice("Successfully set screen on display %p", iter); uterm_screen_unref(screen); } log_notice("Waiting 5 seconds..."); ev_eloop_run(eloop, 5000); log_notice("Exiting..."); gl_shader_unref(shader); return 0; }
static int gltex_set(struct kmscon_text *txt) { struct gltex *gt = txt->data; int ret; static char *attr[] = { "position", "texture_position", "fgcolor", "bgcolor" }; GLint s; const char *ext; struct uterm_mode *mode; bool opengl; memset(gt, 0, sizeof(*gt)); shl_dlist_init(>->atlases); ret = shl_hashtable_new(>->glyphs, shl_direct_hash, shl_direct_equal, NULL, free_glyph); if (ret) return ret; ret = shl_hashtable_new(>->bold_glyphs, shl_direct_hash, shl_direct_equal, NULL, free_glyph); if (ret) goto err_htable; ret = uterm_display_use(txt->disp, &opengl); if (ret < 0 || !opengl) { if (ret == -EOPNOTSUPP) log_error("display doesn't support hardware-acceleration"); goto err_bold_htable; } gl_clear_error(); ret = gl_shader_new(>->shader, gl_static_gltex_vert, gl_static_gltex_frag, attr, 4, log_llog, NULL); if (ret) goto err_bold_htable; gt->uni_proj = gl_shader_get_uniform(gt->shader, "projection"); gt->uni_atlas = gl_shader_get_uniform(gt->shader, "atlas"); gt->uni_advance_htex = gl_shader_get_uniform(gt->shader, "advance_htex"); gt->uni_advance_vtex = gl_shader_get_uniform(gt->shader, "advance_vtex"); if (gl_has_error(gt->shader)) { log_warning("cannot create shader"); goto err_shader; } mode = uterm_display_get_current(txt->disp); gt->sw = uterm_mode_get_width(mode); gt->sh = uterm_mode_get_height(mode); txt->cols = gt->sw / FONT_WIDTH(txt); txt->rows = gt->sh / FONT_HEIGHT(txt); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s); if (s <= 0) s = 64; else if (s > 2048) s = 2048; gt->max_tex_size = s; gl_clear_error(); ext = (const char*)glGetString(GL_EXTENSIONS); if (ext && strstr((const char*)ext, "GL_EXT_unpack_subimage")) { gt->supports_rowlen = true; } else { log_warning("your GL implementation does not support GL_EXT_unpack_subimage, glyph-rendering may be slower than usual"); } return 0; err_shader: gl_shader_unref(gt->shader); err_bold_htable: shl_hashtable_free(gt->bold_glyphs); err_htable: shl_hashtable_free(gt->glyphs); return ret; }
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; }