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