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