blob: 3fd5176e5be0ef96a419d41225e7070577f10405 [file] [log] [blame]
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -05001#include <stdint.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
5#include <i915_drm.h>
6#include <sys/ioctl.h>
7#include <math.h>
8#include <cairo.h>
9#include "cairo-util.h"
10
11struct buffer *
12buffer_create(int fd, int width, int height, int stride)
13{
14 struct buffer *buffer;
15 struct drm_i915_gem_create create;
16 struct drm_gem_flink flink;
17
18 buffer = malloc(sizeof *buffer);
19 buffer->width = width;
20 buffer->height = height;
21 buffer->stride = stride;
22
23 memset(&create, 0, sizeof(create));
24 create.size = height * stride;
25
26 if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
27 fprintf(stderr, "gem create failed: %m\n");
28 free(buffer);
29 return NULL;
30 }
31
32 flink.handle = create.handle;
33 if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
34 fprintf(stderr, "gem flink failed: %m\n");
35 free(buffer);
36 return 0;
37 }
38
39 buffer->handle = flink.handle;
40 buffer->name = flink.name;
41
42 return buffer;
43}
44
45int
46buffer_destroy(struct buffer *buffer, int fd)
47{
48 struct drm_gem_close close;
49
50 close.handle = buffer->handle;
51 if (ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) {
52 fprintf(stderr, "gem close failed: %m\n");
53 return -1;
54 }
55
56 free(buffer);
57
58 return 0;
59}
60
61int
62buffer_data(struct buffer *buffer, int fd, void *data)
63{
64 struct drm_i915_gem_pwrite pwrite;
65
66 pwrite.handle = buffer->handle;
67 pwrite.offset = 0;
68 pwrite.size = buffer->height * buffer->stride;
69 pwrite.data_ptr = (uint64_t) (uintptr_t) data;
70
71 if (ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite) < 0) {
72 fprintf(stderr, "gem pwrite failed: %m\n");
73 return -1;
74 }
75
76 return 0;
77}
78
79struct buffer *
80buffer_create_from_cairo_surface(int fd, cairo_surface_t *surface)
81{
82 struct buffer *buffer;
83 int32_t width, height, stride;
84 void *data;
85
86 width = cairo_image_surface_get_width(surface);
87 height = cairo_image_surface_get_height(surface);
88 stride = cairo_image_surface_get_stride(surface);
89 data = cairo_image_surface_get_data(surface);
90
91 buffer = buffer_create(fd, width, height, stride);
92 if (buffer == NULL)
93 return NULL;
94
95 if (buffer_data(buffer, fd, data) < 0) {
96 buffer_destroy(buffer, fd);
97 return NULL;
98 }
99
100 return buffer;
101}
102
Kristian Høgsberg87330262008-11-17 22:23:55 -0500103#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
104
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500105void
Kristian Høgsberg10bdd292008-11-08 23:27:27 -0500106blur_surface(cairo_surface_t *surface, int margin)
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500107{
108 cairo_surface_t *tmp;
109 int32_t width, height, stride, x, y, z, w;
110 uint8_t *src, *dst;
111 uint32_t *s, *d, a, p;
Kristian Høgsberg87330262008-11-17 22:23:55 -0500112 int i, j, k, size, half;
113 uint8_t kernel[10];
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500114 double f;
115
Kristian Høgsberg87330262008-11-17 22:23:55 -0500116 size = ARRAY_LENGTH(kernel);
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500117 width = cairo_image_surface_get_width(surface);
118 height = cairo_image_surface_get_height(surface);
119 stride = cairo_image_surface_get_stride(surface);
120 src = cairo_image_surface_get_data(surface);
121
122 tmp = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
123 dst = cairo_image_surface_get_data(tmp);
124
125 half = size / 2;
126 a = 0;
127 for (i = 0; i < size; i++) {
128 f = (i - half);
129 kernel[i] = exp(- f * f / 30.0) * 80;
130 a += kernel[i];
131 }
132
133 for (i = 0; i < height; i++) {
134 s = (uint32_t *) (src + i * stride);
135 d = (uint32_t *) (dst + i * stride);
136 for (j = 0; j < width; j++) {
Kristian Høgsberg87330262008-11-17 22:23:55 -0500137 if (margin < j && j < width - margin) {
138 d[j] = s[j];
Kristian Høgsberg10bdd292008-11-08 23:27:27 -0500139 continue;
Kristian Høgsberg87330262008-11-17 22:23:55 -0500140 }
141
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500142 x = 0;
143 y = 0;
144 z = 0;
145 w = 0;
146 for (k = 0; k < size; k++) {
147 if (j - half + k < 0 || j - half + k >= width)
148 continue;
149 p = s[j - half + k];
150
151 x += (p >> 24) * kernel[k];
152 y += ((p >> 16) & 0xff) * kernel[k];
153 z += ((p >> 8) & 0xff) * kernel[k];
154 w += (p & 0xff) * kernel[k];
155 }
156 d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
157 }
158 }
159
160 for (i = 0; i < height; i++) {
161 s = (uint32_t *) (dst + i * stride);
162 d = (uint32_t *) (src + i * stride);
163 for (j = 0; j < width; j++) {
Kristian Høgsberg87330262008-11-17 22:23:55 -0500164 if (margin <= i && i < height - margin) {
165 d[j] = s[j];
Kristian Høgsberg10bdd292008-11-08 23:27:27 -0500166 continue;
Kristian Høgsberg87330262008-11-17 22:23:55 -0500167 }
168
Kristian Høgsberg2f2cfae2008-11-08 22:46:30 -0500169 x = 0;
170 y = 0;
171 z = 0;
172 w = 0;
173 for (k = 0; k < size; k++) {
174 if (i - half + k < 0 || i - half + k >= height)
175 continue;
176 s = (uint32_t *) (dst + (i - half + k) * stride);
177 p = s[j];
178
179 x += (p >> 24) * kernel[k];
180 y += ((p >> 16) & 0xff) * kernel[k];
181 z += ((p >> 8) & 0xff) * kernel[k];
182 w += (p & 0xff) * kernel[k];
183 }
184 d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
185 }
186 }
187
188 cairo_surface_destroy(tmp);
189}