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
13 gfx_surface* vc_gfx;
14 gfx_surface* vc_tb_gfx;
15
16 const gfx_font* vc_font;
17
vc_gfx_draw_char(vc_t * vc,vc_char_t ch,unsigned x,unsigned y,bool invert)18 void 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
35 static gfx_surface* vc_test_gfx;
36
vc_init_gfx(gfx_surface * test)37 zx_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
vc_gfx_invalidate_all(vc_t * vc)64 void 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
vc_gfx_invalidate_status()69 void vc_gfx_invalidate_status() {
70 gfx_copylines(vc_test_gfx, vc_tb_gfx, 0, 0, vc_tb_gfx->height);
71 }
72
vc_gfx_invalidate(vc_t * vc,unsigned x,unsigned y,unsigned w,unsigned h)73 void 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
vc_gfx_invalidate_region(vc_t * vc,unsigned x,unsigned y,unsigned w,unsigned h)83 void 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
92 static zx_handle_t vc_gfx_vmo = ZX_HANDLE_INVALID;
93 static uintptr_t vc_gfx_mem = 0;
94 static size_t vc_gfx_size = 0;
95
96 static zx_handle_t vc_hw_gfx_vmo = ZX_HANDLE_INVALID;
97 static gfx_surface* vc_hw_gfx = 0;
98 static uintptr_t vc_hw_gfx_mem = 0;
99
vc_free_gfx()100 void 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
vc_init_gfx(zx_handle_t fb_vmo,int32_t width,int32_t height,zx_pixel_format_t format,int32_t stride)127 zx_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
183 fail:
184 vc_free_gfx();
185 return r;
186 }
187
vc_gfx_invalidate_mem(size_t offset,size_t size)188 static 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
vc_gfx_invalidate_all(vc_t * vc)200 void 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
vc_gfx_invalidate_status()206 void 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
vc_gfx_invalidate_region(vc_t * vc,unsigned x,unsigned y,unsigned w,unsigned h)211 void 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
vc_gfx_invalidate(vc_t * vc,unsigned x,unsigned y,unsigned w,unsigned h)223 void 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