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