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