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