Merge branch 'const-buffer-changes'
[mesa.git] / src / gallium / state_trackers / xorg / xorg_exa.c
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
42 struct exa_entity
43 {
44 ExaDriverPtr pExa;
45 struct pipe_context *ctx;
46 struct pipe_screen *scrn;
47 };
48
49 struct 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
64 static void
65 exa_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
99 static void
100 ExaWaitMarker(ScreenPtr pScreen, int marker)
101 {
102 }
103
104 static int
105 ExaMarkSync(ScreenPtr pScreen)
106 {
107 return 1;
108 }
109
110 static Bool
111 ExaPrepareAccess(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
142 static void
143 ExaFinishAccess(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
166 static void
167 ExaDone(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
182 static void
183 ExaDoneComposite(PixmapPtr pPixmap)
184 {
185
186 }
187
188 static Bool
189 ExaPrepareSolid(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
219 static void
220 ExaSolid(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
237 static Bool
238 ExaPrepareCopy(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
276 static void
277 ExaCopy(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
294 static Bool
295 ExaPrepareComposite(int op, PicturePtr pSrcPicture,
296 PicturePtr pMaskPicture, PicturePtr pDstPicture,
297 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
298 {
299 return FALSE;
300 }
301
302 static void
303 ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
304 int dstX, int dstY, int width, int height)
305 {
306 }
307
308 static Bool
309 ExaCheckComposite(int op,
310 PicturePtr pSrcPicture, PicturePtr pMaskPicture,
311 PicturePtr pDstPicture)
312 {
313 return FALSE;
314 }
315
316 static void *
317 ExaCreatePixmap(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
328 static void
329 ExaDestroyPixmap(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
344 static Bool
345 ExaPixmapIsOffscreen(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
360 unsigned
361 xorg_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
389 static Bool
390 ExaModifyPixmapHeader(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
456 struct pipe_texture *
457 xorg_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
465 void
466 xorg_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
479 void *
480 xorg_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: */