Merge branch 'gallium-0.2' into gallium-winsys-private
[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 struct drm_mode_modeinfo *
20 drm_find_mode(drmModeConnectorPtr connector, _EGLMode *mode)
21 {
22 int i;
23 struct drm_mode_modeinfo *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_DISPLAY_TARGET;
102 templat.tex_usage |= PIPE_TEXTURE_USAGE_RENDER_TARGET;
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 scrn->front.handle = drm_api_hocks.handle_from_buffer(dev->winsys, scrn->buffer);
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(screen, &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(dev->screen, &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, dpy, &surf->base, EGL_PBUFFER_BIT, config, 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 _eglSaveSurface(&surf->base);
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 struct pipe_context *pipe;
275 _EGLMode *mode = _eglLookupMode(dpy, m);
276 int ret;
277 unsigned int i, k;
278
279 if (scrn->shown)
280 drm_takedown_shown_screen(drv, scrn);
281
282
283 drm_create_texture(drv, scrn, mode->Width, mode->Height);
284 if (!scrn->buffer)
285 return EGL_FALSE;
286
287 ret = drmModeAddFB(dev->drmFD,
288 scrn->front.width, scrn->front.height,
289 32, 32, scrn->front.pitch,
290 scrn->front.handle,
291 &scrn->fbID);
292
293 if (ret)
294 goto err_bo;
295
296 scrn->fb = drmModeGetFB(dev->drmFD, scrn->fbID);
297 if (!scrn->fb)
298 goto err_bo;
299
300 /* find a fitting crtc */
301 {
302 drmModeConnector *con = scrn->connector;
303
304 scrn->mode = drm_find_mode(con, mode);
305 if (!scrn->mode)
306 goto err_fb;
307
308 for (k = 0; k < con->count_encoders; k++) {
309 drmModeEncoder *enc = drmModeGetEncoder(dev->drmFD, con->encoders[k]);
310 for (i = 0; i < dev->res->count_crtcs; i++) {
311 if (enc->possible_crtcs & (1<<i)) {
312 /* save the ID */
313 scrn->crtcID = dev->res->crtcs[i];
314
315 /* skip the rest */
316 i = dev->res->count_crtcs;
317 k = dev->res->count_encoders;
318 }
319 }
320 drmModeFreeEncoder(enc);
321 }
322 }
323
324 ret = drmModeSetCrtc(dev->drmFD,
325 scrn->crtcID,
326 scrn->fbID,
327 0, 0,
328 &scrn->connectorID, 1,
329 scrn->mode);
330
331 if (ret)
332 goto err_crtc;
333
334 surf->screen = scrn;
335
336 scrn->surf = surf;
337 scrn->shown = 1;
338
339 return EGL_TRUE;
340
341 err_crtc:
342 scrn->crtcID = 0;
343
344 err_fb:
345 drmModeRmFB(dev->drmFD, scrn->fbID);
346 drmModeFreeFB(scrn->fb);
347 scrn->fb = NULL;
348
349 err_bo:
350 pipe_surface_reference(&scrn->surface, NULL);
351 pipe_texture_reference(&scrn->tex, NULL);
352 pipe_buffer_reference(dev->screen, &scrn->buffer, NULL);
353
354 return EGL_FALSE;
355 }
356
357 EGLBoolean
358 drm_destroy_surface(_EGLDriver *drv, EGLDisplay dpy, EGLSurface surface)
359 {
360 struct drm_surface *surf = lookup_drm_surface(surface);
361 _eglRemoveSurface(&surf->base);
362 if (surf->base.IsBound) {
363 surf->base.DeletePending = EGL_TRUE;
364 } else {
365 if (surf->screen)
366 drm_takedown_shown_screen(drv, surf->screen);
367 st_unreference_framebuffer(surf->stfb);
368 free(surf);
369 }
370 return EGL_TRUE;
371 }
372
373 EGLBoolean
374 drm_swap_buffers(_EGLDriver *drv, EGLDisplay dpy, EGLSurface draw)
375 {
376 struct drm_surface *surf = lookup_drm_surface(draw);
377 struct pipe_surface *back_surf;
378
379 if (!surf)
380 return EGL_FALSE;
381
382 /* error checking */
383 if (!_eglSwapBuffers(drv, dpy, draw))
384 return EGL_FALSE;
385
386 st_get_framebuffer_surface(surf->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
387
388 if (back_surf) {
389
390 st_notify_swapbuffers(surf->stfb);
391
392 if (surf->screen) {
393 surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
394 surf->user->pipe->surface_copy(surf->user->pipe,
395 0,
396 surf->screen->surface,
397 0, 0,
398 back_surf,
399 0, 0,
400 surf->w, surf->h);
401 surf->user->pipe->flush(surf->user->pipe, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_TEXTURE_CACHE, NULL);
402 /* TODO stuff here */
403 }
404
405 st_notify_swapbuffers_complete(surf->stfb);
406 }
407
408 return EGL_TRUE;
409 }