st/dri: Make lookup_egl_image a hook
[mesa.git] / src / gallium / state_trackers / dri / drm / dri2.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.9
4 *
5 * Copyright 2009, VMware, Inc.
6 * All Rights Reserved.
7 * Copyright (C) 2010 LunarG Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27 * Keith Whitwell <keithw@vmware.com>
28 * Jakob Bornecrantz <wallbraker@gmail.com>
29 * Chia-I Wu <olv@lunarg.com>
30 */
31
32 #include "util/u_memory.h"
33 #include "util/u_inlines.h"
34 #include "util/u_format.h"
35 #include "util/u_debug.h"
36 #include "state_tracker/drm_api.h"
37
38 #include "dri_screen.h"
39 #include "dri_context.h"
40 #include "dri_drawable.h"
41 #include "dri_st_api.h"
42 #include "dri2.h"
43
44 #include "GL/internal/dri_interface.h"
45
46 /**
47 * DRI2 flush extension.
48 */
49 static void
50 dri2_flush_drawable(__DRIdrawable *draw)
51 {
52 }
53
54 static void
55 dri2_invalidate_drawable(__DRIdrawable *dPriv)
56 {
57 struct dri_drawable *drawable = dri_drawable(dPriv);
58 struct dri_context *ctx = dri_context(dPriv->driContextPriv);
59
60 dri2InvalidateDrawable(dPriv);
61 drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
62
63 if (ctx)
64 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
65 }
66
67 static const __DRI2flushExtension dri2FlushExtension = {
68 { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
69 dri2_flush_drawable,
70 dri2_invalidate_drawable,
71 };
72
73 /**
74 * These are used for GLX_EXT_texture_from_pixmap
75 */
76 static void
77 dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
78 GLint format, __DRIdrawable *dPriv)
79 {
80 struct dri_context *ctx = dri_context(pDRICtx);
81 struct dri_drawable *drawable = dri_drawable(dPriv);
82 struct pipe_resource *pt;
83
84 dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT);
85
86 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
87
88 if (pt) {
89 enum pipe_format internal_format = pt->format;
90
91 if (format == __DRI_TEXTURE_FORMAT_RGB) {
92 /* only need to cover the formats recognized by dri_fill_st_visual */
93 switch (internal_format) {
94 case PIPE_FORMAT_B8G8R8A8_UNORM:
95 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
96 break;
97 case PIPE_FORMAT_A8R8G8B8_UNORM:
98 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
99 break;
100 default:
101 break;
102 }
103 }
104
105 ctx->st->teximage(ctx->st,
106 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
107 0, internal_format, pt, FALSE);
108 }
109 }
110
111 static void
112 dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
113 __DRIdrawable *dPriv)
114 {
115 dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
116 }
117
118 static const __DRItexBufferExtension dri2TexBufferExtension = {
119 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
120 dri2_set_tex_buffer,
121 dri2_set_tex_buffer2,
122 };
123
124 /**
125 * Get the format and binding of an attachment.
126 */
127 static INLINE void
128 dri2_drawable_get_format(struct dri_drawable *drawable,
129 enum st_attachment_type statt,
130 enum pipe_format *format,
131 unsigned *bind)
132 {
133 switch (statt) {
134 case ST_ATTACHMENT_FRONT_LEFT:
135 case ST_ATTACHMENT_BACK_LEFT:
136 case ST_ATTACHMENT_FRONT_RIGHT:
137 case ST_ATTACHMENT_BACK_RIGHT:
138 *format = drawable->stvis.color_format;
139 *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
140 break;
141 case ST_ATTACHMENT_DEPTH_STENCIL:
142 *format = drawable->stvis.depth_stencil_format;
143 *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
144 break;
145 default:
146 *format = PIPE_FORMAT_NONE;
147 *bind = 0;
148 break;
149 }
150 }
151
152
153 /**
154 * Retrieve __DRIbuffer from the DRI loader.
155 */
156 static __DRIbuffer *
157 dri2_drawable_get_buffers(struct dri_drawable *drawable,
158 const enum st_attachment_type *statts,
159 unsigned *count)
160 {
161 __DRIdrawable *dri_drawable = drawable->dPriv;
162 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
163 boolean with_format;
164 __DRIbuffer *buffers;
165 int num_buffers;
166 unsigned attachments[10];
167 unsigned num_attachments, i;
168
169 assert(loader);
170 with_format = dri_with_format(drawable->sPriv);
171
172 num_attachments = 0;
173
174 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
175 if (!with_format)
176 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
177
178 for (i = 0; i < *count; i++) {
179 enum pipe_format format;
180 unsigned bind;
181 int att, bpp;
182
183 dri2_drawable_get_format(drawable, statts[i], &format, &bind);
184 if (format == PIPE_FORMAT_NONE)
185 continue;
186
187 switch (statts[i]) {
188 case ST_ATTACHMENT_FRONT_LEFT:
189 /* already added */
190 if (!with_format)
191 continue;
192 att = __DRI_BUFFER_FRONT_LEFT;
193 break;
194 case ST_ATTACHMENT_BACK_LEFT:
195 att = __DRI_BUFFER_BACK_LEFT;
196 break;
197 case ST_ATTACHMENT_FRONT_RIGHT:
198 att = __DRI_BUFFER_FRONT_RIGHT;
199 break;
200 case ST_ATTACHMENT_BACK_RIGHT:
201 att = __DRI_BUFFER_BACK_RIGHT;
202 break;
203 case ST_ATTACHMENT_DEPTH_STENCIL:
204 att = __DRI_BUFFER_DEPTH_STENCIL;
205 break;
206 default:
207 att = -1;
208 break;
209 }
210
211 bpp = util_format_get_blocksizebits(format);
212
213 if (att >= 0) {
214 attachments[num_attachments++] = att;
215 if (with_format) {
216 attachments[num_attachments++] = bpp;
217 }
218 }
219 }
220
221 if (with_format) {
222 num_attachments /= 2;
223 buffers = loader->getBuffersWithFormat(dri_drawable,
224 &dri_drawable->w, &dri_drawable->h,
225 attachments, num_attachments,
226 &num_buffers, dri_drawable->loaderPrivate);
227 }
228 else {
229 buffers = loader->getBuffers(dri_drawable,
230 &dri_drawable->w, &dri_drawable->h,
231 attachments, num_attachments,
232 &num_buffers, dri_drawable->loaderPrivate);
233 }
234
235 if (buffers) {
236 /* set one cliprect to cover the whole dri_drawable */
237 dri_drawable->x = 0;
238 dri_drawable->y = 0;
239 dri_drawable->backX = 0;
240 dri_drawable->backY = 0;
241 dri_drawable->numClipRects = 1;
242 dri_drawable->pClipRects[0].x1 = 0;
243 dri_drawable->pClipRects[0].y1 = 0;
244 dri_drawable->pClipRects[0].x2 = dri_drawable->w;
245 dri_drawable->pClipRects[0].y2 = dri_drawable->h;
246 dri_drawable->numBackClipRects = 1;
247 dri_drawable->pBackClipRects[0].x1 = 0;
248 dri_drawable->pBackClipRects[0].y1 = 0;
249 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
250 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
251
252 *count = num_buffers;
253 }
254
255 return buffers;
256 }
257
258 /**
259 * Process __DRIbuffer and convert them into pipe_resources.
260 */
261 static void
262 dri2_drawable_process_buffers(struct dri_drawable *drawable,
263 __DRIbuffer *buffers, unsigned count)
264 {
265 struct dri_screen *screen = dri_screen(drawable->sPriv);
266 __DRIdrawable *dri_drawable = drawable->dPriv;
267 struct pipe_resource templ;
268 struct winsys_handle whandle;
269 boolean have_depth = FALSE;
270 unsigned i, bind;
271
272 if (drawable->old_num == count &&
273 drawable->old_w == dri_drawable->w &&
274 drawable->old_h == dri_drawable->h &&
275 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
276 return;
277
278 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
279 pipe_resource_reference(&drawable->textures[i], NULL);
280
281 memset(&templ, 0, sizeof(templ));
282 templ.target = PIPE_TEXTURE_2D;
283 templ.last_level = 0;
284 templ.width0 = dri_drawable->w;
285 templ.height0 = dri_drawable->h;
286 templ.depth0 = 1;
287
288 memset(&whandle, 0, sizeof(whandle));
289
290 for (i = 0; i < count; i++) {
291 __DRIbuffer *buf = &buffers[i];
292 enum st_attachment_type statt;
293 enum pipe_format format;
294
295 switch (buf->attachment) {
296 case __DRI_BUFFER_FRONT_LEFT:
297 if (!screen->auto_fake_front) {
298 statt = ST_ATTACHMENT_INVALID;
299 break;
300 }
301 /* fallthrough */
302 case __DRI_BUFFER_FAKE_FRONT_LEFT:
303 statt = ST_ATTACHMENT_FRONT_LEFT;
304 break;
305 case __DRI_BUFFER_BACK_LEFT:
306 statt = ST_ATTACHMENT_BACK_LEFT;
307 break;
308 case __DRI_BUFFER_DEPTH:
309 case __DRI_BUFFER_DEPTH_STENCIL:
310 case __DRI_BUFFER_STENCIL:
311 /* use only the first depth/stencil buffer */
312 if (!have_depth) {
313 have_depth = TRUE;
314 statt = ST_ATTACHMENT_DEPTH_STENCIL;
315 }
316 else {
317 statt = ST_ATTACHMENT_INVALID;
318 }
319 break;
320 default:
321 statt = ST_ATTACHMENT_INVALID;
322 break;
323 }
324
325 dri2_drawable_get_format(drawable, statt, &format, &bind);
326 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
327 continue;
328
329 templ.format = format;
330 templ.bind = bind;
331 whandle.handle = buf->name;
332 whandle.stride = buf->pitch;
333
334 drawable->textures[statt] =
335 screen->pipe_screen->resource_from_handle(screen->pipe_screen,
336 &templ, &whandle);
337 }
338
339 drawable->old_num = count;
340 drawable->old_w = dri_drawable->w;
341 drawable->old_h = dri_drawable->h;
342 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
343 }
344
345 /*
346 * Backend functions for st_framebuffer interface.
347 */
348
349 void
350 dri2_allocate_textures(struct dri_drawable *drawable,
351 const enum st_attachment_type *statts,
352 unsigned count)
353 {
354 __DRIbuffer *buffers;
355 unsigned num_buffers = count;
356
357 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
358 dri2_drawable_process_buffers(drawable, buffers, num_buffers);
359 }
360
361 void
362 dri2_flush_frontbuffer(struct dri_drawable *drawable,
363 enum st_attachment_type statt)
364 {
365 __DRIdrawable *dri_drawable = drawable->dPriv;
366 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
367
368 if (loader->flushFrontBuffer == NULL)
369 return;
370
371 if (statt == ST_ATTACHMENT_FRONT_LEFT) {
372 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
373 }
374 }
375
376 static __DRIimage *
377 dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
378 {
379 __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
380 __DRIimage *img;
381
382 if (!loader->lookupEGLImage)
383 return NULL;
384
385 img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
386
387 return img;
388 }
389
390 static __DRIimage *
391 dri2_create_image_from_name(__DRIcontext *context,
392 int width, int height, int format,
393 int name, int pitch, void *loaderPrivate)
394 {
395 struct dri_screen *screen = dri_screen(context->driScreenPriv);
396 __DRIimage *img;
397 struct pipe_resource templ;
398 struct winsys_handle whandle;
399 unsigned tex_usage;
400 enum pipe_format pf;
401
402 tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
403
404 switch (format) {
405 case __DRI_IMAGE_FORMAT_RGB565:
406 pf = PIPE_FORMAT_B5G6R5_UNORM;
407 break;
408 case __DRI_IMAGE_FORMAT_XRGB8888:
409 pf = PIPE_FORMAT_B8G8R8X8_UNORM;
410 break;
411 case __DRI_IMAGE_FORMAT_ARGB8888:
412 pf = PIPE_FORMAT_B8G8R8A8_UNORM;
413 break;
414 default:
415 pf = PIPE_FORMAT_NONE;
416 break;
417 }
418 if (pf == PIPE_FORMAT_NONE)
419 return NULL;
420
421 img = CALLOC_STRUCT(__DRIimageRec);
422 if (!img)
423 return NULL;
424
425 memset(&templ, 0, sizeof(templ));
426 templ.bind = tex_usage;
427 templ.format = pf;
428 templ.target = PIPE_TEXTURE_2D;
429 templ.last_level = 0;
430 templ.width0 = width;
431 templ.height0 = height;
432 templ.depth0 = 1;
433
434 memset(&whandle, 0, sizeof(whandle));
435 whandle.handle = name;
436 whandle.stride = pitch * util_format_get_blocksize(pf);
437
438 img->texture = screen->pipe_screen->resource_from_handle(screen->pipe_screen,
439 &templ, &whandle);
440 if (!img->texture) {
441 FREE(img);
442 return NULL;
443 }
444
445 img->face = 0;
446 img->level = 0;
447 img->zslice = 0;
448 img->loader_private = loaderPrivate;
449
450 return img;
451 }
452
453 static __DRIimage *
454 dri2_create_image_from_renderbuffer(__DRIcontext *context,
455 int renderbuffer, void *loaderPrivate)
456 {
457 struct dri_context *ctx = dri_context(context->driverPrivate);
458
459 if (!ctx->st->get_resource_for_egl_image)
460 return NULL;
461
462 /* TODO */
463 return NULL;
464 }
465
466 static void
467 dri2_destroy_image(__DRIimage *img)
468 {
469 pipe_resource_reference(&img->texture, NULL);
470 FREE(img);
471 }
472
473 static struct __DRIimageExtensionRec dri2ImageExtension = {
474 { __DRI_IMAGE, __DRI_IMAGE_VERSION },
475 dri2_create_image_from_name,
476 dri2_create_image_from_renderbuffer,
477 dri2_destroy_image,
478 };
479
480 /*
481 * Backend function init_screen.
482 */
483
484 static const __DRIextension *dri_screen_extensions[] = {
485 &driReadDrawableExtension,
486 &driCopySubBufferExtension.base,
487 &driSwapControlExtension.base,
488 &driFrameTrackingExtension.base,
489 &driMediaStreamCounterExtension.base,
490 &dri2TexBufferExtension.base,
491 &dri2FlushExtension.base,
492 &dri2ImageExtension.base,
493 NULL
494 };
495
496 /**
497 * This is the driver specific part of the createNewScreen entry point.
498 *
499 * Returns the __GLcontextModes supported by this driver.
500 */
501 const __DRIconfig **
502 dri2_init_screen(__DRIscreen * sPriv)
503 {
504 const __DRIconfig **configs;
505 struct dri_screen *screen;
506 struct pipe_screen *pscreen;
507
508 screen = CALLOC_STRUCT(dri_screen);
509 if (!screen)
510 return NULL;
511
512 screen->api = drm_api_create();
513 screen->sPriv = sPriv;
514 screen->fd = sPriv->fd;
515 screen->lookup_egl_image = dri2_lookup_egl_image;
516
517 sPriv->private = (void *)screen;
518 sPriv->extensions = dri_screen_extensions;
519
520 pscreen = screen->api->create_screen(screen->api, screen->fd, NULL);
521 /* dri_init_screen_helper checks pscreen for us */
522
523 configs = dri_init_screen_helper(screen, pscreen, 32);
524 if (!configs)
525 goto fail;
526
527 screen->auto_fake_front = dri_with_format(sPriv);
528
529 return configs;
530 fail:
531 dri_destroy_screen_helper(screen);
532 FREE(screen);
533 return NULL;
534 }
535
536 /* This is the table of extensions that the loader will dlsym() for. */
537 PUBLIC const __DRIextension *__driDriverExtensions[] = {
538 &driCoreExtension.base,
539 &driLegacyExtension.base,
540 &driDRI2Extension.base,
541 NULL
542 };
543
544 /* vim: set sw=3 ts=8 sts=3 expandtab: */