radeon_glamor.c revision de2362d3
1de2362d3Smrg/*
2de2362d3Smrg * Copyright © 2011 Intel Corporation.
3de2362d3Smrg *             2012 Advanced Micro Devices, Inc.
4de2362d3Smrg *
5de2362d3Smrg * Permission is hereby granted, free of charge, to any person
6de2362d3Smrg * obtaining a copy of this software and associated documentation
7de2362d3Smrg * files (the "Software"), to deal in the Software without
8de2362d3Smrg * restriction, including without limitation the rights to use, copy,
9de2362d3Smrg * modify, merge, publish, distribute, sublicense, and/or sell copies
10de2362d3Smrg * of the Software, and to permit persons to whom the Software is
11de2362d3Smrg * furnished to do so, subject to the following conditions:
12de2362d3Smrg *
13de2362d3Smrg * The above copyright notice and this permission notice (including
14de2362d3Smrg * the next paragraph) shall be included in all copies or substantial
15de2362d3Smrg * portions of the Software.
16de2362d3Smrg *
17de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18de2362d3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19de2362d3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20de2362d3Smrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21de2362d3Smrg * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22de2362d3Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24de2362d3Smrg * DEALINGS IN THE SOFTWARE.
25de2362d3Smrg */
26de2362d3Smrg
27de2362d3Smrg#ifdef HAVE_CONFIG_H
28de2362d3Smrg#include "config.h"
29de2362d3Smrg#endif
30de2362d3Smrg
31de2362d3Smrg#include <xf86.h>
32de2362d3Smrg#define GLAMOR_FOR_XORG  1
33de2362d3Smrg#include <glamor.h>
34de2362d3Smrg
35de2362d3Smrg#include "radeon.h"
36de2362d3Smrg#include "radeon_bo_helper.h"
37de2362d3Smrg
38de2362d3Smrg#if HAS_DEVPRIVATEKEYREC
39de2362d3SmrgDevPrivateKeyRec glamor_pixmap_index;
40de2362d3Smrg#else
41de2362d3Smrgint glamor_pixmap_index;
42de2362d3Smrg#endif
43de2362d3Smrg
44de2362d3Smrgvoid
45de2362d3Smrgradeon_glamor_exchange_buffers(PixmapPtr src,
46de2362d3Smrg			       PixmapPtr dst)
47de2362d3Smrg{
48de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(dst->drawable.pScreen));
49de2362d3Smrg
50de2362d3Smrg	if (!info->use_glamor)
51de2362d3Smrg		return;
52de2362d3Smrg	glamor_egl_exchange_buffers(src, dst);
53de2362d3Smrg}
54de2362d3Smrg
55de2362d3SmrgBool
56de2362d3Smrgradeon_glamor_create_screen_resources(ScreenPtr screen)
57de2362d3Smrg{
58de2362d3Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
59de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
60de2362d3Smrg
61de2362d3Smrg	if (!info->use_glamor)
62de2362d3Smrg		return TRUE;
63de2362d3Smrg
64de2362d3Smrg	if (!glamor_glyphs_init(screen))
65de2362d3Smrg		return FALSE;
66de2362d3Smrg
67de2362d3Smrg	if (!glamor_egl_create_textured_screen_ext(screen,
68de2362d3Smrg						   info->front_bo->handle,
69de2362d3Smrg						   scrn->displayWidth *
70de2362d3Smrg						   info->pixel_bytes,
71de2362d3Smrg						   NULL))
72de2362d3Smrg		return FALSE;
73de2362d3Smrg
74de2362d3Smrg	return TRUE;
75de2362d3Smrg}
76de2362d3Smrg
77de2362d3Smrg
78de2362d3SmrgBool
79de2362d3Smrgradeon_glamor_pre_init(ScrnInfoPtr scrn)
80de2362d3Smrg{
81de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
82de2362d3Smrg	pointer glamor_module;
83de2362d3Smrg	CARD32 version;
84de2362d3Smrg	const char *s;
85de2362d3Smrg
86de2362d3Smrg	if (!info->dri2.available)
87de2362d3Smrg		return FALSE;
88de2362d3Smrg
89de2362d3Smrg	s = xf86GetOptValString(info->Options, OPTION_ACCELMETHOD);
90de2362d3Smrg	if (s == NULL && info->ChipFamily < CHIP_FAMILY_TAHITI)
91de2362d3Smrg		return FALSE;
92de2362d3Smrg
93de2362d3Smrg	if (s && strcasecmp(s, "glamor") != 0) {
94de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_TAHITI)
95de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
96de2362d3Smrg				   "EXA not supported, using glamor\n");
97de2362d3Smrg		else
98de2362d3Smrg			return FALSE;
99de2362d3Smrg	}
100de2362d3Smrg
101de2362d3Smrg	if (info->ChipFamily < CHIP_FAMILY_R300) {
102de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
103de2362d3Smrg			   "glamor requires R300 or higher GPU, disabling.\n");
104de2362d3Smrg		return FALSE;
105de2362d3Smrg	}
106de2362d3Smrg
107de2362d3Smrg	if (info->ChipFamily < CHIP_FAMILY_RV515) {
108de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
109de2362d3Smrg			   "glamor may not work (well) with GPUs < RV515.\n");
110de2362d3Smrg	}
111de2362d3Smrg
112de2362d3Smrg	if (scrn->depth < 24) {
113de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
114de2362d3Smrg			   "glamor requires depth >= 24, disabling.\n");
115de2362d3Smrg		return FALSE;
116de2362d3Smrg	}
117de2362d3Smrg
118de2362d3Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,15,0,0,0)
119de2362d3Smrg	if (!xf86LoaderCheckSymbol("glamor_egl_init")) {
120de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
121de2362d3Smrg			   "glamor requires Load \"glamoregl\" in "
122de2362d3Smrg			   "Section \"Module\", disabling.\n");
123de2362d3Smrg		return FALSE;
124de2362d3Smrg	}
125de2362d3Smrg#endif
126de2362d3Smrg
127de2362d3Smrg	/* Load glamor module */
128de2362d3Smrg	if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) {
129de2362d3Smrg		version = xf86GetModuleVersion(glamor_module);
130de2362d3Smrg		if (version < MODULE_VERSION_NUMERIC(0,3,1)) {
131de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
132de2362d3Smrg			"Incompatible glamor version, required >= 0.3.0.\n");
133de2362d3Smrg			return FALSE;
134de2362d3Smrg		} else {
135de2362d3Smrg			if (glamor_egl_init(scrn, info->dri2.drm_fd)) {
136de2362d3Smrg				xf86DrvMsg(scrn->scrnIndex, X_INFO,
137de2362d3Smrg					   "glamor detected, initialising EGL layer.\n");
138de2362d3Smrg			} else {
139de2362d3Smrg				xf86DrvMsg(scrn->scrnIndex, X_ERROR,
140de2362d3Smrg					   "glamor detected, failed to initialize EGL.\n");
141de2362d3Smrg				return FALSE;
142de2362d3Smrg			}
143de2362d3Smrg		}
144de2362d3Smrg	} else {
145de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n");
146de2362d3Smrg		return FALSE;
147de2362d3Smrg	}
148de2362d3Smrg
149de2362d3Smrg	info->use_glamor = TRUE;
150de2362d3Smrg
151de2362d3Smrg	return TRUE;
152de2362d3Smrg}
153de2362d3Smrg
154de2362d3SmrgBool
155de2362d3Smrgradeon_glamor_create_textured_pixmap(PixmapPtr pixmap)
156de2362d3Smrg{
157de2362d3Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
158de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
159de2362d3Smrg	struct radeon_pixmap *priv;
160de2362d3Smrg
161de2362d3Smrg	if ((info->use_glamor) == 0)
162de2362d3Smrg		return TRUE;
163de2362d3Smrg
164de2362d3Smrg	priv = radeon_get_pixmap_private(pixmap);
165de2362d3Smrg	if (!priv->stride)
166de2362d3Smrg		priv->stride = pixmap->devKind;
167de2362d3Smrg	if (glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle,
168de2362d3Smrg					      priv->stride))
169de2362d3Smrg		return TRUE;
170de2362d3Smrg	else
171de2362d3Smrg		return FALSE;
172de2362d3Smrg}
173de2362d3Smrg
174de2362d3SmrgBool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap)
175de2362d3Smrg{
176de2362d3Smrg	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
177de2362d3Smrg	return priv && priv->bo;
178de2362d3Smrg}
179de2362d3Smrg
180de2362d3Smrg#ifndef CREATE_PIXMAP_USAGE_SHARED
181de2362d3Smrg#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2
182de2362d3Smrg#endif
183de2362d3Smrg
184de2362d3Smrg#define RADEON_CREATE_PIXMAP_SHARED(usage) \
185de2362d3Smrg	(((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \
186de2362d3Smrg	 (usage) == CREATE_PIXMAP_USAGE_SHARED)
187de2362d3Smrg
188de2362d3Smrgstatic PixmapPtr
189de2362d3Smrgradeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth,
190de2362d3Smrg			unsigned usage)
191de2362d3Smrg{
192de2362d3Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
193de2362d3Smrg	struct radeon_pixmap *priv;
194de2362d3Smrg	PixmapPtr pixmap, new_pixmap = NULL;
195de2362d3Smrg
196de2362d3Smrg	if (!RADEON_CREATE_PIXMAP_SHARED(usage)) {
197de2362d3Smrg		pixmap = glamor_create_pixmap(screen, w, h, depth, usage);
198de2362d3Smrg		if (pixmap)
199de2362d3Smrg			return pixmap;
200de2362d3Smrg	}
201de2362d3Smrg
202de2362d3Smrg	if (w > 32767 || h > 32767)
203de2362d3Smrg		return NullPixmap;
204de2362d3Smrg
205de2362d3Smrg	if (depth == 1)
206de2362d3Smrg		return fbCreatePixmap(screen, w, h, depth, usage);
207de2362d3Smrg
208de2362d3Smrg	if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32)
209de2362d3Smrg		return fbCreatePixmap(screen, w, h, depth, usage);
210de2362d3Smrg
211de2362d3Smrg	pixmap = fbCreatePixmap(screen, 0, 0, depth, usage);
212de2362d3Smrg	if (pixmap == NullPixmap)
213de2362d3Smrg		return pixmap;
214de2362d3Smrg
215de2362d3Smrg	if (w && h) {
216de2362d3Smrg		priv = calloc(1, sizeof (struct radeon_pixmap));
217de2362d3Smrg		if (priv == NULL)
218de2362d3Smrg			goto fallback_pixmap;
219de2362d3Smrg
220de2362d3Smrg		priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage,
221de2362d3Smrg						  pixmap->drawable.bitsPerPixel,
222de2362d3Smrg						  &priv->stride,
223de2362d3Smrg						  &priv->surface,
224de2362d3Smrg						  &priv->tiling_flags);
225de2362d3Smrg		if (!priv->bo)
226de2362d3Smrg			goto fallback_priv;
227de2362d3Smrg
228de2362d3Smrg		radeon_set_pixmap_private(pixmap, priv);
229de2362d3Smrg
230de2362d3Smrg		screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride, NULL);
231de2362d3Smrg
232de2362d3Smrg		if (!radeon_glamor_create_textured_pixmap(pixmap))
233de2362d3Smrg			goto fallback_glamor;
234de2362d3Smrg	}
235de2362d3Smrg
236de2362d3Smrg	return pixmap;
237de2362d3Smrg
238de2362d3Smrgfallback_glamor:
239de2362d3Smrg	if (RADEON_CREATE_PIXMAP_SHARED(usage)) {
240de2362d3Smrg	/* XXX need further work to handle the DRI2 failure case.
241de2362d3Smrg	 * Glamor don't know how to handle a BO only pixmap. Put
242de2362d3Smrg	 * a warning indicator here.
243de2362d3Smrg	 */
244de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
245de2362d3Smrg			   "Failed to create textured DRI2/PRIME pixmap.");
246de2362d3Smrg		return pixmap;
247de2362d3Smrg	}
248de2362d3Smrg	/* Create textured pixmap failed means glamor failed to
249de2362d3Smrg	 * create a texture from current BO for some reasons. We turn
250de2362d3Smrg	 * to create a new glamor pixmap and clean up current one.
251de2362d3Smrg	 * One thing need to be noted, this new pixmap doesn't
252de2362d3Smrg	 * has a priv and bo attached to it. It's glamor's responsbility
253de2362d3Smrg	 * to take care of it. Glamor will mark this new pixmap as a
254de2362d3Smrg	 * texture only pixmap and will never fallback to DDX layer
255de2362d3Smrg	 * afterwards.
256de2362d3Smrg	 */
257de2362d3Smrg	new_pixmap = glamor_create_pixmap(screen, w, h,	depth, usage);
258de2362d3Smrg	radeon_bo_unref(priv->bo);
259de2362d3Smrgfallback_priv:
260de2362d3Smrg	free(priv);
261de2362d3Smrgfallback_pixmap:
262de2362d3Smrg	fbDestroyPixmap(pixmap);
263de2362d3Smrg	if (new_pixmap)
264de2362d3Smrg		return new_pixmap;
265de2362d3Smrg	else
266de2362d3Smrg		return fbCreatePixmap(screen, w, h, depth, usage);
267de2362d3Smrg}
268de2362d3Smrg
269de2362d3Smrgstatic Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap)
270de2362d3Smrg{
271de2362d3Smrg	if (pixmap->refcnt == 1) {
272de2362d3Smrg		glamor_egl_destroy_textured_pixmap(pixmap);
273de2362d3Smrg		radeon_set_pixmap_bo(pixmap, NULL);
274de2362d3Smrg	}
275de2362d3Smrg	fbDestroyPixmap(pixmap);
276de2362d3Smrg	return TRUE;
277de2362d3Smrg}
278de2362d3Smrg
279de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
280de2362d3Smrg
281de2362d3Smrgstatic Bool
282de2362d3Smrgradeon_glamor_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave,
283de2362d3Smrg				   void **handle_p)
284de2362d3Smrg{
285de2362d3Smrg	struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap);
286de2362d3Smrg
287de2362d3Smrg	if (!priv)
288de2362d3Smrg		return FALSE;
289de2362d3Smrg
290de2362d3Smrg	return radeon_share_pixmap_backing(priv->bo, handle_p);
291de2362d3Smrg}
292de2362d3Smrg
293de2362d3Smrgstatic Bool
294de2362d3Smrgradeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle)
295de2362d3Smrg{
296de2362d3Smrg	ScreenPtr screen = pixmap->drawable.pScreen;
297de2362d3Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
298de2362d3Smrg	struct radeon_surface surface;
299de2362d3Smrg	struct radeon_pixmap *priv;
300de2362d3Smrg
301de2362d3Smrg	if (!radeon_set_shared_pixmap_backing(pixmap, handle, &surface))
302de2362d3Smrg		return FALSE;
303de2362d3Smrg
304de2362d3Smrg	priv = radeon_get_pixmap_private(pixmap);
305de2362d3Smrg	priv->stride = pixmap->devKind;
306de2362d3Smrg	priv->surface = surface;
307de2362d3Smrg	priv->tiling_flags = 0;
308de2362d3Smrg
309de2362d3Smrg	if (!radeon_glamor_create_textured_pixmap(pixmap)) {
310de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
311de2362d3Smrg			   "Failed to get PRIME drawable for glamor pixmap.\n");
312de2362d3Smrg		return FALSE;
313de2362d3Smrg	}
314de2362d3Smrg
315de2362d3Smrg	screen->ModifyPixmapHeader(pixmap,
316de2362d3Smrg				   pixmap->drawable.width,
317de2362d3Smrg				   pixmap->drawable.height,
318de2362d3Smrg				   0, 0,
319de2362d3Smrg				   priv->stride,
320de2362d3Smrg				   NULL);
321de2362d3Smrg
322de2362d3Smrg	return TRUE;
323de2362d3Smrg}
324de2362d3Smrg
325de2362d3Smrg#endif /* RADEON_PIXMAP_SHARING */
326de2362d3Smrg
327de2362d3SmrgBool
328de2362d3Smrgradeon_glamor_init(ScreenPtr screen)
329de2362d3Smrg{
330de2362d3Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
331de2362d3Smrg
332de2362d3Smrg	if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN |
333de2362d3Smrg#ifdef GLAMOR_NO_DRI3
334de2362d3Smrg			 GLAMOR_NO_DRI3 |
335de2362d3Smrg#endif
336de2362d3Smrg			 GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) {
337de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
338de2362d3Smrg			   "Failed to initialize glamor.\n");
339de2362d3Smrg		return FALSE;
340de2362d3Smrg	}
341de2362d3Smrg
342de2362d3Smrg	if (!glamor_egl_init_textured_pixmap(screen)) {
343de2362d3Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
344de2362d3Smrg			   "Failed to initialize textured pixmap of screen for glamor.\n");
345de2362d3Smrg		return FALSE;
346de2362d3Smrg	}
347de2362d3Smrg
348de2362d3Smrg#if HAS_DIXREGISTERPRIVATEKEY
349de2362d3Smrg	if (!dixRegisterPrivateKey(&glamor_pixmap_index, PRIVATE_PIXMAP, 0))
350de2362d3Smrg#else
351de2362d3Smrg	if (!dixRequestPrivate(&glamor_pixmap_index, 0))
352de2362d3Smrg#endif
353de2362d3Smrg		return FALSE;
354de2362d3Smrg
355de2362d3Smrg	screen->CreatePixmap = radeon_glamor_create_pixmap;
356de2362d3Smrg	screen->DestroyPixmap = radeon_glamor_destroy_pixmap;
357de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
358de2362d3Smrg	screen->SharePixmapBacking = radeon_glamor_share_pixmap_backing;
359de2362d3Smrg	screen->SetSharedPixmapBacking = radeon_glamor_set_shared_pixmap_backing;
360de2362d3Smrg#endif
361de2362d3Smrg
362de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
363de2362d3Smrg		   "Use GLAMOR acceleration.\n");
364de2362d3Smrg	return TRUE;
365de2362d3Smrg}
366de2362d3Smrg
367de2362d3Smrgvoid
368de2362d3Smrgradeon_glamor_flush(ScrnInfoPtr pScrn)
369de2362d3Smrg{
370de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
371de2362d3Smrg
372de2362d3Smrg	if (info->use_glamor)
373de2362d3Smrg		glamor_block_handler(pScrn->pScreen);
374de2362d3Smrg}
375de2362d3Smrg
376de2362d3SmrgXF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt)
377de2362d3Smrg{
378de2362d3Smrg	return glamor_xv_init(pScreen, num_adapt);
379de2362d3Smrg}
380