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