blob: 33de455489ac50cac40cc3c56f352fed41116922 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <gfx/gfx.h>
#include <zircon/device/display.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include "vc.h"
gfx_surface* vc_gfx;
gfx_surface* vc_tb_gfx;
const gfx_font* vc_font;
void vc_gfx_draw_char(vc_t* vc, vc_char_t ch, unsigned x, unsigned y,
bool invert) {
uint8_t fg_color = vc_char_get_fg_color(ch);
uint8_t bg_color = vc_char_get_bg_color(ch);
if (invert) {
// Swap the colors.
uint8_t temp = fg_color;
fg_color = bg_color;
bg_color = temp;
}
gfx_putchar(vc_gfx, vc->font, vc_char_get_char(ch),
x * vc->charw, y * vc->charh,
palette_to_color(vc, fg_color),
palette_to_color(vc, bg_color));
}
#if BUILD_FOR_TEST
static gfx_surface* vc_test_gfx;
zx_status_t vc_init_gfx(gfx_surface* test) {
const gfx_font* font = vc_get_font();
vc_font = font;
vc_test_gfx = test;
// init the status bar
vc_tb_gfx = gfx_create_surface(NULL, test->width, font->height,
test->stride, test->format, 0);
if (!vc_tb_gfx) {
return ZX_ERR_NO_MEMORY;
}
// init the main surface
vc_gfx = gfx_create_surface(NULL, test->width, test->height,
test->stride, test->format, 0);
if (!vc_gfx) {
gfx_surface_destroy(vc_tb_gfx);
vc_tb_gfx = NULL;
return ZX_ERR_NO_MEMORY;
}
return ZX_OK;
}
void vc_gfx_invalidate_all(vc_t* vc) {
gfx_copylines(vc_test_gfx, vc_tb_gfx, 0, 0, vc_tb_gfx->height);
gfx_copylines(vc_test_gfx, vc_gfx, 0, vc_tb_gfx->height, vc_gfx->height - vc_tb_gfx->height);
}
void vc_gfx_invalidate_status() {
gfx_copylines(vc_test_gfx, vc_tb_gfx, 0, 0, vc_tb_gfx->height);
}
void vc_gfx_invalidate(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {
unsigned desty = vc_tb_gfx->height + y * vc->charh;
if ((x == 0) && (w == vc->columns)) {
gfx_copylines(vc_test_gfx, vc_gfx, y * vc->charh, desty, h * vc->charh);
} else {
gfx_blend(vc_test_gfx, vc_gfx, x * vc->charw, y * vc->charh,
w * vc->charw, h * vc->charh, x * vc->charw, desty);
}
}
void vc_gfx_invalidate_region(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {
unsigned desty = vc_tb_gfx->height + y;
if ((x == 0) && (w == vc->columns)) {
gfx_copylines(vc_test_gfx, vc_gfx, y, desty, h);
} else {
gfx_blend(vc_test_gfx, vc_gfx, x, y, w, h, x, desty);
}
}
#else
static int vc_gfx_fd = -1;
static zx_handle_t vc_gfx_vmo = 0;
static uintptr_t vc_gfx_mem = 0;
static size_t vc_gfx_size = 0;
void vc_free_gfx() {
if (vc_gfx) {
gfx_surface_destroy(vc_gfx);
vc_gfx = NULL;
}
if (vc_tb_gfx) {
gfx_surface_destroy(vc_tb_gfx);
vc_tb_gfx = NULL;
}
if (vc_gfx_mem) {
zx_vmar_unmap(zx_vmar_root_self(), vc_gfx_mem, vc_gfx_size);
vc_gfx_mem = 0;
}
if (vc_gfx_fd >= 0) {
close(vc_gfx_fd);
vc_gfx_fd = -1;
}
}
zx_status_t vc_init_gfx(int fd) {
const gfx_font* font = vc_get_font();
vc_font = font;
ioctl_display_get_fb_t fb;
vc_gfx_fd = fd;
uintptr_t ptr;
zx_status_t r;
if (ioctl_display_get_fb(fd, &fb) < 0) {
printf("vc_alloc: cannot get fb from driver instance\n");
r = ZX_ERR_INTERNAL;
goto fail;
}
vc_gfx_vmo = fb.vmo;
vc_gfx_size = fb.info.stride * fb.info.pixelsize * fb.info.height;
if ((r = zx_vmar_map(zx_vmar_root_self(), 0, vc_gfx_vmo, 0, vc_gfx_size,
ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &vc_gfx_mem)) < 0) {
goto fail;
}
r = ZX_ERR_NO_MEMORY;
// init the status bar
if ((vc_tb_gfx = gfx_create_surface((void*) vc_gfx_mem, fb.info.width, font->height,
fb.info.stride, fb.info.format, 0)) == NULL) {
goto fail;
}
// init the main surface
ptr = vc_gfx_mem + fb.info.stride * font->height * fb.info.pixelsize;
if ((vc_gfx = gfx_create_surface((void*) ptr, fb.info.width, fb.info.height - font->height,
fb.info.stride, fb.info.format, 0)) == NULL) {
goto fail;
}
return ZX_OK;
fail:
vc_free_gfx();
return r;
}
void vc_gfx_invalidate_all(vc_t* vc) {
if (vc->active) {
ioctl_display_flush_fb(vc_gfx_fd);
}
}
void vc_gfx_invalidate_status() {
ioctl_display_region_t r = {
.x = 0,
.y = 0,
.width = vc_tb_gfx->width,
.height = vc_tb_gfx->height,
};
ioctl_display_flush_fb_region(vc_gfx_fd, &r);
}
// pixel coords
void vc_gfx_invalidate_region(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {
if (vc->active) {
ioctl_display_region_t r = {
.x = x,
.y = vc->charh + y,
.width = w,
.height = h,
};
ioctl_display_flush_fb_region(vc_gfx_fd, &r);
}
}
// text coords
void vc_gfx_invalidate(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {
if (vc->active) {
ioctl_display_region_t r = {
.x = x * vc->charw,
.y = vc->charh + y * vc->charh,
.width = w * vc->charw,
.height = h * vc->charh,
};
ioctl_display_flush_fb_region(vc_gfx_fd, &r);
}
}
#endif