main shrub/neuswc / libswc / fb.c
  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}