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