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