radeon_glamor.c revision 446f62d6
1/*
2 * Copyright © 2011 Intel Corporation.
3 *             2012 Advanced Micro Devices, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use, copy,
9 * modify, merge, publish, distribute, sublicense, and/or sell copies
10 * of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including
14 * the next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <xf86.h>
32
33#include "radeon.h"
34#include "radeon_bo_helper.h"
35#include "radeon_glamor.h"
36
37DevPrivateKeyRec glamor_pixmap_index;
38
39void
40radeon_glamor_exchange_buffers(PixmapPtr src,
41			       PixmapPtr dst)
42{
43	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(dst->drawable.pScreen));
44
45	if (!info->use_glamor)
46		return;
47	glamor_egl_exchange_buffers(src, dst);
48}
49
50Bool
51radeon_glamor_create_screen_resources(ScreenPtr screen)
52{
53	PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
54	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
55	RADEONInfoPtr info = RADEONPTR(scrn);
56
57	if (!info->use_glamor)
58		return TRUE;
59
60#ifdef HAVE_GLAMOR_GLYPHS_INIT
61	if (!glamor_glyphs_init(screen))
62		return FALSE;
63#endif
64
65	return radeon_glamor_create_textured_pixmap(screen_pixmap,
66						    info->front_buffer);
67}
68
69
70Bool
71radeon_glamor_pre_init(ScrnInfoPtr scrn)
72{
73	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
74	RADEONInfoPtr info = RADEONPTR(scrn);
75	pointer glamor_module;
76	CARD32 version;
77	const char *s;
78
79	if (!info->dri2.available)
80		return FALSE;
81
82	s = xf86GetOptValString(info->Options, OPTION_ACCELMETHOD);
83	if (!s) {
84		if (xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0)) {
85			if (info->ChipFamily < CHIP_FAMILY_R600)
86				return FALSE;
87		} else {
88			if (info->ChipFamily < CHIP_FAMILY_TAHITI)
89				return FALSE;
90		}
91	}
92
93	if (s && strcasecmp(s, "glamor") != 0) {
94		if (info->ChipFamily >= CHIP_FAMILY_TAHITI)
95			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
96				   "EXA not supported, using glamor\n");
97		else
98			return FALSE;
99	}
100
101	if (info->ChipFamily < CHIP_FAMILY_R300) {
102		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
103			   "glamor requires R300 or higher GPU, disabling.\n");
104		return FALSE;
105	}
106
107	if (info->ChipFamily < CHIP_FAMILY_RV515) {
108		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
109			   "glamor may not work (well) with GPUs < RV515.\n");
110	}
111
112#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,20,99,0,0)
113	if (scrn->depth < 24) {
114#else
115	if (scrn->depth < 15) {
116#endif
117		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
118			   "Depth %d not supported with glamor, disabling\n",
119			   scrn->depth);
120		return FALSE;
121	}
122
123	if (scrn->depth == 30 &&
124	    xorgGetVersion() < XORG_VERSION_NUMERIC(1,19,99,1,0)) {
125		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
126			   "Depth 30 is not supported by GLAMOR with Xorg < "
127			   "1.19.99.1\n");
128		return FALSE;
129	}
130
131#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,15,0,0,0)
132	if (!xf86LoaderCheckSymbol("glamor_egl_init")) {
133		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
134			   "glamor requires Load \"glamoregl\" in "
135			   "Section \"Module\", disabling.\n");
136		return FALSE;
137	}
138#endif
139
140	info->gbm = gbm_create_device(pRADEONEnt->fd);
141	if (!info->gbm) {
142		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
143			   "gbm_create_device returned NULL\n");
144		return FALSE;
145	}
146
147	/* Load glamor module */
148	if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) {
149		version = xf86GetModuleVersion(glamor_module);
150		if (version < MODULE_VERSION_NUMERIC(0,3,1)) {
151			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
152			"Incompatible glamor version, required >= 0.3.0.\n");
153			return FALSE;
154		} else {
155			if (glamor_egl_init(scrn, pRADEONEnt->fd)) {
156				xf86DrvMsg(scrn->scrnIndex, X_INFO,
157					   "glamor detected, initialising EGL layer.\n");
158			} else {
159				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
160					   "glamor detected, failed to initialize EGL.\n");
161				return FALSE;
162			}
163		}
164	} else {
165		xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n");
166		return FALSE;
167	}
168
169	info->use_glamor = TRUE;
170
171	return TRUE;
172}
173
174Bool
175radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_buffer *bo)
176{
177	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
178	RADEONInfoPtr info = RADEONPTR(scrn);
179
180	if (!info->use_glamor)
181		return TRUE;
182
183	if (bo->flags & RADEON_BO_FLAGS_GBM) {
184		return glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap,
185								     bo->bo.gbm
186#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,19,99,903,0)
187								     , FALSE
188#endif
189								     );
190	} else {
191		return glamor_egl_create_textured_pixmap(pixmap,
192							 bo->bo.radeon->handle,
193							 pixmap->devKind);
194	}
195}
196
197static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
198{
199#ifndef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
200	ScreenPtr screen = pixmap->drawable.pScreen;
201	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
202	Bool ret;
203#endif
204
205	if (pixmap->refcnt == 1) {
206#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
207		glamor_egl_destroy_textured_pixmap(pixmap);
208#endif
209		radeon_set_pixmap_bo(pixmap, NULL);
210	}
211
212#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
213	fbDestroyPixmap(pixmap);
214	return TRUE;
215#else
216	screen->DestroyPixmap = info->glamor.SavedDestroyPixmap;
217	ret = screen->DestroyPixmap(pixmap);
218	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
219	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
220
221	return ret;
222#endif
223}
224
225static PixmapPtr
226radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
227			unsigned usage)
228{
229	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
230	RADEONInfoPtr info = RADEONPTR(scrn);
231	struct radeon_pixmap *priv;
232	PixmapPtr pixmap, new_pixmap = NULL;
233
234	if (!xf86GetPixFormat(scrn, depth))
235		return NULL;
236
237	if (!RADEON_CREATE_PIXMAP_SHARED(usage)) {
238		if (info->shadow_primary) {
239			if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
240				return fbCreatePixmap(screen, w, h, depth, usage);
241		} else {
242			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
243			if (pixmap)
244			    return pixmap;
245		}
246	}
247
248	if (w > 32767 || h > 32767)
249		return NullPixmap;
250
251	if (depth == 1)
252		return fbCreatePixmap(screen, w, h, depth, usage);
253
254	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
255		return fbCreatePixmap(screen, w, h, depth, usage);
256
257	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
258	if (pixmap == NullPixmap)
259		return pixmap;
260
261	if (w && h) {
262		int stride;
263
264		priv = calloc(1, sizeof (struct radeon_pixmap));
265		if (!priv)
266			goto fallback_pixmap;
267
268		priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage,
269						  pixmap->drawable.bitsPerPixel,
270						  &stride, NULL,
271						  &priv->tiling_flags);
272		if (!priv->bo)
273			goto fallback_priv;
274
275		radeon_set_pixmap_private(pixmap, priv);
276
277		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
278
279		if (!radeon_glamor_create_textured_pixmap(pixmap, priv->bo))
280			goto fallback_glamor;
281
282		pixmap->devPrivate.ptr = NULL;
283	}
284
285	return pixmap;
286
287fallback_glamor:
288	if (RADEON_CREATE_PIXMAP_SHARED(usage)) {
289	/* XXX need further work to handle the DRI2 failure case.
290	 * Glamor don't know how to handle a BO only pixmap. Put
291	 * a warning indicator here.
292	 */
293		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
294			   "Failed to create textured DRI2/PRIME pixmap.");
295
296		radeon_glamor_destroy_pixmap(pixmap);
297		return NullPixmap;
298	}
299	/* Create textured pixmap failed means glamor failed to
300	 * create a texture from current BO for some reasons. We turn
301	 * to create a new glamor pixmap and clean up current one.
302	 * One thing need to be noted, this new pixmap doesn't
303	 * has a priv and bo attached to it. It's glamor's responsbility
304	 * to take care of it. Glamor will mark this new pixmap as a
305	 * texture only pixmap and will never fallback to DDX layer
306	 * afterwards.
307	 */
308	new_pixmap = glamor_create_pixmap(screen, w, h,	depth, usage);
309	radeon_buffer_unref(&priv->bo);
310fallback_priv:
311	free(priv);
312fallback_pixmap:
313	fbDestroyPixmap(pixmap);
314	if (new_pixmap)
315		return new_pixmap;
316	else
317		return fbCreatePixmap(screen, w, h, depth, usage);
318}
319
320PixmapPtr
321radeon_glamor_set_pixmap_bo(DrawablePtr drawable, PixmapPtr pixmap)
322{
323	PixmapPtr old = get_drawable_pixmap(drawable);
324	ScreenPtr screen = drawable->pScreen;
325	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
326	GCPtr gc;
327
328	/* With a glamor pixmap, 2D pixmaps are created in texture
329	 * and without a static BO attached to it. To support DRI,
330	 * we need to create a new textured-drm pixmap and
331	 * need to copy the original content to this new textured-drm
332	 * pixmap, and then convert the old pixmap to a coherent
333	 * textured-drm pixmap which has a valid BO attached to it
334	 * and also has a valid texture, thus both glamor and DRI2
335	 * can access it.
336	 *
337	 */
338
339	/* Copy the current contents of the pixmap to the bo. */
340	gc = GetScratchGC(drawable->depth, screen);
341	if (gc) {
342		ValidateGC(&pixmap->drawable, gc);
343		gc->ops->CopyArea(&old->drawable, &pixmap->drawable,
344				  gc,
345				  0, 0,
346				  old->drawable.width,
347				  old->drawable.height, 0, 0);
348		FreeScratchGC(gc);
349	}
350
351	/* And redirect the pixmap to the new bo (for 3D). */
352	glamor_egl_exchange_buffers(old, pixmap);
353	radeon_set_pixmap_private(pixmap, radeon_get_pixmap_private(old));
354	radeon_set_pixmap_private(old, priv);
355
356	screen->ModifyPixmapHeader(old,
357				   old->drawable.width,
358				   old->drawable.height,
359				   0, 0, pixmap->devKind, NULL);
360	old->devPrivate.ptr = NULL;
361
362	screen->DestroyPixmap(pixmap);
363
364	return old;
365}
366
367
368static Bool
369radeon_glamor_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave,
370				   void **handle_p)
371{
372	ScreenPtr screen = pixmap->drawable.pScreen;
373	CARD16 stride;
374	CARD32 size;
375	int fd;
376
377	if ((radeon_get_pixmap_tiling_flags(pixmap) &
378	     RADEON_TILING_MASK) != RADEON_TILING_LINEAR) {
379		PixmapPtr linear;
380
381		/* We don't want to re-allocate the screen pixmap as
382		 * linear, to avoid trouble with page flipping
383		 */
384		if (screen->GetScreenPixmap(screen) == pixmap)
385			return FALSE;
386
387		linear = screen->CreatePixmap(screen, pixmap->drawable.width,
388					      pixmap->drawable.height,
389					      pixmap->drawable.depth,
390					      CREATE_PIXMAP_USAGE_SHARED);
391		if (!linear)
392			return FALSE;
393
394		radeon_glamor_set_pixmap_bo(&pixmap->drawable, linear);
395	}
396
397	fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size);
398	if (fd < 0)
399		return FALSE;
400
401	*handle_p = (void *)(long)fd;
402	return TRUE;
403}
404
405static Bool
406radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
407{
408	ScreenPtr screen = pixmap->drawable.pScreen;
409	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
410	int ihandle = (int)(long)handle;
411
412	if (!radeon_set_shared_pixmap_backing(pixmap, handle, NULL))
413		return FALSE;
414
415	if (ihandle != -1 &&
416	    !radeon_glamor_create_textured_pixmap(pixmap,
417						  radeon_get_pixmap_bo(pixmap))) {
418		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
419			   "Failed to get PRIME drawable for glamor pixmap.\n");
420		return FALSE;
421	}
422
423	screen->ModifyPixmapHeader(pixmap,
424				   pixmap->drawable.width,
425				   pixmap->drawable.height,
426				   0, 0, 0, NULL);
427
428	return TRUE;
429}
430
431
432Bool
433radeon_glamor_init(ScreenPtr screen)
434{
435	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
436	RADEONInfoPtr info = RADEONPTR(scrn);
437#ifdef RENDER
438#ifdef HAVE_FBGLYPHS
439	UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL;
440#endif
441	PictureScreenPtr ps = NULL;
442
443	if (info->shadow_primary) {
444		ps = GetPictureScreenIfSet(screen);
445
446		if (ps) {
447#ifdef HAVE_FBGLYPHS
448			SavedUnrealizeGlyph = ps->UnrealizeGlyph;
449#endif
450			info->glamor.SavedGlyphs = ps->Glyphs;
451			info->glamor.SavedTriangles = ps->Triangles;
452			info->glamor.SavedTrapezoids = ps->Trapezoids;
453		}
454	}
455#endif /* RENDER */
456
457	if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN |
458			 GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS |
459			 GLAMOR_NO_DRI3)) {
460		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
461			   "Failed to initialize glamor.\n");
462		return FALSE;
463	}
464
465	if (!glamor_egl_init_textured_pixmap(screen)) {
466		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
467			   "Failed to initialize textured pixmap of screen for glamor.\n");
468		return FALSE;
469	}
470
471	if (!dixRegisterPrivateKey(&glamor_pixmap_index, PRIVATE_PIXMAP, 0))
472		return FALSE;
473
474	if (info->shadow_primary)
475		radeon_glamor_screen_init(screen);
476
477#if defined(RENDER) && defined(HAVE_FBGLYPHS)
478	/* For ShadowPrimary, we need fbUnrealizeGlyph instead of
479	 * glamor_unrealize_glyph
480	 */
481	if (ps)
482		ps->UnrealizeGlyph = SavedUnrealizeGlyph;
483#endif
484
485	info->glamor.SavedCreatePixmap = screen->CreatePixmap;
486	screen->CreatePixmap = radeon_glamor_create_pixmap;
487	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
488	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
489	info->glamor.SavedSharePixmapBacking = screen->SharePixmapBacking;
490	screen->SharePixmapBacking = radeon_glamor_share_pixmap_backing;
491	info->glamor.SavedSetSharedPixmapBacking = screen->SetSharedPixmapBacking;
492	screen->SetSharedPixmapBacking = radeon_glamor_set_shared_pixmap_backing;
493
494	xf86DrvMsg(scrn->scrnIndex, X_INFO,
495		   "Use GLAMOR acceleration.\n");
496	return TRUE;
497}
498
499void
500radeon_glamor_fini(ScreenPtr screen)
501{
502	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
503
504	if (!info->use_glamor)
505		return;
506
507	screen->CreatePixmap = info->glamor.SavedCreatePixmap;
508	screen->DestroyPixmap = info->glamor.SavedDestroyPixmap;
509	screen->SharePixmapBacking = info->glamor.SavedSharePixmapBacking;
510	screen->SetSharedPixmapBacking = info->glamor.SavedSetSharedPixmapBacking;
511}
512
513XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt)
514{
515	return glamor_xv_init(pScreen, num_adapt);
516}
517