radeon_glamor.c revision 0d16fef4
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	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
54	RADEONInfoPtr info = RADEONPTR(scrn);
55
56	if (!info->use_glamor)
57		return TRUE;
58
59#ifdef HAVE_GLAMOR_GLYPHS_INIT
60	if (!glamor_glyphs_init(screen))
61		return FALSE;
62#endif
63
64	if (!glamor_egl_create_textured_screen_ext(screen,
65						   info->front_bo->handle,
66						   scrn->displayWidth *
67						   info->pixel_bytes,
68						   NULL))
69		return FALSE;
70
71	return TRUE;
72}
73
74
75Bool
76radeon_glamor_pre_init(ScrnInfoPtr scrn)
77{
78	RADEONInfoPtr info = RADEONPTR(scrn);
79	pointer glamor_module;
80	CARD32 version;
81	const char *s;
82
83	if (!info->dri2.available)
84		return FALSE;
85
86	s = xf86GetOptValString(info->Options, OPTION_ACCELMETHOD);
87	if (s == NULL && info->ChipFamily < CHIP_FAMILY_TAHITI)
88		return FALSE;
89
90	if (s && strcasecmp(s, "glamor") != 0) {
91		if (info->ChipFamily >= CHIP_FAMILY_TAHITI)
92			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
93				   "EXA not supported, using glamor\n");
94		else
95			return FALSE;
96	}
97
98	if (info->ChipFamily < CHIP_FAMILY_R300) {
99		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
100			   "glamor requires R300 or higher GPU, disabling.\n");
101		return FALSE;
102	}
103
104	if (info->ChipFamily < CHIP_FAMILY_RV515) {
105		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
106			   "glamor may not work (well) with GPUs < RV515.\n");
107	}
108
109	if (scrn->depth < 24) {
110		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
111			   "glamor requires depth >= 24, disabling.\n");
112		return FALSE;
113	}
114
115#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,15,0,0,0)
116	if (!xf86LoaderCheckSymbol("glamor_egl_init")) {
117		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
118			   "glamor requires Load \"glamoregl\" in "
119			   "Section \"Module\", disabling.\n");
120		return FALSE;
121	}
122#endif
123
124	/* Load glamor module */
125	if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) {
126		version = xf86GetModuleVersion(glamor_module);
127		if (version < MODULE_VERSION_NUMERIC(0,3,1)) {
128			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
129			"Incompatible glamor version, required >= 0.3.0.\n");
130			return FALSE;
131		} else {
132			if (glamor_egl_init(scrn, info->dri2.drm_fd)) {
133				xf86DrvMsg(scrn->scrnIndex, X_INFO,
134					   "glamor detected, initialising EGL layer.\n");
135			} else {
136				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
137					   "glamor detected, failed to initialize EGL.\n");
138				return FALSE;
139			}
140		}
141	} else {
142		xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n");
143		return FALSE;
144	}
145
146	info->use_glamor = TRUE;
147
148	return TRUE;
149}
150
151Bool
152radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv)
153{
154	return glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle,
155						 pixmap->devKind);
156}
157
158static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
159{
160#ifndef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
161	ScreenPtr screen = pixmap->drawable.pScreen;
162	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
163	Bool ret;
164#endif
165
166	if (pixmap->refcnt == 1) {
167		if (pixmap->devPrivate.ptr) {
168			struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap);
169
170			if (bo)
171				radeon_bo_unmap(bo);
172		}
173
174#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
175		glamor_egl_destroy_textured_pixmap(pixmap);
176#endif
177		radeon_set_pixmap_bo(pixmap, NULL);
178	}
179
180#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP
181	fbDestroyPixmap(pixmap);
182	return TRUE;
183#else
184	screen->DestroyPixmap = info->glamor.SavedDestroyPixmap;
185	ret = screen->DestroyPixmap(pixmap);
186	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
187	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
188
189	return ret;
190#endif
191}
192
193static PixmapPtr
194radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
195			unsigned usage)
196{
197	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
198	RADEONInfoPtr info = RADEONPTR(scrn);
199	struct radeon_pixmap *priv;
200	PixmapPtr pixmap, new_pixmap = NULL;
201
202	if (!RADEON_CREATE_PIXMAP_SHARED(usage)) {
203		if (info->shadow_primary) {
204			if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP)
205				return fbCreatePixmap(screen, w, h, depth, usage);
206		} else {
207			pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
208			if (pixmap)
209			    return pixmap;
210		}
211	}
212
213	if (w > 32767 || h > 32767)
214		return NullPixmap;
215
216	if (depth == 1)
217		return fbCreatePixmap(screen, w, h, depth, usage);
218
219	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
220		return fbCreatePixmap(screen, w, h, depth, usage);
221
222	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
223	if (pixmap == NullPixmap)
224		return pixmap;
225
226	if (w && h) {
227		int stride;
228
229		priv = calloc(1, sizeof (struct radeon_pixmap));
230		if (priv == NULL)
231			goto fallback_pixmap;
232
233		priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage,
234						  pixmap->drawable.bitsPerPixel,
235						  &stride,
236						  &priv->surface,
237						  &priv->tiling_flags);
238		if (!priv->bo)
239			goto fallback_priv;
240
241		radeon_set_pixmap_private(pixmap, priv);
242
243		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL);
244
245		if (!radeon_glamor_create_textured_pixmap(pixmap, priv))
246			goto fallback_glamor;
247
248		pixmap->devPrivate.ptr = NULL;
249	}
250
251	return pixmap;
252
253fallback_glamor:
254	if (RADEON_CREATE_PIXMAP_SHARED(usage)) {
255	/* XXX need further work to handle the DRI2 failure case.
256	 * Glamor don't know how to handle a BO only pixmap. Put
257	 * a warning indicator here.
258	 */
259		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
260			   "Failed to create textured DRI2/PRIME pixmap.");
261
262		radeon_glamor_destroy_pixmap(pixmap);
263		return NullPixmap;
264	}
265	/* Create textured pixmap failed means glamor failed to
266	 * create a texture from current BO for some reasons. We turn
267	 * to create a new glamor pixmap and clean up current one.
268	 * One thing need to be noted, this new pixmap doesn't
269	 * has a priv and bo attached to it. It's glamor's responsbility
270	 * to take care of it. Glamor will mark this new pixmap as a
271	 * texture only pixmap and will never fallback to DDX layer
272	 * afterwards.
273	 */
274	new_pixmap = glamor_create_pixmap(screen, w, h,	depth, usage);
275	radeon_bo_unref(priv->bo);
276fallback_priv:
277	free(priv);
278fallback_pixmap:
279	fbDestroyPixmap(pixmap);
280	if (new_pixmap)
281		return new_pixmap;
282	else
283		return fbCreatePixmap(screen, w, h, depth, usage);
284}
285
286#ifdef RADEON_PIXMAP_SHARING
287
288static Bool
289radeon_glamor_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave,
290				   void **handle_p)
291{
292	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
293
294	if (!priv)
295		return FALSE;
296
297	return radeon_share_pixmap_backing(priv->bo, handle_p);
298}
299
300static Bool
301radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
302{
303	ScreenPtr screen = pixmap->drawable.pScreen;
304	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
305	struct radeon_surface surface;
306	struct radeon_pixmap *priv;
307
308	if (!radeon_set_shared_pixmap_backing(pixmap, handle, &surface))
309		return FALSE;
310
311	priv = radeon_get_pixmap_private(pixmap);
312	priv->surface = surface;
313
314	if (!radeon_glamor_create_textured_pixmap(pixmap, priv)) {
315		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
316			   "Failed to get PRIME drawable for glamor pixmap.\n");
317		return FALSE;
318	}
319
320	screen->ModifyPixmapHeader(pixmap,
321				   pixmap->drawable.width,
322				   pixmap->drawable.height,
323				   0, 0, 0, NULL);
324
325	return TRUE;
326}
327
328#endif /* RADEON_PIXMAP_SHARING */
329
330Bool
331radeon_glamor_init(ScreenPtr screen)
332{
333	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
334	RADEONInfoPtr info = RADEONPTR(scrn);
335#ifdef RENDER
336#ifdef HAVE_FBGLYPHS
337	UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL;
338#endif
339	PictureScreenPtr ps = NULL;
340
341	if (info->shadow_primary) {
342		ps = GetPictureScreenIfSet(screen);
343
344		if (ps) {
345#ifdef HAVE_FBGLYPHS
346			SavedUnrealizeGlyph = ps->UnrealizeGlyph;
347#endif
348			info->glamor.SavedGlyphs = ps->Glyphs;
349			info->glamor.SavedTriangles = ps->Triangles;
350			info->glamor.SavedTrapezoids = ps->Trapezoids;
351		}
352	}
353#endif /* RENDER */
354
355	if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN |
356			 GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS |
357			 GLAMOR_NO_DRI3)) {
358		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
359			   "Failed to initialize glamor.\n");
360		return FALSE;
361	}
362
363	if (!glamor_egl_init_textured_pixmap(screen)) {
364		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
365			   "Failed to initialize textured pixmap of screen for glamor.\n");
366		return FALSE;
367	}
368
369	if (!dixRegisterPrivateKey(&glamor_pixmap_index, PRIVATE_PIXMAP, 0))
370		return FALSE;
371
372	if (info->shadow_primary)
373		radeon_glamor_screen_init(screen);
374
375#if defined(RENDER) && defined(HAVE_FBGLYPHS)
376	/* For ShadowPrimary, we need fbUnrealizeGlyph instead of
377	 * glamor_unrealize_glyph
378	 */
379	if (ps)
380		ps->UnrealizeGlyph = SavedUnrealizeGlyph;
381#endif
382
383	info->glamor.SavedCreatePixmap = screen->CreatePixmap;
384	screen->CreatePixmap = radeon_glamor_create_pixmap;
385	info->glamor.SavedDestroyPixmap = screen->DestroyPixmap;
386	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
387#ifdef RADEON_PIXMAP_SHARING
388	info->glamor.SavedSharePixmapBacking = screen->SharePixmapBacking;
389	screen->SharePixmapBacking = radeon_glamor_share_pixmap_backing;
390	info->glamor.SavedSetSharedPixmapBacking = screen->SetSharedPixmapBacking;
391	screen->SetSharedPixmapBacking = radeon_glamor_set_shared_pixmap_backing;
392#endif
393
394	xf86DrvMsg(scrn->scrnIndex, X_INFO,
395		   "Use GLAMOR acceleration.\n");
396	return TRUE;
397}
398
399void
400radeon_glamor_fini(ScreenPtr screen)
401{
402	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen));
403
404	if (!info->use_glamor)
405		return;
406
407	screen->CreatePixmap = info->glamor.SavedCreatePixmap;
408	screen->DestroyPixmap = info->glamor.SavedDestroyPixmap;
409#ifdef RADEON_PIXMAP_SHARING
410	screen->SharePixmapBacking = info->glamor.SavedSharePixmapBacking;
411	screen->SetSharedPixmapBacking = info->glamor.SavedSetSharedPixmapBacking;
412#endif
413}
414
415XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt)
416{
417	return glamor_xv_init(pScreen, num_adapt);
418}
419