2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Author: Alan Hourihane <alanh@tungstengraphics.com>
27 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
31 #include "xorg-server.h"
33 #include "xf86_OSproc.h"
35 #include "xorg_tracker.h"
40 #include "pipe/p_state.h"
41 #include "util/u_inlines.h"
43 #include "util/u_format.h"
45 #include "state_tracker/drm_driver.h"
47 /* Make all the #if cases in the code esier to read */
48 #ifndef DRI2INFOREC_VERSION
49 #define DRI2INFOREC_VERSION 1
52 #if DRI2INFOREC_VERSION == 2
53 static Bool set_format_in_do_create_buffer
;
58 struct pipe_resource
*tex
;
59 struct pipe_fence_handle
*fence
;
63 dri2_do_create_buffer(DrawablePtr pDraw
, DRI2BufferPtr buffer
, unsigned int format
)
65 struct pipe_resource
*tex
= NULL
;
66 ScreenPtr pScreen
= pDraw
->pScreen
;
67 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
68 modesettingPtr ms
= modesettingPTR(pScrn
);
69 struct exa_pixmap_priv
*exa_priv
;
70 BufferPrivatePtr
private = buffer
->driverPrivate
;
72 struct winsys_handle whandle
;
74 if (pDraw
->type
== DRAWABLE_PIXMAP
)
75 pPixmap
= (PixmapPtr
) pDraw
;
77 pPixmap
= (*pScreen
->GetWindowPixmap
)((WindowPtr
) pDraw
);
78 exa_priv
= exaGetPixmapDriverPrivate(pPixmap
);
81 switch (buffer
->attachment
) {
83 if (buffer
->attachment
!= DRI2BufferFakeFrontLeft
||
84 pDraw
->type
!= DRAWABLE_PIXMAP
) {
85 private->pPixmap
= (*pScreen
->CreatePixmap
)(pScreen
, pDraw
->width
,
91 case DRI2BufferFrontLeft
:
93 case DRI2BufferStencil
:
94 #if DRI2INFOREC_VERSION >= 3
95 case DRI2BufferDepthStencil
:
97 /* Works on old X servers because sanity checking is for the weak */
100 if (exa_priv
->depth_stencil_tex
&&
101 !util_format_is_depth_or_stencil(exa_priv
->depth_stencil_tex
->format
))
102 exa_priv
->depth_stencil_tex
= NULL
;
104 case DRI2BufferDepth
:
105 if (exa_priv
->depth_stencil_tex
)
106 pipe_resource_reference(&tex
, exa_priv
->depth_stencil_tex
);
108 struct pipe_resource
template;
109 unsigned depthBits
= (format
!= 0) ? format
: pDraw
->depth
;
110 memset(&template, 0, sizeof(template));
111 template.target
= PIPE_TEXTURE_2D
;
112 if (buffer
->attachment
== DRI2BufferDepth
) {
115 template.format
= PIPE_FORMAT_Z16_UNORM
;
118 template.format
= PIPE_FORMAT_Z32_UNORM
;
121 template.format
= ms
->ds_depth_bits_last
?
122 PIPE_FORMAT_Z24X8_UNORM
: PIPE_FORMAT_X8Z24_UNORM
;
126 template.format
= ms
->ds_depth_bits_last
?
127 PIPE_FORMAT_Z24_UNORM_S8_USCALED
: PIPE_FORMAT_S8_USCALED_Z24_UNORM
;
129 template.width0
= pDraw
->width
;
130 template.height0
= pDraw
->height
;
132 template.last_level
= 0;
133 template.bind
= PIPE_BIND_DEPTH_STENCIL
|
135 tex
= ms
->screen
->resource_create(ms
->screen
, &template);
136 pipe_resource_reference(&exa_priv
->depth_stencil_tex
, tex
);
141 if (!private->pPixmap
) {
142 private->pPixmap
= pPixmap
;
147 /* First call to make sure we have a pixmap private */
148 exaMoveInPixmap(private->pPixmap
);
149 xorg_exa_set_shared_usage(private->pPixmap
);
150 pScreen
->ModifyPixmapHeader(private->pPixmap
, 0, 0, 0, 0, 0, NULL
);
151 /* Second call to make sure texture has valid contents */
152 exaMoveInPixmap(private->pPixmap
);
153 tex
= xorg_exa_get_texture(private->pPixmap
);
157 FatalError("NO TEXTURE IN DRI2\n");
159 memset(&whandle
, 0, sizeof(whandle
));
160 whandle
.type
= DRM_API_HANDLE_TYPE_SHARED
;
162 ms
->screen
->resource_get_handle(ms
->screen
, tex
, &whandle
);
164 buffer
->name
= whandle
.handle
;
165 buffer
->pitch
= whandle
.stride
;
167 buffer
->driverPrivate
= private;
168 buffer
->flags
= 0; /* not tiled */
169 #if DRI2INFOREC_VERSION == 2
170 /* ABI forwards/backwards compatibility */
171 if (set_format_in_do_create_buffer
)
172 ((DRI2Buffer2Ptr
)buffer
)->format
= 0;
173 #elif DRI2INFOREC_VERSION >= 3
182 dri2_do_destroy_buffer(DrawablePtr pDraw
, DRI2BufferPtr buffer
)
184 ScreenPtr pScreen
= pDraw
->pScreen
;
185 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
186 modesettingPtr ms
= modesettingPTR(pScrn
);
187 BufferPrivatePtr
private = buffer
->driverPrivate
;
188 struct exa_pixmap_priv
*exa_priv
= exaGetPixmapDriverPrivate(private->pPixmap
);
190 pipe_resource_reference(&private->tex
, NULL
);
191 ms
->screen
->fence_reference(ms
->screen
, &private->fence
, NULL
);
192 pipe_resource_reference(&exa_priv
->depth_stencil_tex
, NULL
);
193 (*pScreen
->DestroyPixmap
)(private->pPixmap
);
196 #if DRI2INFOREC_VERSION >= 2
198 static DRI2Buffer2Ptr
199 dri2_create_buffer(DrawablePtr pDraw
, unsigned int attachment
, unsigned int format
)
201 DRI2Buffer2Ptr buffer
;
202 BufferPrivatePtr
private;
204 buffer
= xcalloc(1, sizeof *buffer
);
208 private = xcalloc(1, sizeof *private);
213 buffer
->attachment
= attachment
;
214 buffer
->driverPrivate
= private;
216 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
217 if (dri2_do_create_buffer(pDraw
, (DRI2BufferPtr
)buffer
, format
))
227 dri2_destroy_buffer(DrawablePtr pDraw
, DRI2Buffer2Ptr buffer
)
229 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
230 dri2_do_destroy_buffer(pDraw
, (DRI2BufferPtr
)buffer
);
232 xfree(buffer
->driverPrivate
);
236 #endif /* DRI2INFOREC_VERSION >= 2 */
238 #if DRI2INFOREC_VERSION <= 2
241 dri2_create_buffers(DrawablePtr pDraw
, unsigned int *attachments
, int count
)
243 BufferPrivatePtr privates
;
244 DRI2BufferPtr buffers
;
247 buffers
= xcalloc(count
, sizeof *buffers
);
251 privates
= xcalloc(count
, sizeof *privates
);
255 for (i
= 0; i
< count
; i
++) {
256 buffers
[i
].attachment
= attachments
[i
];
257 buffers
[i
].driverPrivate
= &privates
[i
];
259 if (!dri2_do_create_buffer(pDraw
, &buffers
[i
], 0))
274 dri2_destroy_buffers(DrawablePtr pDraw
, DRI2BufferPtr buffers
, int count
)
278 for (i
= 0; i
< count
; i
++) {
279 dri2_do_destroy_buffer(pDraw
, &buffers
[i
]);
283 xfree(buffers
[0].driverPrivate
);
288 #endif /* DRI2INFOREC_VERSION <= 2 */
291 dri2_copy_region(DrawablePtr pDraw
, RegionPtr pRegion
,
292 DRI2BufferPtr pDestBuffer
, DRI2BufferPtr pSrcBuffer
)
294 ScreenPtr pScreen
= pDraw
->pScreen
;
295 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
296 modesettingPtr ms
= modesettingPTR(pScrn
);
297 BufferPrivatePtr dst_priv
= pDestBuffer
->driverPrivate
;
298 BufferPrivatePtr src_priv
= pSrcBuffer
->driverPrivate
;
299 DrawablePtr src_draw
;
300 DrawablePtr dst_draw
;
304 CustomizerPtr cust
= ms
->cust
;
307 * In driCreateBuffers we dewrap windows into the
308 * backing pixmaps in order to get to the texture.
309 * We need to use the real drawable in CopyArea
310 * so that cliprects and offsets are correct.
312 src_draw
= (pSrcBuffer
->attachment
== DRI2BufferFrontLeft
) ? pDraw
:
313 &src_priv
->pPixmap
->drawable
;
314 dst_draw
= (pDestBuffer
->attachment
== DRI2BufferFrontLeft
) ? pDraw
:
315 &dst_priv
->pPixmap
->drawable
;
318 * The clients implements glXWaitX with a copy front to fake and then
319 * waiting on the server to signal its completion of it. While
320 * glXWaitGL is a client side flush and a copy from fake to front.
321 * This is how it is done in the DRI2 protocol, how ever depending
322 * which type of drawables the server does things a bit differently
323 * then what the protocol says as the fake and front are the same.
325 * for pixmaps glXWaitX is a server flush.
326 * for pixmaps glXWaitGL is a client flush.
327 * for windows glXWaitX is a copy from front to fake then a server flush.
328 * for windows glXWaitGL is a client flush then a copy from fake to front.
330 * XXX in the windows case this code always flushes but that isn't a
331 * must in the glXWaitGL case but we don't know if this is a glXWaitGL
332 * or a glFlush/glFinish call.
334 if (dst_priv
->pPixmap
== src_priv
->pPixmap
) {
335 /* pixmap glXWaitX */
336 if (pSrcBuffer
->attachment
== DRI2BufferFrontLeft
&&
337 pDestBuffer
->attachment
== DRI2BufferFakeFrontLeft
) {
338 ms
->ctx
->flush(ms
->ctx
, PIPE_FLUSH_SWAPBUFFERS
, NULL
);
341 /* pixmap glXWaitGL */
342 if (pDestBuffer
->attachment
== DRI2BufferFrontLeft
&&
343 pSrcBuffer
->attachment
== DRI2BufferFakeFrontLeft
) {
346 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
347 "copying between the same pixmap\n");
351 gc
= GetScratchGC(pDraw
->depth
, pScreen
);
352 copy_clip
= REGION_CREATE(pScreen
, NULL
, 0);
353 REGION_COPY(pScreen
, copy_clip
, pRegion
);
354 (*gc
->funcs
->ChangeClip
) (gc
, CT_REGION
, copy_clip
, 0);
355 ValidateGC(dst_draw
, gc
);
357 /* If this is a full buffer swap, throttle on the previous one */
358 if (ms
->swapThrottling
&&
359 dst_priv
->fence
&& REGION_NUM_RECTS(pRegion
) == 1) {
360 BoxPtr extents
= REGION_EXTENTS(pScreen
, pRegion
);
362 if (extents
->x1
== 0 && extents
->y1
== 0 &&
363 extents
->x2
== pDraw
->width
&& extents
->y2
== pDraw
->height
) {
364 ms
->screen
->fence_finish(ms
->screen
, dst_priv
->fence
, 0);
365 ms
->screen
->fence_reference(ms
->screen
, &dst_priv
->fence
, NULL
);
369 /* Try to make sure the blit will be accelerated */
370 save_accel
= ms
->exa
->accel
;
371 ms
->exa
->accel
= TRUE
;
373 /* In case it won't be though, make sure the GPU copy contents of the
374 * source pixmap will be used for the software fallback - presumably the
375 * client modified them before calling in here.
377 exaMoveInPixmap(src_priv
->pPixmap
);
378 DamageRegionAppend(src_draw
, pRegion
);
379 DamageRegionProcessPending(src_draw
);
381 if (cust
&& cust
->winsys_context_throttle
)
382 cust
->winsys_context_throttle(cust
, ms
->ctx
, THROTTLE_SWAP
);
384 (*gc
->ops
->CopyArea
)(src_draw
, dst_draw
, gc
,
385 0, 0, pDraw
->width
, pDraw
->height
, 0, 0);
386 ms
->exa
->accel
= save_accel
;
390 ms
->ctx
->flush(ms
->ctx
, PIPE_FLUSH_SWAPBUFFERS
,
391 (pDestBuffer
->attachment
== DRI2BufferFrontLeft
392 && ms
->swapThrottling
) ?
393 &dst_priv
->fence
: NULL
);
395 if (cust
&& cust
->winsys_context_throttle
)
396 cust
->winsys_context_throttle(cust
, ms
->ctx
, THROTTLE_RENDER
);
401 xorg_dri2_init(ScreenPtr pScreen
)
403 ScrnInfoPtr pScrn
= xf86Screens
[pScreen
->myNum
];
404 modesettingPtr ms
= modesettingPTR(pScrn
);
405 DRI2InfoRec dri2info
;
406 #if DRI2INFOREC_VERSION >= 2
409 if (xf86LoaderCheckSymbol("DRI2Version")) {
410 DRI2Version(&major
, &minor
);
412 /* Assume version 1.0 */
418 dri2info
.version
= min(DRI2INFOREC_VERSION
, 3);
419 dri2info
.fd
= ms
->fd
;
421 dri2info
.driverName
= pScrn
->driverName
;
422 dri2info
.deviceName
= "/dev/dri/card0"; /* FIXME */
424 #if DRI2INFOREC_VERSION >= 2
425 dri2info
.CreateBuffer
= dri2_create_buffer
;
426 dri2info
.DestroyBuffer
= dri2_destroy_buffer
;
429 /* For X servers in the 1.6.x series there where two DRI2 version.
430 * This allows us to build one binary that works on both servers.
432 #if DRI2INFOREC_VERSION == 2
434 set_format_in_do_create_buffer
= FALSE
;
435 dri2info
.CreateBuffers
= dri2_create_buffers
;
436 dri2info
.DestroyBuffers
= dri2_destroy_buffers
;
438 set_format_in_do_create_buffer
= FALSE
;
441 /* For version 1 set these unconditionaly. */
442 #if DRI2INFOREC_VERSION == 1
443 dri2info
.CreateBuffers
= dri2_create_buffers
;
444 dri2info
.DestroyBuffers
= dri2_destroy_buffers
;
446 dri2info
.CopyRegion
= dri2_copy_region
;
447 dri2info
.Wait
= NULL
;
449 ms
->d_depth_bits_last
=
450 ms
->screen
->is_format_supported(ms
->screen
, PIPE_FORMAT_Z24X8_UNORM
,
453 PIPE_BIND_DEPTH_STENCIL
, 0);
454 ms
->ds_depth_bits_last
=
455 ms
->screen
->is_format_supported(ms
->screen
, PIPE_FORMAT_Z24_UNORM_S8_USCALED
,
458 PIPE_BIND_DEPTH_STENCIL
, 0);
460 return DRI2ScreenInit(pScreen
, &dri2info
);
464 xorg_dri2_close(ScreenPtr pScreen
)
466 DRI2CloseScreen(pScreen
);
469 /* vim: set sw=4 ts=8 sts=4: */