Merge branch '7.8'
[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 /**
45 * DRI2 flush extension.
46 */
47 static void
48 dri2_flush_drawable(__DRIdrawable *draw)
49 {
50 }
51
52 static void
53 dri2_invalidate_drawable(__DRIdrawable *dPriv)
54 {
55 struct dri_drawable *drawable = dri_drawable(dPriv);
56 struct dri_context *ctx = dri_context(dPriv->driContextPriv);
57
58 dri2InvalidateDrawable(dPriv);
59 drawable->dPriv->lastStamp = *drawable->dPriv->pStamp;
60
61 if (ctx)
62 ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
63 }
64
65 static const __DRI2flushExtension dri2FlushExtension = {
66 { __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
67 dri2_flush_drawable,
68 dri2_invalidate_drawable,
69 };
70
71 /**
72 * These are used for GLX_EXT_texture_from_pixmap
73 */
74 static void
75 dri2_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
76 GLint format, __DRIdrawable *dPriv)
77 {
78 struct dri_context *ctx = dri_context(pDRICtx);
79 struct dri_drawable *drawable = dri_drawable(dPriv);
80 struct pipe_texture *pt;
81
82 dri_st_framebuffer_validate_att(drawable->stfb, ST_ATTACHMENT_FRONT_LEFT);
83
84 pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
85
86 if (pt) {
87 enum pipe_format internal_format = pt->format;
88
89 if (format == __DRI_TEXTURE_FORMAT_RGB) {
90 /* only need to cover the formats recognized by dri_fill_st_visual */
91 switch (internal_format) {
92 case PIPE_FORMAT_B8G8R8A8_UNORM:
93 internal_format = PIPE_FORMAT_B8G8R8X8_UNORM;
94 break;
95 case PIPE_FORMAT_A8R8G8B8_UNORM:
96 internal_format = PIPE_FORMAT_X8R8G8B8_UNORM;
97 break;
98 default:
99 break;
100 }
101 }
102
103 ctx->st->teximage(ctx->st,
104 (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
105 0, internal_format, pt, FALSE);
106 }
107 }
108
109 static void
110 dri2_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
111 __DRIdrawable *dPriv)
112 {
113 dri2_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
114 }
115
116 static const __DRItexBufferExtension dri2TexBufferExtension = {
117 { __DRI_TEX_BUFFER, __DRI_TEX_BUFFER_VERSION },
118 dri2_set_tex_buffer,
119 dri2_set_tex_buffer2,
120 };
121
122 /**
123 * Get the format of an attachment.
124 */
125 static INLINE enum pipe_format
126 dri2_drawable_get_format(struct dri_drawable *drawable,
127 enum st_attachment_type statt)
128 {
129 enum pipe_format format;
130
131 switch (statt) {
132 case ST_ATTACHMENT_FRONT_LEFT:
133 case ST_ATTACHMENT_BACK_LEFT:
134 case ST_ATTACHMENT_FRONT_RIGHT:
135 case ST_ATTACHMENT_BACK_RIGHT:
136 format = drawable->stvis.color_format;
137 break;
138 case ST_ATTACHMENT_DEPTH_STENCIL:
139 format = drawable->stvis.depth_stencil_format;
140 break;
141 default:
142 format = PIPE_FORMAT_NONE;
143 break;
144 }
145
146 return format;
147 }
148
149 /**
150 * Retrieve __DRIbuffer from the DRI loader.
151 */
152 static __DRIbuffer *
153 dri2_drawable_get_buffers(struct dri_drawable *drawable,
154 const enum st_attachment_type *statts,
155 unsigned *count)
156 {
157 __DRIdrawable *dri_drawable = drawable->dPriv;
158 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
159 boolean with_format;
160 __DRIbuffer *buffers;
161 int num_buffers;
162 unsigned attachments[10];
163 unsigned num_attachments, i;
164
165 assert(loader);
166 with_format = dri_with_format(drawable->sPriv);
167
168 num_attachments = 0;
169
170 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
171 if (!with_format)
172 attachments[num_attachments++] = __DRI_BUFFER_FRONT_LEFT;
173
174 for (i = 0; i < *count; i++) {
175 enum pipe_format format;
176 int att, bpp;
177
178 format = dri2_drawable_get_format(drawable, statts[i]);
179 if (format == PIPE_FORMAT_NONE)
180 continue;
181
182 switch (statts[i]) {
183 case ST_ATTACHMENT_FRONT_LEFT:
184 /* already added */
185 if (!with_format)
186 continue;
187 att = __DRI_BUFFER_FRONT_LEFT;
188 break;
189 case ST_ATTACHMENT_BACK_LEFT:
190 att = __DRI_BUFFER_BACK_LEFT;
191 break;
192 case ST_ATTACHMENT_FRONT_RIGHT:
193 att = __DRI_BUFFER_FRONT_RIGHT;
194 break;
195 case ST_ATTACHMENT_BACK_RIGHT:
196 att = __DRI_BUFFER_BACK_RIGHT;
197 break;
198 case ST_ATTACHMENT_DEPTH_STENCIL:
199 att = __DRI_BUFFER_DEPTH_STENCIL;
200 break;
201 default:
202 att = -1;
203 break;
204 }
205
206 bpp = util_format_get_blocksizebits(format);
207
208 if (att >= 0) {
209 attachments[num_attachments++] = att;
210 if (with_format) {
211 attachments[num_attachments++] = bpp;
212 }
213 }
214 }
215
216 if (with_format) {
217 num_attachments /= 2;
218 buffers = loader->getBuffersWithFormat(dri_drawable,
219 &dri_drawable->w, &dri_drawable->h,
220 attachments, num_attachments,
221 &num_buffers, dri_drawable->loaderPrivate);
222 }
223 else {
224 buffers = loader->getBuffers(dri_drawable,
225 &dri_drawable->w, &dri_drawable->h,
226 attachments, num_attachments,
227 &num_buffers, dri_drawable->loaderPrivate);
228 }
229
230 if (buffers) {
231 /* set one cliprect to cover the whole dri_drawable */
232 dri_drawable->x = 0;
233 dri_drawable->y = 0;
234 dri_drawable->backX = 0;
235 dri_drawable->backY = 0;
236 dri_drawable->numClipRects = 1;
237 dri_drawable->pClipRects[0].x1 = 0;
238 dri_drawable->pClipRects[0].y1 = 0;
239 dri_drawable->pClipRects[0].x2 = dri_drawable->w;
240 dri_drawable->pClipRects[0].y2 = dri_drawable->h;
241 dri_drawable->numBackClipRects = 1;
242 dri_drawable->pBackClipRects[0].x1 = 0;
243 dri_drawable->pBackClipRects[0].y1 = 0;
244 dri_drawable->pBackClipRects[0].x2 = dri_drawable->w;
245 dri_drawable->pBackClipRects[0].y2 = dri_drawable->h;
246
247 *count = num_buffers;
248 }
249
250 return buffers;
251 }
252
253 /**
254 * Process __DRIbuffer and convert them into pipe_textures.
255 */
256 static void
257 dri2_drawable_process_buffers(struct dri_drawable *drawable,
258 __DRIbuffer *buffers, unsigned count)
259 {
260 struct dri_screen *screen = dri_screen(drawable->sPriv);
261 __DRIdrawable *dri_drawable = drawable->dPriv;
262 struct pipe_texture templ;
263 struct winsys_handle whandle;
264 boolean have_depth = FALSE;
265 unsigned i;
266
267 if (drawable->old_num == count &&
268 drawable->old_w == dri_drawable->w &&
269 drawable->old_h == dri_drawable->h &&
270 memcmp(drawable->old, buffers, sizeof(__DRIbuffer) * count) == 0)
271 return;
272
273 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
274 pipe_texture_reference(&drawable->textures[i], NULL);
275
276 memset(&templ, 0, sizeof(templ));
277 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
278 templ.target = PIPE_TEXTURE_2D;
279 templ.last_level = 0;
280 templ.width0 = dri_drawable->w;
281 templ.height0 = dri_drawable->h;
282 templ.depth0 = 1;
283
284 memset(&whandle, 0, sizeof(whandle));
285
286 for (i = 0; i < count; i++) {
287 __DRIbuffer *buf = &buffers[i];
288 enum st_attachment_type statt;
289 enum pipe_format format;
290
291 switch (buf->attachment) {
292 case __DRI_BUFFER_FRONT_LEFT:
293 if (!screen->auto_fake_front) {
294 statt = ST_ATTACHMENT_INVALID;
295 break;
296 }
297 /* fallthrough */
298 case __DRI_BUFFER_FAKE_FRONT_LEFT:
299 statt = ST_ATTACHMENT_FRONT_LEFT;
300 break;
301 case __DRI_BUFFER_BACK_LEFT:
302 statt = ST_ATTACHMENT_BACK_LEFT;
303 break;
304 case __DRI_BUFFER_DEPTH:
305 case __DRI_BUFFER_DEPTH_STENCIL:
306 case __DRI_BUFFER_STENCIL:
307 /* use only the first depth/stencil buffer */
308 if (!have_depth) {
309 have_depth = TRUE;
310 statt = ST_ATTACHMENT_DEPTH_STENCIL;
311 }
312 else {
313 statt = ST_ATTACHMENT_INVALID;
314 }
315 break;
316 default:
317 statt = ST_ATTACHMENT_INVALID;
318 break;
319 }
320
321 format = dri2_drawable_get_format(drawable, statt);
322 if (statt == ST_ATTACHMENT_INVALID || format == PIPE_FORMAT_NONE)
323 continue;
324
325 templ.format = format;
326 whandle.handle = buf->name;
327 whandle.stride = buf->pitch;
328
329 drawable->textures[statt] =
330 screen->pipe_screen->texture_from_handle(screen->pipe_screen,
331 &templ, &whandle);
332 }
333
334 drawable->old_num = count;
335 drawable->old_w = dri_drawable->w;
336 drawable->old_h = dri_drawable->h;
337 memcpy(drawable->old, buffers, sizeof(__DRIbuffer) * count);
338 }
339
340 /*
341 * Backend functions for st_framebuffer interface.
342 */
343
344 void
345 dri2_allocate_textures(struct dri_drawable *drawable,
346 const enum st_attachment_type *statts,
347 unsigned count)
348 {
349 __DRIbuffer *buffers;
350 unsigned num_buffers = count;
351
352 buffers = dri2_drawable_get_buffers(drawable, statts, &num_buffers);
353 dri2_drawable_process_buffers(drawable, buffers, num_buffers);
354 }
355
356 void
357 dri2_flush_frontbuffer(struct dri_drawable *drawable,
358 enum st_attachment_type statt)
359 {
360 __DRIdrawable *dri_drawable = drawable->dPriv;
361 struct __DRIdri2LoaderExtensionRec *loader = drawable->sPriv->dri2.loader;
362
363 if (loader->flushFrontBuffer == NULL)
364 return;
365
366 if (statt == ST_ATTACHMENT_FRONT_LEFT) {
367 loader->flushFrontBuffer(dri_drawable, dri_drawable->loaderPrivate);
368 }
369 }
370
371 __DRIimage *
372 dri2_lookup_egl_image(struct dri_context *ctx, void *handle)
373 {
374 __DRIimageLookupExtension *loader = ctx->sPriv->dri2.image;
375 __DRIimage *img;
376
377 if (!loader->lookupEGLImage)
378 return NULL;
379
380 img = loader->lookupEGLImage(ctx->cPriv, handle, ctx->cPriv->loaderPrivate);
381
382 return img;
383 }
384
385 static __DRIimage *
386 dri2_create_image_from_name(__DRIcontext *context,
387 int width, int height, int format,
388 int name, int pitch, void *loaderPrivate)
389 {
390 struct dri_screen *screen = dri_screen(context->driScreenPriv);
391 __DRIimage *img;
392 struct pipe_texture templ;
393 struct winsys_handle whandle;
394 unsigned tex_usage;
395 enum pipe_format pf;
396
397 tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | PIPE_TEXTURE_USAGE_SAMPLER;
398
399 switch (format) {
400 case __DRI_IMAGE_FORMAT_RGB565:
401 pf = PIPE_FORMAT_B5G6R5_UNORM;
402 break;
403 case __DRI_IMAGE_FORMAT_XRGB8888:
404 pf = PIPE_FORMAT_B8G8R8X8_UNORM;
405 break;
406 case __DRI_IMAGE_FORMAT_ARGB8888:
407 pf = PIPE_FORMAT_B8G8R8A8_UNORM;
408 break;
409 default:
410 pf = PIPE_FORMAT_NONE;
411 break;
412 }
413 if (pf == PIPE_FORMAT_NONE)
414 return NULL;
415
416 img = CALLOC_STRUCT(__DRIimageRec);
417 if (!img)
418 return NULL;
419
420 memset(&templ, 0, sizeof(templ));
421 templ.tex_usage = tex_usage;
422 templ.format = pf;
423 templ.target = PIPE_TEXTURE_2D;
424 templ.last_level = 0;
425 templ.width0 = width;
426 templ.height0 = height;
427 templ.depth0 = 1;
428
429 memset(&whandle, 0, sizeof(whandle));
430 whandle.handle = name;
431 whandle.stride = pitch * util_format_get_blocksize(pf);
432
433 img->texture = screen->pipe_screen->texture_from_handle(screen->pipe_screen,
434 &templ, &whandle);
435 if (!img->texture) {
436 FREE(img);
437 return NULL;
438 }
439
440 img->face = 0;
441 img->level = 0;
442 img->zslice = 0;
443 img->loader_private = loaderPrivate;
444
445 return img;
446 }
447
448 static __DRIimage *
449 dri2_create_image_from_renderbuffer(__DRIcontext *context,
450 int renderbuffer, void *loaderPrivate)
451 {
452 struct dri_context *ctx = dri_context(context->driverPrivate);
453
454 if (!ctx->st->get_resource_for_egl_image)
455 return NULL;
456
457 /* TODO */
458 return NULL;
459 }
460
461 static void
462 dri2_destroy_image(__DRIimage *img)
463 {
464 pipe_texture_reference(&img->texture, NULL);
465 FREE(img);
466 }
467
468 static struct __DRIimageExtensionRec dri2ImageExtension = {
469 { __DRI_IMAGE, __DRI_IMAGE_VERSION },
470 dri2_create_image_from_name,
471 dri2_create_image_from_renderbuffer,
472 dri2_destroy_image,
473 };
474
475 /*
476 * Backend function init_screen.
477 */
478
479 static const __DRIextension *dri_screen_extensions[] = {
480 &driReadDrawableExtension,
481 &driCopySubBufferExtension.base,
482 &driSwapControlExtension.base,
483 &driFrameTrackingExtension.base,
484 &driMediaStreamCounterExtension.base,
485 &dri2TexBufferExtension.base,
486 &dri2FlushExtension.base,
487 &dri2ImageExtension.base,
488 NULL
489 };
490
491 /**
492 * This is the driver specific part of the createNewScreen entry point.
493 *
494 * Returns the __GLcontextModes supported by this driver.
495 */
496 const __DRIconfig **
497 dri2_init_screen(__DRIscreen * sPriv)
498 {
499 const __DRIconfig **configs;
500 struct dri_screen *screen;
501 struct drm_create_screen_arg arg;
502
503 screen = CALLOC_STRUCT(dri_screen);
504 if (!screen)
505 return NULL;
506
507 screen->api = drm_api_create();
508 screen->sPriv = sPriv;
509 screen->fd = sPriv->fd;
510
511 sPriv->private = (void *)screen;
512 sPriv->extensions = dri_screen_extensions;
513
514 arg.mode = DRM_CREATE_NORMAL;
515
516 configs = dri_init_screen_helper(screen, &arg, 32);
517 if (!configs)
518 goto fail;
519
520 screen->auto_fake_front = dri_with_format(sPriv);
521
522 return configs;
523 fail:
524 dri_destroy_screen_helper(screen);
525 FREE(screen);
526 return NULL;
527 }
528
529 /* This is the table of extensions that the loader will dlsym() for. */
530 PUBLIC const __DRIextension *__driDriverExtensions[] = {
531 &driCoreExtension.base,
532 &driLegacyExtension.base,
533 &driDRI2Extension.base,
534 NULL
535 };
536
537 /* vim: set sw=3 ts=8 sts=3 expandtab: */