Merge branch 'mesa_7_5_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(_EGLDriver *drv,
71 struct drm_screen *scrn,
72 unsigned w, unsigned h)
73 {
74 struct drm_device *dev = (struct drm_device *)drv;
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;
80 unsigned stride = 1024;
81 unsigned pitch = 0;
82 unsigned size = 0;
83
84 /* ugly */
85 if (stride < w)
86 stride = 2048;
87
88 pitch = stride * 4;
89 size = h * 2 * pitch;
90
91 buf = pipe_buffer_create(screen,
92 0, /* alignment */
93 PIPE_BUFFER_USAGE_GPU_READ_WRITE |
94 PIPE_BUFFER_USAGE_CPU_READ_WRITE,
95 size);
96
97 if (!buf)
98 goto err_buf;
99
100 memset(&templat, 0, sizeof(templat));
101 templat.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
102 templat.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY;
103 templat.target = PIPE_TEXTURE_2D;
104 templat.last_level = 0;
105 templat.depth[0] = 1;
106 templat.format = PIPE_FORMAT_A8R8G8B8_UNORM;
107 templat.width[0] = w;
108 templat.height[0] = h;
109 pf_get_block(templat.format, &templat.block);
110
111 texture = screen->texture_blanket(dev->screen,
112 &templat,
113 &pitch,
114 buf);
115 if (!texture)
116 goto err_tex;
117
118 surface = screen->get_tex_surface(screen,
119 texture,
120 0,
121 0,
122 0,
123 PIPE_BUFFER_USAGE_GPU_WRITE);
124
125 if (!surface)
126 goto err_surf;
127
128
129 scrn->tex = texture;
130 scrn->surface = surface;
131 scrn->buffer = buf;
132 scrn->front.width = w;
133 scrn->front.height = h;
134 scrn->front.pitch = pitch;
135 dev->api->handle_from_buffer(dev->api, screen, scrn->buffer, &scrn->front.handle);
136 if (0)
137 goto err_handle;
138
139 return;
140
141 err_handle:
142 pipe_surface_reference(&surface, NULL);
143 err_surf:
144 pipe_texture_reference(&texture, NULL);
145 err_tex:
146 pipe_buffer_reference(&buf, NULL);
147 err_buf:
148 return;
149 }
150
151 /*
152 * Exported functions
153 */
154
155 void
156 drm_takedown_shown_screen(_EGLDriver *drv, struct drm_screen *screen)
157 {
158 struct drm_device *dev = (struct drm_device *)drv;
159
160 screen->surf = NULL;
161
162 drmModeSetCrtc(
163 dev->drmFD,
164 screen->crtcID,
165 0, // FD
166 0, 0,
167 NULL, 0, // List of output ids
168 NULL);
169
170 drmModeRmFB(dev->drmFD, screen->fbID);
171 drmModeFreeFB(screen->fb);
172 screen->fb = NULL;
173
174 pipe_surface_reference(&screen->surface, NULL);
175 pipe_texture_reference(&screen->tex, NULL);
176 pipe_buffer_reference(&screen->buffer, NULL);
177
178 screen->shown = 0;
179 }
180
181 EGLSurface
182 drm_create_window_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list)
183 {
184 return EGL_NO_SURFACE;
185 }
186
187
188 EGLSurface
189 drm_create_pixmap_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list)
190 {
191 return EGL_NO_SURFACE;
192 }
193
194
195 EGLSurface
196 drm_create_pbuffer_surface(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
197 const EGLint *attrib_list)
198 {
199 int i;
200 int width = -1;
201 int height = -1;
202 struct drm_surface *surf = NULL;
203 __GLcontextModes *visual;
204 _EGLConfig *conf;
205
206 conf = _eglLookupConfig(drv, dpy, config);
207 if (!conf) {
208 _eglError(EGL_BAD_CONFIG, "eglCreatePbufferSurface");
209 return EGL_NO_CONTEXT;
210 }
211
212 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
213 switch (attrib_list[i]) {
214 case EGL_WIDTH:
215 width = attrib_list[++i];
216 break;
217 case EGL_HEIGHT:
218 height = attrib_list[++i];
219 break;
220 default:
221 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
222 return EGL_NO_SURFACE;
223 }
224 }
225
226 if (width < 1 || height < 1) {
227 _eglError(EGL_BAD_ATTRIBUTE, "eglCreatePbufferSurface");
228 return EGL_NO_SURFACE;
229 }
230
231 surf = (struct drm_surface *) calloc(1, sizeof(struct drm_surface));
232 if (!surf)
233 goto err;
234
235 if (!_eglInitSurface(drv, &surf->base, EGL_PBUFFER_BIT, conf, attrib_list))
236 goto err_surf;
237
238 surf->w = width;
239 surf->h = height;
240
241 visual = drm_visual_from_config(conf);
242 surf->stfb = drm_create_framebuffer(visual,
243 width,
244 height,
245 (void*)surf);
246 drm_visual_modes_destroy(visual);
247
248 _eglLinkSurface(&surf->base, _eglLookupDisplay(dpy));
249 return surf->base.Handle;
250
251 err_surf:
252 free(surf);
253 err:
254 return EGL_NO_SURFACE;
255 }
256
257 EGLSurface
258 drm_create_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy, EGLConfig cfg,
259 const EGLint *attrib_list)
260 {
261 EGLSurface surf = drm_create_pbuffer_surface(drv, dpy, cfg, attrib_list);
262
263 return surf;
264 }
265
266 EGLBoolean
267 drm_show_screen_surface_mesa(_EGLDriver *drv, EGLDisplay dpy,
268 EGLScreenMESA screen,
269 EGLSurface surface, EGLModeMESA m)
270 {
271 struct drm_device *dev = (struct drm_device *)drv;
272 struct drm_surface *surf = lookup_drm_surface(surface);
273 struct drm_screen *scrn = lookup_drm_screen(dpy, screen);
274 _EGLMode *mode = _eglLookupMode(dpy, m);
275 int ret;
276 unsigned int i, k;
277
278 if (scrn->shown)
279 drm_takedown_shown_screen(drv, scrn);
280
281
282 drm_create_texture(drv, scrn, mode->Width, mode->Height);
283 if (!scrn->buffer)
284 return EGL_FALSE;
285
286 ret = drmModeAddFB(dev->drmFD,
287 scrn->front.width, scrn->front.height,
288 32, 32, scrn->front.pitch,
289 scrn->front.handle,
290 &scrn->fbID);
291
292 if (ret)
293 goto err_bo;
294
295 scrn->fb = drmModeGetFB(dev->drmFD, scrn->fbID);
296 if (!scrn->fb)
297 goto err_bo;
298
299 /* find a fitting crtc */
300 {
301 drmModeConnector *con = scrn->connector;
302
303 scrn->mode = drm_find_mode(con, mode);
304 if (!scrn->mode)
305 goto err_fb;
306
307 for (k = 0; k < con->count_encoders; k++) {
308 drmModeEncoder *enc = drmModeGetEncoder(dev->drmFD, con->encoders[k]);
309 for (i = 0; i < dev->res->count_crtcs; i++) {
310 if (enc->possible_crtcs & (1<<i)) {
311 /* save the ID */
312 scrn->crtcID = dev->res->crtcs[i];
313
314 /* skip the rest */
315 i = dev->res->count_crtcs;
316 k = dev->res->count_encoders;
317 }
318 }
319 drmModeFreeEncoder(enc);
320 }
321 }
322
323 ret = drmModeSetCrtc(dev->drmFD,
324 scrn->crtcID,
325 scrn->fbID,
326 0, 0,
327 &scrn->connectorID, 1,
328 scrn->mode);
329
330 if (ret)
331 goto err_crtc;
332
333
334 if (scrn->dpms)
335 drmModeConnectorSetProperty(dev->drmFD,
336 scrn->connectorID,
337 scrn->dpms->prop_id,
338 DRM_MODE_DPMS_ON);
339
340 surf->screen = scrn;
341
342 scrn->surf = surf;
343 scrn->shown = 1;
344
345 return EGL_TRUE;
346
347 err_crtc:
348 scrn->crtcID = 0;
349
350 err_fb:
351 drmModeRmFB(dev->drmFD, scrn->fbID);
352 drmModeFreeFB(scrn->fb);
353 scrn->fb = NULL;
354
355 err_bo:
356 pipe_surface_reference(&scrn->surface, NULL);
357 pipe_texture_reference(&scrn->tex, NULL);
358 pipe_buffer_reference(&scrn->buffer, NULL);
359
360 return EGL_FALSE;
361 }
362
363 EGLBoolean
364 drm_destroy_surface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
365 {
366 struct drm_surface *surf = lookup_drm_surface(surface);
367 _eglUnlinkSurface(&surf->base);
368
369 if (!_eglIsSurfaceBound(&surf->base)) {
370 if (surf->screen)
371 drm_takedown_shown_screen(drv, surf->screen);
372 st_unreference_framebuffer(surf->stfb);
373 free(surf);
374 }
375 return EGL_TRUE;
376 }
377
378 EGLBoolean
379 drm_swap_buffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
380 {
381 struct drm_surface *surf = lookup_drm_surface(draw);
382 struct pipe_surface *back_surf;
383
384 if (!surf)
385 return EGL_FALSE;
386
387 /* error checking */
388 if (!_eglSwapBuffers(drv, dpy, draw))
389 return EGL_FALSE;
390
391 st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
392
393 if (back_surf) {
394
395 st_notify_swapbuffers(surf->stfb);
396
397 if (surf->screen) {
398 surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
399 surf->user->pipe->surface_copy(surf->user->pipe,
400 surf->screen->surface,
401 0, 0,
402 back_surf,
403 0, 0,
404 surf->w, surf->h);
405 surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
406 /* TODO stuff here */
407 }
408 }
409
410 return EGL_TRUE;
411 }