f2dac73e908c75ad544c0e6e8204e3884a33f389
[mesa.git] / src / gallium / state_trackers / xorg / xorg_exa.c
1 /*
2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3 * All Rights Reserved.
4 *
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:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
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.
24 *
25 *
26 * Author: Alan Hourihane <alanh@tungstengraphics.com>
27 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
28 *
29 */
30
31 #include "xorg_exa.h"
32 #include "xorg_tracker.h"
33 #include "xorg_composite.h"
34
35 #include <xorg-server.h>
36 #include <xf86.h>
37 #include <picturestr.h>
38 #include <picture.h>
39
40 #include "pipe/p_format.h"
41 #include "pipe/p_context.h"
42 #include "pipe/p_state.h"
43 #include "pipe/p_inlines.h"
44
45 #include "util/u_rect.h"
46
47 /*
48 * Helper functions
49 */
50
51 static void
52 exa_get_pipe_format(int depth, enum pipe_format *format, int *bbp)
53 {
54 switch (depth) {
55 case 32:
56 *format = PIPE_FORMAT_A8R8G8B8_UNORM;
57 assert(*bbp == 32);
58 break;
59 case 24:
60 *format = PIPE_FORMAT_X8R8G8B8_UNORM;
61 assert(*bbp == 32);
62 break;
63 case 16:
64 *format = PIPE_FORMAT_R5G6B5_UNORM;
65 assert(*bbp == 16);
66 break;
67 case 15:
68 *format = PIPE_FORMAT_A1R5G5B5_UNORM;
69 assert(*bbp == 16);
70 break;
71 case 8:
72 case 4:
73 case 1:
74 *format = PIPE_FORMAT_A8R8G8B8_UNORM; /* bad bad bad */
75 break;
76 default:
77 assert(0);
78 break;
79 }
80 }
81
82 /*
83 * Static exported EXA functions
84 */
85
86 static void
87 ExaWaitMarker(ScreenPtr pScreen, int marker)
88 {
89 }
90
91 static int
92 ExaMarkSync(ScreenPtr pScreen)
93 {
94 return 1;
95 }
96
97 static Bool
98 ExaPrepareAccess(PixmapPtr pPix, int index)
99 {
100 ScreenPtr pScreen = pPix->drawable.pScreen;
101 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
102 modesettingPtr ms = modesettingPTR(pScrn);
103 struct exa_context *exa = ms->exa;
104 struct exa_pixmap_priv *priv;
105
106 priv = exaGetPixmapDriverPrivate(pPix);
107
108 if (!priv)
109 return FALSE;
110
111 if (!priv->tex)
112 return FALSE;
113
114 if (priv->map_count++ == 0)
115 {
116 priv->map_transfer =
117 exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0,
118 PIPE_TRANSFER_READ_WRITE,
119 0, 0, priv->tex->width[0], priv->tex->height[0]);
120
121 pPix->devPrivate.ptr =
122 exa->scrn->transfer_map(exa->scrn, priv->map_transfer);
123 pPix->devKind = priv->map_transfer->stride;
124 }
125
126 return TRUE;
127 }
128
129 static void
130 ExaFinishAccess(PixmapPtr pPix, int index)
131 {
132 ScreenPtr pScreen = pPix->drawable.pScreen;
133 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
134 modesettingPtr ms = modesettingPTR(pScrn);
135 struct exa_context *exa = ms->exa;
136 struct exa_pixmap_priv *priv;
137 priv = exaGetPixmapDriverPrivate(pPix);
138
139 if (!priv)
140 return;
141
142 if (!priv->map_transfer)
143 return;
144
145 if (--priv->map_count == 0) {
146 assert(priv->map_transfer);
147 exa->scrn->transfer_unmap(exa->scrn, priv->map_transfer);
148 exa->scrn->tex_transfer_destroy(priv->map_transfer);
149 priv->map_transfer = NULL;
150 }
151 }
152
153 static void
154 ExaDone(PixmapPtr pPixmap)
155 {
156 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
157 modesettingPtr ms = modesettingPTR(pScrn);
158 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
159 struct exa_context *exa = ms->exa;
160
161 if (!priv)
162 return;
163
164 if (priv->src_surf)
165 exa->scrn->tex_surface_destroy(priv->src_surf);
166 priv->src_surf = NULL;
167 }
168
169 static void
170 ExaDoneComposite(PixmapPtr pPixmap)
171 {
172
173 }
174
175 static Bool
176 ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
177 {
178 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
179 modesettingPtr ms = modesettingPTR(pScrn);
180 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
181 struct exa_context *exa = ms->exa;
182
183 if (1)
184 return FALSE;
185
186 if (pPixmap->drawable.depth < 15)
187 return FALSE;
188
189 if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask))
190 return FALSE;
191
192 if (!priv || !priv->tex)
193 return FALSE;
194
195 if (alu != GXcopy)
196 return FALSE;
197
198 if (!exa->ctx || !exa->ctx->surface_fill)
199 return FALSE;
200
201 priv->color = fg;
202
203 return TRUE;
204 }
205
206 static void
207 ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1)
208 {
209 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
210 modesettingPtr ms = modesettingPTR(pScrn);
211 struct exa_context *exa = ms->exa;
212 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
213 struct pipe_surface *surf =
214 exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
215 PIPE_BUFFER_USAGE_GPU_READ |
216 PIPE_BUFFER_USAGE_GPU_WRITE);
217
218 exa->ctx->surface_fill(exa->ctx, surf, x0, y0, x1 - x0, y1 - y0,
219 priv->color);
220
221 exa->scrn->tex_surface_destroy(surf);
222 }
223
224 static Bool
225 ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
226 int ydir, int alu, Pixel planeMask)
227 {
228 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
229 modesettingPtr ms = modesettingPTR(pScrn);
230 struct exa_context *exa = ms->exa;
231 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
232 struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);
233
234 if (1)
235 return FALSE;
236
237 if (alu != GXcopy)
238 return FALSE;
239
240 if (pSrcPixmap->drawable.depth < 15 || pDstPixmap->drawable.depth < 15)
241 return FALSE;
242
243 if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
244 return FALSE;
245
246 if (!priv || !src_priv)
247 return FALSE;
248
249 if (!priv->tex || !src_priv->tex)
250 return FALSE;
251
252 if (!exa->ctx || !exa->ctx->surface_copy)
253 return FALSE;
254
255 priv->src_surf =
256 exa->scrn->get_tex_surface(exa->scrn, src_priv->tex, 0, 0, 0,
257 PIPE_BUFFER_USAGE_GPU_READ |
258 PIPE_BUFFER_USAGE_GPU_WRITE);
259
260 return TRUE;
261 }
262
263 static void
264 ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
265 int width, int height)
266 {
267 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
268 modesettingPtr ms = modesettingPTR(pScrn);
269 struct exa_context *exa = ms->exa;
270 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
271 struct pipe_surface *surf =
272 exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
273 PIPE_BUFFER_USAGE_GPU_READ |
274 PIPE_BUFFER_USAGE_GPU_WRITE);
275
276 exa->ctx->surface_copy(exa->ctx, surf, dstX, dstY, priv->src_surf,
277 srcX, srcY, width, height);
278 exa->scrn->tex_surface_destroy(surf);
279 }
280
281 static Bool
282 ExaPrepareComposite(int op, PicturePtr pSrcPicture,
283 PicturePtr pMaskPicture, PicturePtr pDstPicture,
284 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
285 {
286 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
287 modesettingPtr ms = modesettingPTR(pScrn);
288 struct exa_context *exa = ms->exa;
289
290 return xorg_composite_bind_state(exa, op, pSrcPicture, pMaskPicture,
291 pDstPicture);
292 }
293
294 static void
295 ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
296 int dstX, int dstY, int width, int height)
297 {
298 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
299 modesettingPtr ms = modesettingPTR(pScrn);
300 struct exa_context *exa = ms->exa;
301 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDst);
302
303 xorg_composite(exa, priv, srcX, srcY, maskX, maskY,
304 dstX, dstY, width, height);
305 }
306
307 static Bool
308 ExaCheckComposite(int op,
309 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
310 PicturePtr pDstPicture)
311 {
312 return xorg_composite_accelerated(op,
313 pSrcPicture,
314 pMaskPicture,
315 pDstPicture);
316 }
317
318 static void *
319 ExaCreatePixmap(ScreenPtr pScreen, int size, int align)
320 {
321 struct exa_pixmap_priv *priv;
322
323 priv = xcalloc(1, sizeof(struct exa_pixmap_priv));
324 if (!priv)
325 return NULL;
326
327 return priv;
328 }
329
330 static void
331 ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv)
332 {
333 struct exa_pixmap_priv *priv = (struct exa_pixmap_priv *)dPriv;
334 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
335 modesettingPtr ms = modesettingPTR(pScrn);
336
337 if (!priv)
338 return;
339
340 if (priv->tex)
341 ms->screen->texture_destroy(priv->tex);
342
343 xfree(priv);
344 }
345
346 static Bool
347 ExaPixmapIsOffscreen(PixmapPtr pPixmap)
348 {
349 struct exa_pixmap_priv *priv;
350
351 priv = exaGetPixmapDriverPrivate(pPixmap);
352
353 if (!priv)
354 return FALSE;
355
356 if (priv->tex)
357 return TRUE;
358
359 return FALSE;
360 }
361
362 int
363 xorg_exa_set_displayed_usage(PixmapPtr pPixmap)
364 {
365 struct exa_pixmap_priv *priv;
366 priv = exaGetPixmapDriverPrivate(pPixmap);
367
368 if (!priv) {
369 FatalError("NO PIXMAP PRIVATE\n");
370 return 0;
371 }
372
373 if (priv->flags & ~PIPE_TEXTURE_USAGE_PRIMARY) {
374 FatalError("BAD FLAGS\n");
375 return 0;
376 }
377 priv->flags = PIPE_TEXTURE_USAGE_PRIMARY;
378
379 return 0;
380 }
381
382 int
383 xorg_exa_set_shared_usage(PixmapPtr pPixmap)
384 {
385 struct exa_pixmap_priv *priv;
386 priv = exaGetPixmapDriverPrivate(pPixmap);
387
388 if (!priv) {
389 FatalError("NO PIXMAP PRIVATE\n");
390 return 0;
391 }
392
393 if (priv->flags & ~PIPE_TEXTURE_USAGE_DISPLAY_TARGET) {
394 FatalError("BAD FLAGS\n");
395 return 0;
396 }
397 priv->flags = PIPE_TEXTURE_USAGE_DISPLAY_TARGET;
398
399 return 0;
400 }
401
402 unsigned
403 xorg_exa_get_pixmap_handle(PixmapPtr pPixmap, unsigned *stride_out)
404 {
405 ScreenPtr pScreen = pPixmap->drawable.pScreen;
406 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
407 modesettingPtr ms = modesettingPTR(pScrn);
408 struct exa_pixmap_priv *priv;
409 struct pipe_buffer *buffer = NULL;
410 unsigned handle;
411 unsigned stride;
412
413 if (!ms->exa) {
414 FatalError("NO MS->EXA\n");
415 return 0;
416 }
417
418 priv = exaGetPixmapDriverPrivate(pPixmap);
419
420 if (!priv) {
421 FatalError("NO PIXMAP PRIVATE\n");
422 return 0;
423 }
424
425 ms->api->buffer_from_texture(ms->api, priv->tex, &buffer, &stride);
426 ms->api->handle_from_buffer(ms->api, ms->screen, buffer, &handle);
427 pipe_buffer_reference(&buffer, NULL);
428 if (stride_out)
429 *stride_out = stride;
430
431 return handle;
432 }
433
434 static Bool
435 ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
436 int depth, int bitsPerPixel, int devKind,
437 pointer pPixData)
438 {
439 ScreenPtr pScreen = pPixmap->drawable.pScreen;
440 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
441 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
442 modesettingPtr ms = modesettingPTR(pScrn);
443 struct exa_context *exa = ms->exa;
444
445 if (!priv)
446 return FALSE;
447
448 if (depth <= 0)
449 depth = pPixmap->drawable.depth;
450
451 if (bitsPerPixel <= 0)
452 bitsPerPixel = pPixmap->drawable.bitsPerPixel;
453
454 if (width <= 0)
455 width = pPixmap->drawable.width;
456
457 if (height <= 0)
458 height = pPixmap->drawable.height;
459
460 if (width <= 0 || height <= 0 || depth <= 0)
461 return FALSE;
462
463 miModifyPixmapHeader(pPixmap, width, height, depth,
464 bitsPerPixel, devKind, NULL);
465
466 /* Deal with screen resize */
467 if (priv->tex && (priv->tex->width[0] != width ||
468 priv->tex->height[0] != height ||
469 priv->tex_flags != priv->flags)) {
470 pipe_texture_reference(&priv->tex, NULL);
471 }
472
473 if (!priv->tex) {
474 struct pipe_texture template;
475
476 memset(&template, 0, sizeof(template));
477 template.target = PIPE_TEXTURE_2D;
478 exa_get_pipe_format(depth, &template.format, &bitsPerPixel);
479 pf_get_block(template.format, &template.block);
480 template.width[0] = width;
481 template.height[0] = height;
482 template.depth[0] = 1;
483 template.last_level = 0;
484 template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | priv->flags;
485 priv->tex_flags = priv->flags;
486 priv->tex = exa->scrn->texture_create(exa->scrn, &template);
487 }
488
489 if (pPixData) {
490 struct pipe_transfer *transfer =
491 exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0,
492 PIPE_TRANSFER_WRITE,
493 0, 0, width, height);
494 pipe_copy_rect(exa->scrn->transfer_map(exa->scrn, transfer),
495 &priv->tex->block, transfer->stride, 0, 0,
496 width, height, pPixData, pPixmap->devKind, 0, 0);
497 exa->scrn->transfer_unmap(exa->scrn, transfer);
498 exa->scrn->tex_transfer_destroy(transfer);
499 }
500
501 return TRUE;
502 }
503
504 struct pipe_texture *
505 xorg_exa_get_texture(PixmapPtr pPixmap)
506 {
507 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
508 struct pipe_texture *tex = NULL;
509 pipe_texture_reference(&tex, priv->tex);
510 return tex;
511 }
512
513 void
514 xorg_exa_close(ScrnInfoPtr pScrn)
515 {
516 modesettingPtr ms = modesettingPTR(pScrn);
517 struct exa_context *exa = ms->exa;
518
519 if (exa->ctx)
520 exa->ctx->destroy(exa->ctx);
521
522 exaDriverFini(pScrn->pScreen);
523 xfree(exa);
524 ms->exa = NULL;
525 }
526
527 void *
528 xorg_exa_init(ScrnInfoPtr pScrn)
529 {
530 modesettingPtr ms = modesettingPTR(pScrn);
531 struct exa_context *exa;
532 ExaDriverPtr pExa;
533
534 exa = xcalloc(1, sizeof(struct exa_context));
535 if (!exa)
536 return NULL;
537
538 pExa = exaDriverAlloc();
539 if (!pExa) {
540 goto out_err;
541 }
542
543 memset(pExa, 0, sizeof(*pExa));
544 pExa->exa_major = 2;
545 pExa->exa_minor = 2;
546 pExa->memoryBase = 0;
547 pExa->memorySize = 0;
548 pExa->offScreenBase = 0;
549 pExa->pixmapOffsetAlign = 0;
550 pExa->pixmapPitchAlign = 1;
551 pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS;
552 pExa->maxX = 8191; /* FIXME */
553 pExa->maxY = 8191; /* FIXME */
554 pExa->WaitMarker = ExaWaitMarker;
555 pExa->MarkSync = ExaMarkSync;
556 pExa->PrepareSolid = ExaPrepareSolid;
557 pExa->Solid = ExaSolid;
558 pExa->DoneSolid = ExaDone;
559 pExa->PrepareCopy = ExaPrepareCopy;
560 pExa->Copy = ExaCopy;
561 pExa->DoneCopy = ExaDone;
562 pExa->CheckComposite = ExaCheckComposite;
563 pExa->PrepareComposite = ExaPrepareComposite;
564 pExa->Composite = ExaComposite;
565 pExa->DoneComposite = ExaDoneComposite;
566 pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen;
567 pExa->PrepareAccess = ExaPrepareAccess;
568 pExa->FinishAccess = ExaFinishAccess;
569 pExa->CreatePixmap = ExaCreatePixmap;
570 pExa->DestroyPixmap = ExaDestroyPixmap;
571 pExa->ModifyPixmapHeader = ExaModifyPixmapHeader;
572
573 if (!exaDriverInit(pScrn->pScreen, pExa)) {
574 goto out_err;
575 }
576
577 exa->scrn = ms->screen;
578 exa->ctx = ms->api->create_context(ms->api, exa->scrn);
579 /* Share context with DRI */
580 ms->ctx = exa->ctx;
581
582 return (void *)exa;
583
584 out_err:
585 xorg_exa_close(pScrn);
586
587 return NULL;
588 }
589
590 /* vim: set sw=4 ts=8 sts=4: */