1#include "fb.h"
2#include "internal.h"
3#include "output.h"
4#include "pointer.h"
5#include "screen.h"
6#include "seat.h"
7#include "util.h"
8
9#include <stdlib.h>
10#include <string.h>
11#include <wayland-server.h>
12#include <wld/pixman.h>
13#include <wld/wld.h>
14
15struct swc_fb swc_fb;
16
17/* for the cursor */
18static uint32_t
19blend(uint32_t background, uint32_t foreground)
20{
21 uint32_t alpha = foreground >> 24;
22 uint32_t inverse = 255 - alpha;
23 uint32_t red = ((foreground >> 16) & 0xff) +
24 (((background >> 16) & 0xff) * inverse + 127) / 255;
25 uint32_t green = ((foreground >> 8) & 0xff) +
26 (((background >> 8) & 0xff) * inverse + 127) / 255;
27 uint32_t blue = (foreground & 0xff) +
28 ((background & 0xff) * inverse + 127) / 255;
29 return (MIN(red, 255) << 16) | (MIN(green, 255) << 8) | MIN(blue, 255);
30}
31
32bool
33fb_initialize(void)
34{
35 if (!framebuffer_initialize(&swc_fb)) {
36 return false;
37 }
38 swc_fb.pitch = (size_t)swc_fb.width * sizeof(*swc_fb.pixels);
39 swc_fb.pixels = calloc(swc_fb.height, swc_fb.pitch);
40 if (!swc_fb.pixels) {
41 goto error0;
42 }
43 swc_fb.backend.context = wld_pixman_create_context();
44 if (!swc_fb.backend.context) {
45 goto error1;
46 }
47 swc_fb.backend.renderer = wld_create_renderer(swc_fb.backend.context);
48 if (!swc_fb.backend.renderer) {
49 goto error2;
50 }
51 swc_fb.backend.cursor_width = 64;
52 swc_fb.backend.cursor_height = 64;
53 swc.backend = &swc_fb.backend;
54 return true;
55
56error2:
57 wld_destroy_context(swc_fb.backend.context);
58error1:
59 free(swc_fb.pixels);
60error0:
61 framebuffer_finalize(&swc_fb);
62 return false;
63}
64
65void
66fb_finalize(void)
67{
68 wld_destroy_renderer(swc_fb.backend.renderer);
69 wld_destroy_context(swc_fb.backend.context);
70 free(swc_fb.pixels);
71 framebuffer_finalize(&swc_fb);
72}
73
74bool
75fb_create_screens(struct wl_list *screens)
76{
77 struct output *output;
78 struct screen *screen;
79
80 output = output_new_fb(swc_fb.width, swc_fb.height, framebuffer_name());
81 if (!output) {
82 return false;
83 }
84 screen = screen_new(output);
85 if (!screen) {
86 output_destroy(output);
87 return false;
88 }
89 screen->id = 0;
90 output->screen = screen;
91 wl_list_insert(screens, &screen->link);
92 return true;
93}
94
95bool
96fb_present(struct wld_buffer *buffer, int32_t origin_x, int32_t origin_y)
97{
98 struct pointer *pointer = swc.seat ? swc.seat->pointer : NULL;
99 struct wld_buffer *cursor = NULL;
100 int32_t cursor_x = 0, cursor_y = 0;
101 uint32_t width, height, x, y;
102 bool cursor_mapped = false;
103
104 if (!buffer || !wld_map(buffer)) {
105 return false;
106 }
107 if (pointer && pointer->cursor.view.buffer) {
108 cursor = pointer->cursor.buffer;
109 cursor_x = pointer->cursor.view.geometry.x - origin_x;
110 cursor_y = pointer->cursor.view.geometry.y - origin_y;
111 cursor_mapped = wld_map(cursor);
112 }
113
114 width = buffer->width < swc_fb.width ? buffer->width : swc_fb.width;
115 height = buffer->height < swc_fb.height ? buffer->height : swc_fb.height;
116 if (width != swc_fb.width || height != swc_fb.height) {
117 memset(swc_fb.pixels, 0, swc_fb.height * swc_fb.pitch);
118 }
119 for (y = 0; y < height; ++y) {
120 uint32_t *source = (uint32_t *)((uint8_t *)buffer->map +
121 (size_t)y * buffer->pitch);
122 uint32_t *destination = (uint32_t *)((uint8_t *)swc_fb.pixels +
123 (size_t)y * swc_fb.pitch);
124 for (x = 0; x < width; ++x) {
125 uint32_t pixel = source[x];
126 int32_t cx = (int32_t)x - cursor_x;
127 int32_t cy = (int32_t)y - cursor_y;
128 if (cursor_mapped && cx >= 0 && cy >= 0 &&
129 (uint32_t)cx < cursor->width && (uint32_t)cy < cursor->height) {
130 uint32_t foreground = *(uint32_t *)((uint8_t *)cursor->map +
131 (size_t)cy * cursor->pitch + (size_t)cx * 4);
132 pixel = blend(pixel, foreground);
133 }
134 destination[x] = pixel;
135 }
136 }
137 if (cursor_mapped) {
138 wld_unmap(cursor);
139 }
140 wld_unmap(buffer);
141 return framebuffer_present(&swc_fb);
142}