2 * Mesa 3-D graphics library
5 * Copyright 2009, VMware, Inc.
7 * Copyright (C) 2010 LunarG Inc.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
27 * Keith Whitwell <keithw@vmware.com>
28 * Jakob Bornecrantz <wallbraker@gmail.com>
29 * Chia-I Wu <olv@lunarg.com>
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_driver.h"
38 #include "dri_screen.h"
39 #include "dri_context.h"
40 #include "dri_drawable.h"
41 #include "dri2_buffer.h"
44 * DRI2 flush extension.
47 dri2_flush_drawable(__DRIdrawable
*dPriv
)
49 struct dri_context
*ctx
= dri_get_current(dPriv
->driScreenPriv
);
50 struct dri_drawable
*drawable
= dri_drawable(dPriv
);
52 struct pipe_resource
*ptex
= drawable
->textures
[ST_ATTACHMENT_BACK_LEFT
];
55 if (ptex
&& ctx
->pp
&& drawable
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
])
56 pp_run(ctx
->pp
, ptex
, ptex
, drawable
->textures
[ST_ATTACHMENT_DEPTH_STENCIL
]);
58 ctx
->st
->flush(ctx
->st
, 0, NULL
);
63 dri2_invalidate_drawable(__DRIdrawable
*dPriv
)
65 struct dri_drawable
*drawable
= dri_drawable(dPriv
);
67 dri2InvalidateDrawable(dPriv
);
68 drawable
->dPriv
->lastStamp
= drawable
->dPriv
->dri2
.stamp
;
70 p_atomic_inc(&drawable
->base
.stamp
);
73 static const __DRI2flushExtension dri2FlushExtension
= {
74 { __DRI2_FLUSH
, __DRI2_FLUSH_VERSION
},
76 dri2_invalidate_drawable
,
80 * Retrieve __DRIbuffer from the DRI loader.
83 dri2_drawable_get_buffers(struct dri_drawable
*drawable
,
84 const enum st_attachment_type
*statts
,
87 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
88 struct __DRIdri2LoaderExtensionRec
*loader
= drawable
->sPriv
->dri2
.loader
;
92 unsigned attachments
[10];
93 unsigned num_attachments
, i
;
96 with_format
= dri_with_format(drawable
->sPriv
);
100 /* for Xserver 1.6.0 (DRI2 version 1) we always need to ask for the front */
102 attachments
[num_attachments
++] = __DRI_BUFFER_FRONT_LEFT
;
104 for (i
= 0; i
< *count
; i
++) {
105 enum pipe_format format
;
109 dri_drawable_get_format(drawable
, statts
[i
], &format
, &bind
);
110 if (format
== PIPE_FORMAT_NONE
)
114 case ST_ATTACHMENT_FRONT_LEFT
:
118 att
= __DRI_BUFFER_FRONT_LEFT
;
120 case ST_ATTACHMENT_BACK_LEFT
:
121 att
= __DRI_BUFFER_BACK_LEFT
;
123 case ST_ATTACHMENT_FRONT_RIGHT
:
124 att
= __DRI_BUFFER_FRONT_RIGHT
;
126 case ST_ATTACHMENT_BACK_RIGHT
:
127 att
= __DRI_BUFFER_BACK_RIGHT
;
129 case ST_ATTACHMENT_DEPTH_STENCIL
:
130 att
= __DRI_BUFFER_DEPTH_STENCIL
;
138 * In this switch statement we must support all formats that
139 * may occur as the stvis->color_format or
140 * stvis->depth_stencil_format.
143 case PIPE_FORMAT_B8G8R8A8_UNORM
:
146 case PIPE_FORMAT_B8G8R8X8_UNORM
:
149 case PIPE_FORMAT_B5G6R5_UNORM
:
152 case PIPE_FORMAT_Z16_UNORM
:
153 att
= __DRI_BUFFER_DEPTH
;
156 case PIPE_FORMAT_Z24X8_UNORM
:
157 case PIPE_FORMAT_X8Z24_UNORM
:
158 att
= __DRI_BUFFER_DEPTH
;
161 case PIPE_FORMAT_Z24_UNORM_S8_UINT
:
162 case PIPE_FORMAT_S8_UINT_Z24_UNORM
:
165 case PIPE_FORMAT_Z32_UNORM
:
166 att
= __DRI_BUFFER_DEPTH
;
170 depth
= util_format_get_blocksizebits(format
);
171 assert(!"Unexpected format in dri2_drawable_get_buffers()");
175 attachments
[num_attachments
++] = att
;
177 attachments
[num_attachments
++] = depth
;
183 num_attachments
/= 2;
184 buffers
= loader
->getBuffersWithFormat(dri_drawable
,
185 &dri_drawable
->w
, &dri_drawable
->h
,
186 attachments
, num_attachments
,
187 &num_buffers
, dri_drawable
->loaderPrivate
);
190 buffers
= loader
->getBuffers(dri_drawable
,
191 &dri_drawable
->w
, &dri_drawable
->h
,
192 attachments
, num_attachments
,
193 &num_buffers
, dri_drawable
->loaderPrivate
);
197 *count
= num_buffers
;
203 * Process __DRIbuffer and convert them into pipe_resources.
206 dri2_drawable_process_buffers(struct dri_drawable
*drawable
,
207 __DRIbuffer
*buffers
, unsigned count
)
209 struct dri_screen
*screen
= dri_screen(drawable
->sPriv
);
210 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
211 struct pipe_resource templ
;
212 struct winsys_handle whandle
;
213 boolean have_depth
= FALSE
;
216 if (drawable
->old_num
== count
&&
217 drawable
->old_w
== dri_drawable
->w
&&
218 drawable
->old_h
== dri_drawable
->h
&&
219 memcmp(drawable
->old
, buffers
, sizeof(__DRIbuffer
) * count
) == 0)
222 for (i
= 0; i
< ST_ATTACHMENT_COUNT
; i
++)
223 pipe_resource_reference(&drawable
->textures
[i
], NULL
);
225 memset(&templ
, 0, sizeof(templ
));
226 templ
.target
= screen
->target
;
227 templ
.last_level
= 0;
228 templ
.width0
= dri_drawable
->w
;
229 templ
.height0
= dri_drawable
->h
;
231 templ
.array_size
= 1;
233 memset(&whandle
, 0, sizeof(whandle
));
235 for (i
= 0; i
< count
; i
++) {
236 __DRIbuffer
*buf
= &buffers
[i
];
237 enum st_attachment_type statt
;
238 enum pipe_format format
;
240 switch (buf
->attachment
) {
241 case __DRI_BUFFER_FRONT_LEFT
:
242 if (!screen
->auto_fake_front
) {
243 statt
= ST_ATTACHMENT_INVALID
;
247 case __DRI_BUFFER_FAKE_FRONT_LEFT
:
248 statt
= ST_ATTACHMENT_FRONT_LEFT
;
250 case __DRI_BUFFER_BACK_LEFT
:
251 statt
= ST_ATTACHMENT_BACK_LEFT
;
253 case __DRI_BUFFER_DEPTH
:
254 case __DRI_BUFFER_DEPTH_STENCIL
:
255 case __DRI_BUFFER_STENCIL
:
256 /* use only the first depth/stencil buffer */
259 statt
= ST_ATTACHMENT_DEPTH_STENCIL
;
262 statt
= ST_ATTACHMENT_INVALID
;
266 statt
= ST_ATTACHMENT_INVALID
;
270 dri_drawable_get_format(drawable
, statt
, &format
, &bind
);
271 if (statt
== ST_ATTACHMENT_INVALID
|| format
== PIPE_FORMAT_NONE
)
274 templ
.format
= format
;
276 whandle
.handle
= buf
->name
;
277 whandle
.stride
= buf
->pitch
;
279 drawable
->textures
[statt
] =
280 screen
->base
.screen
->resource_from_handle(screen
->base
.screen
,
284 drawable
->old_num
= count
;
285 drawable
->old_w
= dri_drawable
->w
;
286 drawable
->old_h
= dri_drawable
->h
;
287 memcpy(drawable
->old
, buffers
, sizeof(__DRIbuffer
) * count
);
291 dri2_allocate_buffer(__DRIscreen
*sPriv
,
292 unsigned attachment
, unsigned format
,
293 int width
, int height
)
295 struct dri_screen
*screen
= dri_screen(sPriv
);
296 struct dri2_buffer
*buffer
;
297 struct pipe_resource templ
;
300 struct winsys_handle whandle
;
302 switch (attachment
) {
303 case __DRI_BUFFER_FRONT_LEFT
:
304 case __DRI_BUFFER_FAKE_FRONT_LEFT
:
305 bind
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
307 case __DRI_BUFFER_BACK_LEFT
:
308 bind
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
310 case __DRI_BUFFER_DEPTH
:
311 case __DRI_BUFFER_DEPTH_STENCIL
:
312 case __DRI_BUFFER_STENCIL
:
313 bind
= PIPE_BIND_DEPTH_STENCIL
; /* XXX sampler? */
317 /* because we get the handle and stride */
318 bind
|= PIPE_BIND_SHARED
;
322 pf
= PIPE_FORMAT_B8G8R8A8_UNORM
;
325 pf
= PIPE_FORMAT_B8G8R8X8_UNORM
;
328 pf
= PIPE_FORMAT_Z16_UNORM
;
334 buffer
= CALLOC_STRUCT(dri2_buffer
);
338 memset(&templ
, 0, sizeof(templ
));
341 templ
.target
= PIPE_TEXTURE_2D
;
342 templ
.last_level
= 0;
343 templ
.width0
= width
;
344 templ
.height0
= height
;
346 templ
.array_size
= 1;
349 screen
->base
.screen
->resource_create(screen
->base
.screen
, &templ
);
350 if (!buffer
->resource
) {
355 memset(&whandle
, 0, sizeof(whandle
));
356 whandle
.type
= DRM_API_HANDLE_TYPE_SHARED
;
357 screen
->base
.screen
->resource_get_handle(screen
->base
.screen
,
358 buffer
->resource
, &whandle
);
360 buffer
->base
.attachment
= attachment
;
361 buffer
->base
.name
= whandle
.handle
;
362 buffer
->base
.cpp
= util_format_get_blocksize(pf
);
363 buffer
->base
.pitch
= whandle
.stride
;
365 return &buffer
->base
;
369 dri2_release_buffer(__DRIscreen
*sPriv
, __DRIbuffer
*bPriv
)
371 struct dri2_buffer
*buffer
= dri2_buffer(bPriv
);
373 pipe_resource_reference(&buffer
->resource
, NULL
);
378 * Backend functions for st_framebuffer interface.
382 dri2_allocate_textures(struct dri_drawable
*drawable
,
383 const enum st_attachment_type
*statts
,
386 __DRIbuffer
*buffers
;
387 unsigned num_buffers
= count
;
389 buffers
= dri2_drawable_get_buffers(drawable
, statts
, &num_buffers
);
391 dri2_drawable_process_buffers(drawable
, buffers
, num_buffers
);
395 dri2_flush_frontbuffer(struct dri_drawable
*drawable
,
396 enum st_attachment_type statt
)
398 __DRIdrawable
*dri_drawable
= drawable
->dPriv
;
399 struct __DRIdri2LoaderExtensionRec
*loader
= drawable
->sPriv
->dri2
.loader
;
401 if (loader
->flushFrontBuffer
== NULL
)
404 if (statt
== ST_ATTACHMENT_FRONT_LEFT
) {
405 loader
->flushFrontBuffer(dri_drawable
, dri_drawable
->loaderPrivate
);
410 dri2_update_tex_buffer(struct dri_drawable
*drawable
,
411 struct dri_context
*ctx
,
412 struct pipe_resource
*res
)
418 dri2_lookup_egl_image(struct dri_screen
*screen
, void *handle
)
420 __DRIimageLookupExtension
*loader
= screen
->sPriv
->dri2
.image
;
423 if (!loader
->lookupEGLImage
)
426 img
= loader
->lookupEGLImage(screen
->sPriv
,
427 handle
, screen
->sPriv
->loaderPrivate
);
433 dri2_create_image_from_name(__DRIscreen
*_screen
,
434 int width
, int height
, int format
,
435 int name
, int pitch
, void *loaderPrivate
)
437 struct dri_screen
*screen
= dri_screen(_screen
);
439 struct pipe_resource templ
;
440 struct winsys_handle whandle
;
444 tex_usage
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
447 case __DRI_IMAGE_FORMAT_RGB565
:
448 pf
= PIPE_FORMAT_B5G6R5_UNORM
;
450 case __DRI_IMAGE_FORMAT_XRGB8888
:
451 pf
= PIPE_FORMAT_B8G8R8X8_UNORM
;
453 case __DRI_IMAGE_FORMAT_ARGB8888
:
454 pf
= PIPE_FORMAT_B8G8R8A8_UNORM
;
456 case __DRI_IMAGE_FORMAT_ABGR8888
:
457 pf
= PIPE_FORMAT_R8G8B8A8_UNORM
;
460 pf
= PIPE_FORMAT_NONE
;
463 if (pf
== PIPE_FORMAT_NONE
)
466 img
= CALLOC_STRUCT(__DRIimageRec
);
470 memset(&templ
, 0, sizeof(templ
));
471 templ
.bind
= tex_usage
;
473 templ
.target
= screen
->target
;
474 templ
.last_level
= 0;
475 templ
.width0
= width
;
476 templ
.height0
= height
;
478 templ
.array_size
= 1;
480 memset(&whandle
, 0, sizeof(whandle
));
481 whandle
.handle
= name
;
482 whandle
.stride
= pitch
* util_format_get_blocksize(pf
);
484 img
->texture
= screen
->base
.screen
->resource_from_handle(screen
->base
.screen
,
493 img
->dri_format
= format
;
494 img
->loader_private
= loaderPrivate
;
500 dri2_create_image_from_renderbuffer(__DRIcontext
*context
,
501 int renderbuffer
, void *loaderPrivate
)
503 struct dri_context
*ctx
= dri_context(context
);
505 if (!ctx
->st
->get_resource_for_egl_image
)
513 dri2_create_image(__DRIscreen
*_screen
,
514 int width
, int height
, int format
,
515 unsigned int use
, void *loaderPrivate
)
517 struct dri_screen
*screen
= dri_screen(_screen
);
519 struct pipe_resource templ
;
523 tex_usage
= PIPE_BIND_RENDER_TARGET
| PIPE_BIND_SAMPLER_VIEW
;
524 if (use
& __DRI_IMAGE_USE_SCANOUT
)
525 tex_usage
|= PIPE_BIND_SCANOUT
;
526 if (use
& __DRI_IMAGE_USE_SHARE
)
527 tex_usage
|= PIPE_BIND_SHARED
;
528 if (use
& __DRI_IMAGE_USE_CURSOR
) {
529 if (width
!= 64 || height
!= 64)
531 tex_usage
|= PIPE_BIND_CURSOR
;
535 case __DRI_IMAGE_FORMAT_RGB565
:
536 pf
= PIPE_FORMAT_B5G6R5_UNORM
;
538 case __DRI_IMAGE_FORMAT_XRGB8888
:
539 pf
= PIPE_FORMAT_B8G8R8X8_UNORM
;
541 case __DRI_IMAGE_FORMAT_ARGB8888
:
542 pf
= PIPE_FORMAT_B8G8R8A8_UNORM
;
544 case __DRI_IMAGE_FORMAT_ABGR8888
:
545 pf
= PIPE_FORMAT_R8G8B8A8_UNORM
;
548 pf
= PIPE_FORMAT_NONE
;
551 if (pf
== PIPE_FORMAT_NONE
)
554 img
= CALLOC_STRUCT(__DRIimageRec
);
558 memset(&templ
, 0, sizeof(templ
));
559 templ
.bind
= tex_usage
;
561 templ
.target
= PIPE_TEXTURE_2D
;
562 templ
.last_level
= 0;
563 templ
.width0
= width
;
564 templ
.height0
= height
;
566 templ
.array_size
= 1;
568 img
->texture
= screen
->base
.screen
->resource_create(screen
->base
.screen
, &templ
);
576 img
->dri_format
= format
;
578 img
->loader_private
= loaderPrivate
;
583 dri2_query_image(__DRIimage
*image
, int attrib
, int *value
)
585 struct winsys_handle whandle
;
586 memset(&whandle
, 0, sizeof(whandle
));
589 case __DRI_IMAGE_ATTRIB_STRIDE
:
590 image
->texture
->screen
->resource_get_handle(image
->texture
->screen
,
591 image
->texture
, &whandle
);
592 *value
= whandle
.stride
;
594 case __DRI_IMAGE_ATTRIB_HANDLE
:
595 whandle
.type
= DRM_API_HANDLE_TYPE_KMS
;
596 image
->texture
->screen
->resource_get_handle(image
->texture
->screen
,
597 image
->texture
, &whandle
);
598 *value
= whandle
.handle
;
600 case __DRI_IMAGE_ATTRIB_NAME
:
601 whandle
.type
= DRM_API_HANDLE_TYPE_SHARED
;
602 image
->texture
->screen
->resource_get_handle(image
->texture
->screen
,
603 image
->texture
, &whandle
);
604 *value
= whandle
.handle
;
606 case __DRI_IMAGE_ATTRIB_FORMAT
:
607 *value
= image
->dri_format
;
615 dri2_dup_image(__DRIimage
*image
, void *loaderPrivate
)
619 img
= CALLOC_STRUCT(__DRIimageRec
);
624 pipe_resource_reference(&img
->texture
, image
->texture
);
625 img
->level
= image
->level
;
626 img
->layer
= image
->layer
;
627 img
->loader_private
= loaderPrivate
;
633 dri2_validate_usage(__DRIimage
*image
, unsigned int use
)
636 * Gallium drivers are bad at adding usages to the resources
637 * once opened again in another process, which is the main use
638 * case for this, so we have to lie.
647 dri2_destroy_image(__DRIimage
*img
)
649 pipe_resource_reference(&img
->texture
, NULL
);
653 static struct __DRIimageExtensionRec dri2ImageExtension
= {
655 dri2_create_image_from_name
,
656 dri2_create_image_from_renderbuffer
,
665 * Backend function init_screen.
668 static const __DRIextension
*dri_screen_extensions
[] = {
669 &driTexBufferExtension
.base
,
670 &dri2FlushExtension
.base
,
671 &dri2ImageExtension
.base
,
672 &dri2ConfigQueryExtension
.base
,
676 static const __DRIextension
*dri_screen_extensions_throttle
[] = {
677 &driTexBufferExtension
.base
,
678 &dri2FlushExtension
.base
,
679 &dri2ImageExtension
.base
,
680 &dri2ConfigQueryExtension
.base
,
681 &dri2ThrottleExtension
.base
,
686 * This is the driver specific part of the createNewScreen entry point.
688 * Returns the struct gl_config supported by this driver.
690 static const __DRIconfig
**
691 dri2_init_screen(__DRIscreen
* sPriv
)
693 const __DRIconfig
**configs
;
694 struct dri_screen
*screen
;
695 struct pipe_screen
*pscreen
;
696 const struct drm_conf_ret
*throttle_ret
= NULL
;
698 screen
= CALLOC_STRUCT(dri_screen
);
702 screen
->sPriv
= sPriv
;
703 screen
->fd
= sPriv
->fd
;
705 sPriv
->driverPrivate
= (void *)screen
;
707 pscreen
= driver_descriptor
.create_screen(screen
->fd
);
708 if (driver_descriptor
.configuration
)
709 throttle_ret
= driver_descriptor
.configuration(DRM_CONF_THROTTLE
);
711 if (throttle_ret
&& throttle_ret
->val
.val_int
!= -1) {
712 sPriv
->extensions
= dri_screen_extensions_throttle
;
713 screen
->default_throttle_frames
= throttle_ret
->val
.val_int
;
715 sPriv
->extensions
= dri_screen_extensions
;
717 /* dri_init_screen_helper checks pscreen for us */
719 configs
= dri_init_screen_helper(screen
, pscreen
, 32);
724 if (screen
->st_api
->profile_mask
& ST_PROFILE_DEFAULT_MASK
)
725 sPriv
->api_mask
|= 1 << __DRI_API_OPENGL
;
726 if (screen
->st_api
->profile_mask
& ST_PROFILE_OPENGL_ES1_MASK
)
727 sPriv
->api_mask
|= 1 << __DRI_API_GLES
;
728 if (screen
->st_api
->profile_mask
& ST_PROFILE_OPENGL_ES2_MASK
)
729 sPriv
->api_mask
|= 1 << __DRI_API_GLES2
;
731 screen
->auto_fake_front
= dri_with_format(sPriv
);
732 screen
->broken_invalidate
= !sPriv
->dri2
.useInvalidate
;
733 screen
->lookup_egl_image
= dri2_lookup_egl_image
;
737 dri_destroy_screen_helper(screen
);
743 dri2_create_buffer(__DRIscreen
* sPriv
,
744 __DRIdrawable
* dPriv
,
745 const struct gl_config
* visual
, boolean isPixmap
)
747 struct dri_drawable
*drawable
= NULL
;
749 if (!dri_create_buffer(sPriv
, dPriv
, visual
, isPixmap
))
752 drawable
= dPriv
->driverPrivate
;
754 drawable
->allocate_textures
= dri2_allocate_textures
;
755 drawable
->flush_frontbuffer
= dri2_flush_frontbuffer
;
756 drawable
->update_tex_buffer
= dri2_update_tex_buffer
;
762 * DRI driver virtual function table.
764 * DRI versions differ in their implementation of init_screen and swap_buffers.
766 const struct __DriverAPIRec driDriverAPI
= {
767 .InitScreen
= dri2_init_screen
,
768 .DestroyScreen
= dri_destroy_screen
,
769 .CreateContext
= dri_create_context
,
770 .DestroyContext
= dri_destroy_context
,
771 .CreateBuffer
= dri2_create_buffer
,
772 .DestroyBuffer
= dri_destroy_buffer
,
773 .MakeCurrent
= dri_make_current
,
774 .UnbindContext
= dri_unbind_context
,
776 .AllocateBuffer
= dri2_allocate_buffer
,
777 .ReleaseBuffer
= dri2_release_buffer
,
780 /* This is the table of extensions that the loader will dlsym() for. */
781 PUBLIC
const __DRIextension
*__driDriverExtensions
[] = {
782 &driCoreExtension
.base
,
783 &driDRI2Extension
.base
,
787 /* vim: set sw=3 ts=8 sts=3 expandtab: */