blob: a12d4820282e19e78738667b178cd2a9ea098a98 [file] [log] [blame]
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdint.h>
5#include <i915_drm.h>
6#include <sys/ioctl.h>
7#include <sys/mman.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <linux/fb.h>
11
12#include "wayland.h"
13
14#include <GL/gl.h>
15#include <eagle.h>
16
17#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
18
19struct egl_compositor {
20 struct wl_compositor base;
21 EGLDisplay display;
22 EGLSurface surface;
23 EGLContext context;
24 int gem_fd;
25};
26
27struct surface_data {
28 uint32_t handle;
29 int32_t width, height, stride;
30 GLuint texture;
31};
32
33void notify_surface_create(struct wl_compositor *compositor,
34 struct wl_surface *surface)
35{
36 struct surface_data *sd;
37
38 sd = malloc(sizeof *sd);
39 if (sd == NULL)
40 return;
41
42 sd->handle = 0;
43 wl_surface_set_data(surface, sd);
44
45 glGenTextures(1, &sd->texture);
46}
47
48void notify_surface_destroy(struct wl_compositor *compositor,
49 struct wl_surface *surface)
50{
51 struct egl_compositor *ec = (struct egl_compositor *) compositor;
52 struct surface_data *sd;
53 struct drm_gem_close close_arg;
54 int ret;
55
56 sd = wl_surface_get_data(surface);
57 if (sd == NULL || sd->handle == 0)
58 return;
59
60 close_arg.handle = sd->handle;
61 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
62 if (ret != 0) {
63 fprintf(stderr, "failed to gem_close handle %d: %m\n", sd->handle);
64 }
65
66 glDeleteTextures(1, &sd->texture);
67
68 free(sd);
69}
70
71void notify_surface_attach(struct wl_compositor *compositor,
72 struct wl_surface *surface, uint32_t name,
73 uint32_t width, uint32_t height, uint32_t stride)
74{
75 struct egl_compositor *ec = (struct egl_compositor *) compositor;
76 struct surface_data *sd;
77 struct drm_gem_open open_arg;
78 struct drm_gem_close close_arg;
79 struct drm_i915_gem_pread pread;
80 void *data;
81 uint32_t size;
82 int ret;
83
84 sd = wl_surface_get_data(surface);
85 if (sd == NULL)
86 return;
87
88 if (sd->handle != 0) {
89 close_arg.handle = sd->handle;
90 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
91 if (ret != 0) {
92 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
93 }
94 }
95
96 open_arg.name = name;
97 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
98 if (ret != 0) {
99 fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, ec->gem_fd);
100 return;
101 }
102
103 sd->handle = open_arg.handle;
104 sd->width = width;
105 sd->height = height;
106 sd->stride = stride;
107
108 size = sd->height * sd->stride;
109 data = malloc(size);
110 if (data == NULL) {
111 fprintf(stderr, "swap buffers malloc failed\n");
112 return;
113 }
114
115 pread.handle = sd->handle;
116 pread.pad = 0;
117 pread.offset = 0;
118 pread.size = size;
119 pread.data_ptr = (long) data;
120
121 if (ioctl(ec->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
122 fprintf(stderr, "gem pread failed");
123 return;
124 }
125
126 glBindTexture(GL_TEXTURE_2D, sd->texture);
127 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
128 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
129 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
130 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
131 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
132 GL_BGRA, GL_UNSIGNED_BYTE, data);
133
134 free(data);
135}
136
137void notify_surface_map(struct wl_compositor *compositor,
138 struct wl_surface *surface, struct wl_map *map)
139{
140 struct egl_compositor *ec = (struct egl_compositor *) compositor;
141 struct surface_data *sd;
142 GLint vertices[12] = {
143 map->x, map->y, 0.0,
144 map->x, map->y + map->height, 0.0,
145 map->x + map->width, map->y + map->height, 0.0,
146 map->x + map->width, map->y, 0.0
147 };
148 GLint tex_coords[8] = {
149 1, 0,
150 1, 1,
151 0, 1,
152 0, 0
153 };
154 GLuint indices[4] = { 0, 1, 2, 3 };
155
156 /* This part is where we actually copy the buffer to screen.
157 * Needs to be part of the repaint loop, not in the notify_map
158 * handler. */
159
160 sd = wl_surface_get_data(surface);
161 if (sd == NULL)
162 return;
163
164 glClear(GL_COLOR_BUFFER_BIT);
165 glBindTexture(GL_TEXTURE_2D, sd->texture);
166 glEnable(GL_TEXTURE_2D);
167 glEnable(GL_BLEND);
168 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
169
170 glEnableClientState(GL_VERTEX_ARRAY);
171 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
172 glVertexPointer(3, GL_INT, 0, vertices);
173 glTexCoordPointer(2, GL_INT, 0, tex_coords);
174 glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indices);
175
176 glFlush();
177
178 eglSwapBuffers(ec->display, ec->surface);
179}
180
181struct wl_compositor_interface interface = {
182 notify_surface_create,
183 notify_surface_destroy,
184 notify_surface_attach,
185 notify_surface_map
186};
187
188static const char gem_device[] = "/dev/dri/card0";
189
190struct wl_compositor *
191wl_compositor_create(void)
192{
193 EGLConfig configs[64];
194 EGLint major, minor, count;
195 struct egl_compositor *ec;
196 const int width = 800, height = 600;
197
198 ec = malloc(sizeof *ec);
199 if (ec == NULL)
200 return NULL;
201
202 ec->base.interface = &interface;
203
204 ec->display = eglCreateDisplay(gem_device, "i965");
205 if (ec->display == NULL) {
206 fprintf(stderr, "failed to create display\n");
207 return NULL;
208 }
209
210 if (!eglInitialize(ec->display, &major, &minor)) {
211 fprintf(stderr, "failed to initialize display\n");
212 return NULL;
213 }
214
215 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
216 fprintf(stderr, "failed to get configs\n");
217 return NULL;
218 }
219
220 ec->surface = eglCreateSurface(ec->display, configs[24], 0, 0, width, height);
221 if (ec->surface == NULL) {
222 fprintf(stderr, "failed to create surface\n");
223 return NULL;
224 }
225
226 ec->context = eglCreateContext(ec->display, configs[24], NULL, NULL);
227 if (ec->context == NULL) {
228 fprintf(stderr, "failed to create context\n");
229 return NULL;
230 }
231
232 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
233 fprintf(stderr, "failed to make context current\n");
234 return NULL;
235 }
236
237 glViewport(0, 0, width, height);
238 glMatrixMode(GL_PROJECTION);
239 glLoadIdentity();
240 glOrtho(0, width, height, 0, 0, 1000.0);
241 glMatrixMode(GL_MODELVIEW);
242 glClearColor(0.0, 0.1, 0.3, 0.0);
243
244 ec->gem_fd = open(gem_device, O_RDWR);
245 if (ec->gem_fd < 0) {
246 fprintf(stderr, "failed to open drm device\n");
247 return NULL;
248 }
249
250 return &ec->base;
251}