xorg_exa.c revision 21cce6afb03bf9b9adfc6d8a1a446bb3ef22c7a8
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
51static void
52exa_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
86static void
87ExaWaitMarker(ScreenPtr pScreen, int marker)
88{
89}
90
91static int
92ExaMarkSync(ScreenPtr pScreen)
93{
94    return 1;
95}
96
97static Bool
98ExaPrepareAccess(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
129static void
130ExaFinishAccess(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
153static void
154ExaDone(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
169static void
170ExaDoneComposite(PixmapPtr pPixmap)
171{
172
173}
174
175static Bool
176ExaPrepareSolid(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
206static void
207ExaSolid(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
224static Bool
225ExaPrepareCopy(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
263static void
264ExaCopy(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
281static Bool
282ExaPrepareComposite(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
294static void
295ExaComposite(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
307static Bool
308ExaCheckComposite(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
318static void *
319ExaCreatePixmap(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
330static void
331ExaDestroyPixmap(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
346static Bool
347ExaPixmapIsOffscreen(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
362unsigned
363xorg_exa_get_pixmap_handle(PixmapPtr pPixmap)
364{
365    ScreenPtr pScreen = pPixmap->drawable.pScreen;
366    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
367    modesettingPtr ms = modesettingPTR(pScrn);
368    struct exa_pixmap_priv *priv;
369    struct pipe_buffer *buffer = NULL;
370    unsigned handle;
371    unsigned stride;
372
373    if (!ms->exa) {
374	FatalError("NO MS->EXA\n");
375	return 0;
376    }
377
378    priv = exaGetPixmapDriverPrivate(pPixmap);
379
380    if (!priv) {
381	FatalError("NO PIXMAP PRIVATE\n");
382	return 0;
383    }
384
385    ms->api->buffer_from_texture(ms->api, priv->tex, &buffer, &stride);
386    ms->api->handle_from_buffer(ms->api, ms->screen, buffer, &handle);
387    pipe_buffer_reference(&buffer, NULL);
388    return handle;
389}
390
391static Bool
392ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
393		      int depth, int bitsPerPixel, int devKind,
394		      pointer pPixData)
395{
396    ScreenPtr pScreen = pPixmap->drawable.pScreen;
397    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
398    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
399    modesettingPtr ms = modesettingPTR(pScrn);
400    struct exa_context *exa = ms->exa;
401
402    if (!priv)
403	return FALSE;
404
405    if (depth <= 0)
406	depth = pPixmap->drawable.depth;
407
408    if (bitsPerPixel <= 0)
409	bitsPerPixel = pPixmap->drawable.bitsPerPixel;
410
411    if (width <= 0)
412	width = pPixmap->drawable.width;
413
414    if (height <= 0)
415	height = pPixmap->drawable.height;
416
417    if (width <= 0 || height <= 0 || depth <= 0)
418	return FALSE;
419
420    miModifyPixmapHeader(pPixmap, width, height, depth,
421			     bitsPerPixel, devKind, NULL);
422
423    /* Deal with screen resize */
424    if (priv->tex && (priv->tex->width[0] != width || priv->tex->height[0] != height)) {
425	pipe_texture_reference(&priv->tex, NULL);
426    }
427
428    if (!priv->tex) {
429	struct pipe_texture template;
430
431	memset(&template, 0, sizeof(template));
432	template.target = PIPE_TEXTURE_2D;
433	exa_get_pipe_format(depth, &template.format, &bitsPerPixel);
434	pf_get_block(template.format, &template.block);
435	template.width[0] = width;
436	template.height[0] = height;
437	template.depth[0] = 1;
438	template.last_level = 0;
439	template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
440	priv->tex = exa->scrn->texture_create(exa->scrn, &template);
441    }
442
443    if (pPixData) {
444	struct pipe_transfer *transfer =
445	    exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0,
446					PIPE_TRANSFER_WRITE,
447					0, 0, width, height);
448        pipe_copy_rect(exa->scrn->transfer_map(exa->scrn, transfer),
449                       &priv->tex->block, transfer->stride, 0, 0,
450                       width, height, pPixData, pPixmap->devKind, 0, 0);
451        exa->scrn->transfer_unmap(exa->scrn, transfer);
452        exa->scrn->tex_transfer_destroy(transfer);
453    }
454
455    return TRUE;
456}
457
458struct pipe_texture *
459xorg_exa_get_texture(PixmapPtr pPixmap)
460{
461    struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap);
462    struct pipe_texture *tex = NULL;
463    pipe_texture_reference(&tex, priv->tex);
464    return tex;
465}
466
467void
468xorg_exa_close(ScrnInfoPtr pScrn)
469{
470    modesettingPtr ms = modesettingPTR(pScrn);
471    struct exa_context *exa = ms->exa;
472
473    if (exa->ctx)
474	exa->ctx->destroy(exa->ctx);
475
476    exaDriverFini(pScrn->pScreen);
477    xfree(exa);
478    ms->exa = NULL;
479}
480
481void *
482xorg_exa_init(ScrnInfoPtr pScrn)
483{
484    modesettingPtr ms = modesettingPTR(pScrn);
485    struct exa_context *exa;
486    ExaDriverPtr pExa;
487
488    exa = xcalloc(1, sizeof(struct exa_context));
489    if (!exa)
490	return NULL;
491
492    pExa = exaDriverAlloc();
493    if (!pExa) {
494	goto out_err;
495    }
496
497    memset(pExa, 0, sizeof(*pExa));
498    pExa->exa_major = 2;
499    pExa->exa_minor = 2;
500    pExa->memoryBase = 0;
501    pExa->memorySize = 0;
502    pExa->offScreenBase = 0;
503    pExa->pixmapOffsetAlign = 0;
504    pExa->pixmapPitchAlign = 1;
505    pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS;
506    pExa->maxX = 8191;		       /* FIXME */
507    pExa->maxY = 8191;		       /* FIXME */
508    pExa->WaitMarker = ExaWaitMarker;
509    pExa->MarkSync = ExaMarkSync;
510    pExa->PrepareSolid = ExaPrepareSolid;
511    pExa->Solid = ExaSolid;
512    pExa->DoneSolid = ExaDone;
513    pExa->PrepareCopy = ExaPrepareCopy;
514    pExa->Copy = ExaCopy;
515    pExa->DoneCopy = ExaDone;
516    pExa->CheckComposite = ExaCheckComposite;
517    pExa->PrepareComposite = ExaPrepareComposite;
518    pExa->Composite = ExaComposite;
519    pExa->DoneComposite = ExaDoneComposite;
520    pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen;
521    pExa->PrepareAccess = ExaPrepareAccess;
522    pExa->FinishAccess = ExaFinishAccess;
523    pExa->CreatePixmap = ExaCreatePixmap;
524    pExa->DestroyPixmap = ExaDestroyPixmap;
525    pExa->ModifyPixmapHeader = ExaModifyPixmapHeader;
526
527    if (!exaDriverInit(pScrn->pScreen, pExa)) {
528	goto out_err;
529    }
530
531    exa->scrn = ms->screen;
532    exa->ctx = ms->api->create_context(ms->api, exa->scrn);
533    /* Share context with DRI */
534    ms->ctx = exa->ctx;
535
536    return (void *)exa;
537
538  out_err:
539    xorg_exa_close(pScrn);
540
541    return NULL;
542}
543
544/* vim: set sw=4 ts=8 sts=4: */
545