Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / gallium / state_trackers / egl / egl_surface.c
1
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "egl_tracker.h"
6
7 #include "egllog.h"
8
9 #include "pipe/p_inlines.h"
10 #include "pipe/p_screen.h"
11 #include "pipe/p_context.h"
12
13 #include "state_tracker/drm_api.h"
14
15 #include "util/u_rect.h"
16
17 /*
18 * Util functions
19 */
20
21 static drmModeModeInfoPtr
22 drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode)
23 {
24 int i;
25 drmModeModeInfoPtr m = NULL;
26
27 for (i = 0; i < connector->count_modes; i++) {
28 m = &connector->modes[i];
29 if (m->hdisplay == mode->Width && m->vdisplay == mode->Height && m->vrefresh == mode->RefreshRate)
30 break;
31 m = &connector->modes[0]; /* if we can't find one, return first */
32 }
33
34 return m;
35 }
36
37 static struct st_framebuffer *
38 drm_create_framebuffer(struct pipe_screen *screen,
39 const __GLcontextModes *visual,
40 unsigned width,
41 unsigned height,
42 void *priv)
43 {
44 enum pipe_format color_format, depth_stencil_format;
45 boolean d_depth_bits_last;
46 boolean ds_depth_bits_last;
47
48 d_depth_bits_last =
49 screen->is_format_supported(screen, PIPE_FORMAT_X8Z24_UNORM,
50 PIPE_TEXTURE_2D,
51 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
52 ds_depth_bits_last =
53 screen->is_format_supported(screen, PIPE_FORMAT_S8Z24_UNORM,
54 PIPE_TEXTURE_2D,
55 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
56
57 if (visual->redBits == 8) {
58 if (visual->alphaBits == 8)
59 color_format = PIPE_FORMAT_A8R8G8B8_UNORM;
60 else
61 color_format = PIPE_FORMAT_X8R8G8B8_UNORM;
62 } else {
63 color_format = PIPE_FORMAT_R5G6B5_UNORM;
64 }
65
66 switch(visual->depthBits) {
67 default:
68 case 0:
69 depth_stencil_format = PIPE_FORMAT_NONE;
70 break;
71 case 16:
72 depth_stencil_format = PIPE_FORMAT_Z16_UNORM;
73 break;
74 case 24:
75 if (visual->stencilBits == 0) {
76 depth_stencil_format = (d_depth_bits_last) ?
77 PIPE_FORMAT_X8Z24_UNORM:
78 PIPE_FORMAT_Z24X8_UNORM;
79 } else {
80 depth_stencil_format = (ds_depth_bits_last) ?
81 PIPE_FORMAT_S8Z24_UNORM:
82 PIPE_FORMAT_Z24S8_UNORM;
83 }
84 break;
85 case 32:
86 depth_stencil_format = PIPE_FORMAT_Z32_UNORM;
87 break;
88 }
89
90 return st_create_framebuffer(visual,
91 color_format,
92 depth_stencil_format,
93 depth_stencil_format,
94 width,
95 height,
96 priv);
97 }
98
99 static void
100 drm_create_texture(_EGLDisplay *dpy,
101 struct drm_screen *scrn,
102 unsigned w, unsigned h)
103 {
104 struct drm_device *dev = lookup_drm_device(dpy);
105 struct pipe_screen *screen = dev->screen;
106 struct pipe_surface *surface;
107 struct pipe_texture *texture;
108 struct pipe_texture templat;
109 struct pipe_buffer *buf = NULL;
110 unsigned pitch = 0;
111
112 memset(&templat, 0, sizeof(templat));
113 templat.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
114 templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY;
115 templat.target = PIPE_TEXTURE_2D;
116 templat.last_level = 0;
117 templat.depth[0] = 1;
118 templat.format = PIPE_FORMAT_A8R8G8B8_UNORM;
119 templat.width[0] = w;
120 templat.height[0] = h;
121 pf_get_block(templat.format, &templat.block);
122
123 texture = screen->texture_create(dev->screen,
124 &templat);
125
126 if (!texture)
127 goto err_tex;
128
129 surface = screen->get_tex_surface(screen,
130 texture,
131 0,
132 0,
133 0,
134 PIPE_BUFFER_USAGE_GPU_WRITE);
135
136 if (!surface)
137 goto err_surf;
138
139 scrn->tex = texture;
140 scrn->surface = surface;
141 scrn->front.width = w;
142 scrn->front.height = h;
143 scrn->front.pitch = pitch;
144 dev->api->local_handle_from_texture(dev->api, screen, texture,
145 &scrn->front.pitch, &scrn->front.handle);
146 if (0)
147 goto err_handle;
148
149 return;
150
151 err_handle:
152 pipe_surface_reference(&surface, NULL);
153 err_surf:
154 pipe_texture_reference(&texture, NULL);
155 err_tex:
156 pipe_buffer_reference(&buf, NULL);
157 return;
158 }
159
160 /*
161 * Exported functions
162 */
163
164 void
165 drm_takedown_shown_screen(_EGLDisplay *dpy, struct drm_screen *screen)
166 {
167 struct drm_device *dev = lookup_drm_device(dpy);
168
169 screen->surf = NULL;
170
171 drmModeSetCrtc(
172 dev->drmFD,
173 screen->crtcID,
174 0, /* FD */
175 0, 0,
176 NULL, 0, /* List of output ids */
177 NULL);
178
179 drmModeRmFB(dev->drmFD, screen->fbID);
180 drmModeFreeFB(screen->fb);
181 screen->fb = NULL;
182
183 pipe_surface_reference(&screen->surface, NULL);
184 pipe_texture_reference(&screen->tex, NULL);
185
186 screen->shown = 0;
187 }
188
189 /**
190 * Called by libEGL's eglCreateWindowSurface().
191 */
192 _EGLSurface *
193 drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativeWindowType window, const EGLint *attrib_list)
194 {
195 return NULL;
196 }
197
198
199 /**
200 * Called by libEGL's eglCreatePixmapSurface().
201 */
202 _EGLSurface *
203 drm_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, NativePixmapType pixmap, const EGLint *attrib_list)
204 {
205 return NULL;
206 }
207
208
209 /**
210 * Called by libEGL's eglCreatePbufferSurface().
211 */
212 _EGLSurface *
213 drm_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
214 const EGLint *attrib_list)
215 {
216 struct drm_device *dev = lookup_drm_device(dpy);
217 int i;
218 int width = -1;
219 int height = -1;
220 struct drm_surface *surf = NULL;
221 __GLcontextModes *visual;
222
223 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
224 switch (attrib_list[i]) {
225 case EGL_WIDTH:
226 width = attrib_list[++i];
227 break;
228 case EGL_HEIGHT:
229 height = attrib_list[++i];
230 break;
231 default:
232 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
233 return EGL_NO_SURFACE;
234 }
235 }
236
237 if (width < 1 || height < 1) {
238 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
239 return NULL;
240 }
241
242 surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface));
243 if (!surf)
244 goto err;
245
246 if (!_eglInitSurface(drv, &surf->base, EGL_PBUFFER_BIT, conf, attrib_list))
247 goto err_surf;
248
249 surf->w = width;
250 surf->h = height;
251
252 visual = drm_visual_from_config(conf);
253 surf->stfb = drm_create_framebuffer(dev->screen, visual,
254 width, height,
255 (void*)surf);
256 drm_visual_modes_destroy(visual);
257
258 return &surf->base;
259
260 err_surf:
261 free(surf);
262 err:
263 return NULL;
264 }
265
266 /**
267 * Called by libEGL's eglCreateScreenSurfaceMESA().
268 */
269 _EGLSurface *
270 drm_create_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *cfg,
271 const EGLint *attrib_list)
272 {
273 EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list);
274
275 return surf;
276 }
277
278 /**
279 * Called by libEGL's eglShowScreenSurfaceMESA().
280 */
281 EGLBoolean
282 drm_show_screen_surface_mesa(_EGLDriver *drv, _EGLDisplay *dpy,
283 _EGLScreen *screen,
284 _EGLSurface *surface, _EGLMode *mode)
285 {
286 struct drm_device *dev = lookup_drm_device(dpy);
287 struct drm_surface *surf = lookup_drm_surface(surface);
288 struct drm_screen *scrn = lookup_drm_screen(screen);
289 int ret;
290 unsigned int i, k;
291
292 if (scrn->shown)
293 drm_takedown_shown_screen(dpy, scrn);
294
295
296 drm_create_texture(dpy, scrn, mode->Width, mode->Height);
297 if (!scrn->tex)
298 goto err_tex;
299
300 ret = drmModeAddFB(dev->drmFD,
301 scrn->front.width, scrn->front.height,
302 32, 32, scrn->front.pitch,
303 scrn->front.handle,
304 &scrn->fbID);
305
306 if (ret)
307 goto err_bo;
308
309 scrn->fb = drmModeGetFB(dev->drmFD, scrn->fbID);
310 if (!scrn->fb)
311 goto err_bo;
312
313 /* find a fitting crtc */
314 {
315 drmModeConnector *con = scrn->connector;
316
317 scrn->mode = drm_find_mode(con, mode);
318 if (!scrn->mode)
319 goto err_fb;
320
321 for (k = 0; k < con->count_encoders; k++) {
322 drmModeEncoder *enc = drmModeGetEncoder(dev->drmFD, con->encoders[k]);
323 for (i = 0; i < dev->res->count_crtcs; i++) {
324 if (enc->possible_crtcs & (1<<i)) {
325 /* save the ID */
326 scrn->crtcID = dev->res->crtcs[i];
327
328 /* skip the rest */
329 i = dev->res->count_crtcs;
330 k = dev->res->count_encoders;
331 }
332 }
333 drmModeFreeEncoder(enc);
334 }
335 }
336
337 ret = drmModeSetCrtc(dev->drmFD,
338 scrn->crtcID,
339 scrn->fbID,
340 0, 0,
341 &scrn->connectorID, 1,
342 scrn->mode);
343
344 if (ret)
345 goto err_crtc;
346
347
348 if (scrn->dpms)
349 drmModeConnectorSetProperty(dev->drmFD,
350 scrn->connectorID,
351 scrn->dpms->prop_id,
352 DRM_MODE_DPMS_ON);
353
354 surf->screen = scrn;
355
356 scrn->surf = surf;
357 scrn->shown = 1;
358
359 return EGL_TRUE;
360
361 err_crtc:
362 scrn->crtcID = 0;
363
364 err_fb:
365 drmModeRmFB(dev->drmFD, scrn->fbID);
366 drmModeFreeFB(scrn->fb);
367 scrn->fb = NULL;
368
369 err_bo:
370 pipe_surface_reference(&scrn->surface, NULL);
371 pipe_texture_reference(&scrn->tex, NULL);
372
373 err_tex:
374 return EGL_FALSE;
375 }
376
377 /**
378 * Called by libEGL's eglDestroySurface().
379 */
380 EGLBoolean
381 drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface)
382 {
383 struct drm_surface *surf = lookup_drm_surface(surface);
384 if (!_eglIsSurfaceBound(&surf->base)) {
385 if (surf->screen)
386 drm_takedown_shown_screen(dpy, surf->screen);
387 st_unreference_framebuffer(surf->stfb);
388 free(surf);
389 }
390 return EGL_TRUE;
391 }
392
393 /**
394 * Called by libEGL's eglSwapBuffers().
395 */
396 EGLBoolean
397 drm_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *draw)
398 {
399 struct drm_device *dev = lookup_drm_device(dpy);
400 struct drm_surface *surf = lookup_drm_surface(draw);
401 struct pipe_surface *back_surf;
402
403 if (!surf)
404 return EGL_FALSE;
405
406 st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
407
408 if (back_surf) {
409 struct drm_context *ctx = lookup_drm_context(draw->Binding);
410
411 st_notify_swapbuffers(surf->stfb);
412
413 if (ctx && surf->screen) {
414 if (ctx->pipe->surface_copy) {
415 ctx->pipe->surface_copy(ctx->pipe,
416 surf->screen->surface,
417 0, 0,
418 back_surf,
419 0, 0,
420 surf->w, surf->h);
421 } else {
422 util_surface_copy(ctx->pipe, FALSE,
423 surf->screen->surface,
424 0, 0,
425 back_surf,
426 0, 0,
427 surf->w, surf->h);
428 }
429 ctx->pipe->flush(ctx->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
430
431 #ifdef DRM_MODE_FEATURE_DIRTYFB
432 /* TODO query connector property to see if this is needed */
433 drmModeDirtyFB(dev->drmFD, surf->screen->fbID, NULL, 0);
434 #else
435 (void)dev;
436 #endif
437
438 /* TODO more stuff here */
439 }
440 }
441
442 return EGL_TRUE;
443 }