Beispiel #1
0
void gl_shader_unref(struct gl_shader *shader)
{
	if (!shader || !shader->ref || --shader->ref)
		return;

	llog_debug(shader, "free shader");

	glDeleteProgram(shader->program);
	glDeleteShader(shader->fshader);
	glDeleteShader(shader->vshader);
	free(shader);
}
Beispiel #2
0
SHL_EXPORT
void uvt_ctx_unref(struct uvt_ctx *ctx)
{
	if (!ctx || !ctx->ref || --ctx->ref)
		return;

	llog_debug(ctx, "free ctx %p", ctx);

	shl_flagset_free(ctx->minors);
	free(ctx->cuse_file);
	ev_eloop_unref(ctx->eloop);
	free(ctx);
}
Beispiel #3
0
SHL_EXPORT
int uvt_ctx_new(struct uvt_ctx **out, uvt_log_t log, void *log_data)
{
	struct uvt_ctx *ctx;
	int ret;

	if (!out)
		return llog_dEINVAL(log, log_data);

	ctx = malloc(sizeof(*ctx));
	if (!ctx)
		return llog_dENOMEM(log, log_data);
	memset(ctx, 0, sizeof(*ctx));
	ctx->ref = 1;
	ctx->llog = log;
	ctx->llog_data = log_data;

	/* Default major/minor uses the TTY_MAJOR number with an offset of 2^15
	 * to avoid ID-clashes with any in-kernel TTY driver. As kernel drivers
	 * use static IDs only, a lower number would be fine, too, but lets be
	 * safe and just use high numbers. */
	ctx->major = TTY_MAJOR;
	ctx->minor_offset = 16384;

	llog_debug(ctx, "new ctx %p", ctx);

	ret = ev_eloop_new(&ctx->eloop, ctx->llog, ctx->llog_data);
	if (ret)
		goto err_free;

	ctx->cuse_file = strdup("/dev/cuse");
	if (!ctx->cuse_file) {
		ret = llog_ENOMEM(ctx);
		goto err_eloop;
	}

	ret = shl_flagset_new(&ctx->minors);
	if (ret)
		goto err_file;

	*out = ctx;
	return 0;

err_file:
	free(ctx->cuse_file);
err_eloop:
	ev_eloop_unref(ctx->eloop);
err_free:
	free(ctx);
	return ret;
}
Beispiel #4
0
SHL_EXPORT
int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data)
{
	struct tsm_screen *con;
	int ret;
	unsigned int i;

	if (!out)
		return -EINVAL;

	con = malloc(sizeof(*con));
	if (!con)
		return -ENOMEM;

	memset(con, 0, sizeof(*con));
	con->ref = 1;
	con->llog = log;
	con->llog_data = log_data;
	con->age_cnt = 1;
	con->age = con->age_cnt;
	con->def_attr.fr = 255;
	con->def_attr.fg = 255;
	con->def_attr.fb = 255;

	ret = tsm_symbol_table_new(&con->sym_table);
	if (ret)
		goto err_free;

	ret = tsm_screen_resize(con, 80, 24);
	if (ret)
		goto err_free;

	llog_debug(con, "new screen");
	*out = con;

	return 0;

err_free:
	for (i = 0; i < con->line_num; ++i) {
		line_free(con->main_lines[i]);
		line_free(con->alt_lines[i]);
	}
	free(con->main_lines);
	free(con->alt_lines);
	free(con->tab_ruler);
	tsm_symbol_table_unref(con->sym_table);
	free(con);
	return ret;
}
Beispiel #5
0
void tsm_screen_unref(struct tsm_screen *con)
{
	unsigned int i;

	if (!con || !con->ref || --con->ref)
		return;

	llog_debug(con, "destroying screen");

	for (i = 0; i < con->line_num; ++i)
		line_free(con->lines[i]);
	free(con->lines);
	free(con->tab_ruler);
	shl_timer_free(con->timer);
	free(con);
}
Beispiel #6
0
int tsm_screen_new(struct tsm_screen **out, tsm_log_t log)
{
	struct tsm_screen *con;
	int ret;
	unsigned int i;

	if (!out)
		return -EINVAL;

	con = malloc(sizeof(*con));
	if (!con)
		return -ENOMEM;

	memset(con, 0, sizeof(*con));
	con->ref = 1;
	con->llog = log;
	con->def_attr.fr = 255;
	con->def_attr.fg = 255;
	con->def_attr.fb = 255;

	ret = shl_timer_new(&con->timer);
	if (ret)
		goto err_free;

	ret = tsm_screen_resize(con, 80, 24);
	if (ret)
		goto err_timer;

	llog_debug(con, "new screen");
	*out = con;

	return 0;

err_timer:
	shl_timer_free(con->timer);
	for (i = 0; i < con->line_num; ++i) {
		line_free(con->main_lines[i]);
		line_free(con->alt_lines[i]);
	}
	free(con->main_lines);
	free(con->alt_lines);
	free(con->tab_ruler);
err_free:
	free(con);
	return ret;
}
Beispiel #7
0
SHL_EXPORT
void tsm_screen_unref(struct tsm_screen *con)
{
	unsigned int i;

	if (!con || !con->ref || --con->ref)
		return;

	llog_debug(con, "destroying screen");

	for (i = 0; i < con->line_num; ++i) {
		line_free(con->main_lines[i]);
		line_free(con->alt_lines[i]);
	}
	free(con->main_lines);
	free(con->alt_lines);
	free(con->tab_ruler);
	tsm_symbol_table_unref(con->sym_table);
	free(con);
}
Beispiel #8
0
SHL_EXPORT
tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb,
			  void *data)
{
	unsigned int cur_x, cur_y;
	unsigned int i, j, k;
	struct line *iter, *line = NULL;
	struct cell *cell, empty;
	struct tsm_screen_attr attr;
	int ret, warned = 0;
	const uint32_t *ch;
	size_t len;
	bool in_sel = false, sel_start = false, sel_end = false;
	bool was_sel = false;
	tsm_age_t age;

	if (!con || !draw_cb)
		return 0;

	screen_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;

	/* push each character into rendering pipeline */

	iter = con->sb_pos;
	k = 0;

	if (con->sel_active) {
		if (!con->sel_start.line && con->sel_start.y == SELECTION_TOP)
			in_sel = !in_sel;
		if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP)
			in_sel = !in_sel;

		if (con->sel_start.line &&
		    (!iter || con->sel_start.line->sb_id < iter->sb_id))
			in_sel = !in_sel;
		if (con->sel_end.line &&
		    (!iter || con->sel_end.line->sb_id < iter->sb_id))
			in_sel = !in_sel;
	}

	for (i = 0; i < con->size_y; ++i) {
		if (iter) {
			line = iter;
			iter = iter->next;
		} else {
			line = con->lines[k];
			k++;
		}

		if (con->sel_active) {
			if (con->sel_start.line == line ||
			    (!con->sel_start.line &&
			     con->sel_start.y == k - 1))
				sel_start = true;
			else
				sel_start = false;
			if (con->sel_end.line == line ||
			    (!con->sel_end.line &&
			     con->sel_end.y == k - 1))
				sel_end = true;
			else
				sel_end = false;

			was_sel = false;
		}

		for (j = 0; j < con->size_x; ++j) {
			if (j < line->size)
				cell = &line->cells[j];
			else
				cell = &empty;

			memcpy(&attr, &cell->attr, sizeof(attr));

			if (con->sel_active) {
				if (sel_start &&
				    j == con->sel_start.x) {
					was_sel = in_sel;
					in_sel = !in_sel;
				}
				if (sel_end &&
				    j == con->sel_end.x) {
					was_sel = in_sel;
					in_sel = !in_sel;
				}
			}

			if (k == cur_y + 1 && j == cur_x &&
			    !(con->flags & TSM_SCREEN_HIDE_CURSOR))
                                attr.underline = !attr.underline;
                                //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;

			if (in_sel || was_sel) {
				was_sel = false;
				attr.inverse = !attr.inverse;
			}

			if (con->age_reset) {
				age = 0;
			} else {
				age = cell->age;
				if (line->age > age)
					age = line->age;
				if (con->age > age)
					age = con->age;
			}

			ch = tsm_symbol_get(con->sym_table, &cell->ch, &len);
			if (cell->ch == ' ' || cell->ch == 0)
				len = 0;
			ret = draw_cb(con, cell->ch, ch, len, cell->width,
				      j, i, &attr, age, 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 (con->age_reset) {
		con->age_reset = 0;
		return 0;
	} else {
		return con->age_cnt;
	}
}
Beispiel #9
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 = &empty;
			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);
}
Beispiel #10
0
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;
}