1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <gfx/gfx.h> 6#include <string.h> 7 8#include <zircon/process.h> 9#include <zircon/syscalls.h> 10 11#include "vc.h" 12 13gfx_surface* vc_gfx; 14gfx_surface* vc_tb_gfx; 15 16const gfx_font* vc_font; 17 18void vc_gfx_draw_char(vc_t* vc, vc_char_t ch, unsigned x, unsigned y, 19 bool invert) { 20 uint8_t fg_color = vc_char_get_fg_color(ch); 21 uint8_t bg_color = vc_char_get_bg_color(ch); 22 if (invert) { 23 // Swap the colors. 24 uint8_t temp = fg_color; 25 fg_color = bg_color; 26 bg_color = temp; 27 } 28 gfx_putchar(vc_gfx, vc->font, vc_char_get_char(ch), 29 x * vc->charw, y * vc->charh, 30 palette_to_color(vc, fg_color), 31 palette_to_color(vc, bg_color)); 32} 33 34#if BUILD_FOR_TEST 35static gfx_surface* vc_test_gfx; 36 37zx_status_t vc_init_gfx(gfx_surface* test) { 38 const gfx_font* font = vc_get_font(); 39 vc_font = font; 40 41 vc_test_gfx = test; 42 43 // init the status bar 44 vc_tb_gfx = gfx_create_surface(NULL, test->width, font->height, 45 test->stride, test->format, 0); 46 if (!vc_tb_gfx) { 47 return ZX_ERR_NO_MEMORY; 48 } 49 50 // init the main surface 51 vc_gfx = gfx_create_surface(NULL, test->width, test->height, 52 test->stride, test->format, 0); 53 if (!vc_gfx) { 54 gfx_surface_destroy(vc_tb_gfx); 55 vc_tb_gfx = NULL; 56 return ZX_ERR_NO_MEMORY; 57 } 58 59 g_status_width = vc_gfx->width / font->width; 60 61 return ZX_OK; 62} 63 64void vc_gfx_invalidate_all(vc_t* vc) { 65 gfx_copylines(vc_test_gfx, vc_tb_gfx, 0, 0, vc_tb_gfx->height); 66 gfx_copylines(vc_test_gfx, vc_gfx, 0, vc_tb_gfx->height, vc_gfx->height - vc_tb_gfx->height); 67} 68 69void vc_gfx_invalidate_status() { 70 gfx_copylines(vc_test_gfx, vc_tb_gfx, 0, 0, vc_tb_gfx->height); 71} 72 73void vc_gfx_invalidate(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) { 74 unsigned desty = vc_tb_gfx->height + y * vc->charh; 75 if ((x == 0) && (w == vc->columns)) { 76 gfx_copylines(vc_test_gfx, vc_gfx, y * vc->charh, desty, h * vc->charh); 77 } else { 78 gfx_blend(vc_test_gfx, vc_gfx, x * vc->charw, y * vc->charh, 79 w * vc->charw, h * vc->charh, x * vc->charw, desty); 80 } 81} 82 83void vc_gfx_invalidate_region(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) { 84 unsigned desty = vc_tb_gfx->height + y; 85 if ((x == 0) && (w == vc->columns)) { 86 gfx_copylines(vc_test_gfx, vc_gfx, y, desty, h); 87 } else { 88 gfx_blend(vc_test_gfx, vc_gfx, x, y, w, h, x, desty); 89 } 90} 91#else 92static zx_handle_t vc_gfx_vmo = ZX_HANDLE_INVALID; 93static uintptr_t vc_gfx_mem = 0; 94static size_t vc_gfx_size = 0; 95 96static zx_handle_t vc_hw_gfx_vmo = ZX_HANDLE_INVALID; 97static gfx_surface* vc_hw_gfx = 0; 98static uintptr_t vc_hw_gfx_mem = 0; 99 100void vc_free_gfx() { 101 if (vc_gfx) { 102 gfx_surface_destroy(vc_gfx); 103 vc_gfx = NULL; 104 } 105 if (vc_tb_gfx) { 106 gfx_surface_destroy(vc_tb_gfx); 107 vc_tb_gfx = NULL; 108 } 109 if (vc_gfx_mem) { 110 zx_vmar_unmap(zx_vmar_root_self(), vc_gfx_mem, vc_gfx_size); 111 vc_gfx_mem = 0; 112 } 113 if (vc_gfx_vmo) { 114 zx_handle_close(vc_gfx_vmo); 115 vc_gfx_vmo = ZX_HANDLE_INVALID; 116 } 117 if (vc_hw_gfx_mem) { 118 zx_vmar_unmap(zx_vmar_root_self(), vc_hw_gfx_mem, vc_gfx_size); 119 vc_hw_gfx_mem = 0; 120 } 121 if (vc_hw_gfx_vmo) { 122 zx_handle_close(vc_hw_gfx_vmo); 123 vc_hw_gfx_vmo = ZX_HANDLE_INVALID; 124 } 125} 126 127zx_status_t vc_init_gfx(zx_handle_t fb_vmo, int32_t width, int32_t height, 128 zx_pixel_format_t format, int32_t stride) { 129 const gfx_font* font = vc_get_font(); 130 vc_font = font; 131 132 vc_gfx_size = stride * ZX_PIXEL_FORMAT_BYTES(format) * height; 133 134 zx_status_t r; 135 // If we can't efficiently read from the framebuffer VMO, create a secondary 136 // surface using a regular VMO and blit contents between the two. 137 if ((r = zx_vmo_set_cache_policy(fb_vmo, ZX_CACHE_POLICY_CACHED)) == ZX_ERR_BAD_STATE) { 138 if ((r = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 139 0, fb_vmo, 0, vc_gfx_size, &vc_hw_gfx_mem)) < 0) { 140 goto fail; 141 } 142 143 if ((vc_hw_gfx = gfx_create_surface((void*) vc_hw_gfx_mem, width, height, 144 stride, format, 0)) == NULL) { 145 r = ZX_ERR_INTERNAL; 146 goto fail; 147 } 148 149 vc_hw_gfx_vmo = fb_vmo; 150 151 if ((r = zx_vmo_create(vc_gfx_size, 0, &fb_vmo)) < 0) { 152 goto fail; 153 } 154 } else if (r != ZX_OK) { 155 goto fail; 156 } 157 158 uintptr_t ptr; 159 vc_gfx_vmo = fb_vmo; 160 if ((r = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 161 0, vc_gfx_vmo, 0, vc_gfx_size, &vc_gfx_mem)) < 0) { 162 goto fail; 163 } 164 165 r = ZX_ERR_NO_MEMORY; 166 // init the status bar 167 if ((vc_tb_gfx = gfx_create_surface((void*) vc_gfx_mem, width, font->height, 168 stride, format, 0)) == NULL) { 169 goto fail; 170 } 171 172 // init the main surface 173 ptr = vc_gfx_mem + stride * font->height * ZX_PIXEL_FORMAT_BYTES(format); 174 if ((vc_gfx = gfx_create_surface((void*) ptr, width, height - font->height, 175 stride, format, 0)) == NULL) { 176 goto fail; 177 } 178 179 g_status_width = vc_gfx->width / font->width; 180 181 return ZX_OK; 182 183fail: 184 vc_free_gfx(); 185 return r; 186} 187 188static void vc_gfx_invalidate_mem(size_t offset, size_t size) { 189 void* ptr; 190 if (vc_hw_gfx_mem) { 191 void* data_ptr = reinterpret_cast<void*>(vc_gfx_mem + offset); 192 ptr = reinterpret_cast<void*>(vc_hw_gfx_mem + offset); 193 memcpy(ptr, data_ptr, size); 194 } else { 195 ptr = reinterpret_cast<void*>(vc_gfx_mem + offset); 196 } 197 zx_cache_flush(ptr, size, ZX_CACHE_FLUSH_DATA); 198} 199 200void vc_gfx_invalidate_all(vc_t* vc) { 201 if (g_vc_owns_display || vc->active) { 202 vc_gfx_invalidate_mem(0, vc_gfx_size); 203 } 204} 205 206void vc_gfx_invalidate_status() { 207 vc_gfx_invalidate_mem(0, vc_tb_gfx->stride * vc_tb_gfx->height * vc_tb_gfx->pixelsize); 208} 209 210// pixel coords 211void vc_gfx_invalidate_region(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) { 212 if (!g_vc_owns_display || !vc->active) { 213 return; 214 } 215 uint32_t flush_size = w * vc_gfx->pixelsize; 216 size_t offset = vc_gfx->stride * (vc->charh + y) * vc_gfx->pixelsize; 217 for (unsigned i = 0; i < h; i++, offset += (vc_gfx->stride * vc_gfx->pixelsize)) { 218 vc_gfx_invalidate_mem(offset, flush_size); 219 } 220} 221 222// text coords 223void vc_gfx_invalidate(vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) { 224 vc_gfx_invalidate_region(vc, x * vc->charw, y * vc->charh, w * vc->charw, h * vc->charh); 225} 226#endif 227