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