amdgpu_video.c revision e49c54bc
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include <stdlib.h>
7#include <string.h>
8#include <stdio.h>
9#include <math.h>
10
11#include "amdgpu_drv.h"
12#include "amdgpu_glamor.h"
13#include "amdgpu_probe.h"
14#include "amdgpu_video.h"
15#include "amdgpu_pixmap.h"
16
17#include "xf86.h"
18#include "dixstruct.h"
19
20/* DPMS */
21#ifdef HAVE_XEXTPROTO_71
22#include <X11/extensions/dpmsconst.h>
23#else
24#define DPMS_SERVER
25#include <X11/extensions/dpms.h>
26#endif
27
28#include <X11/extensions/Xv.h>
29#include "fourcc.h"
30
31#define OFF_DELAY       250	/* milliseconds */
32#define FREE_DELAY      15000
33
34#define OFF_TIMER       0x01
35#define FREE_TIMER      0x02
36#define CLIENT_VIDEO_ON 0x04
37
38static void amdgpu_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
39{
40	dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
41	dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
42	if (dest->x1 >= dest->x2) {
43		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
44		return;
45	}
46
47	dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
48	dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
49	if (dest->y1 >= dest->y2)
50		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
51}
52
53static int amdgpu_box_area(BoxPtr box)
54{
55	return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
56}
57
58Bool
59amdgpu_crtc_is_enabled(xf86CrtcPtr crtc)
60{
61	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
62
63	return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn;
64}
65
66static void amdgpu_crtc_box(RRCrtcPtr crtc, BoxPtr crtc_box)
67{
68	if (crtc->mode) {
69		crtc_box->x1 = crtc->x;
70		crtc_box->y1 = crtc->y;
71		switch (crtc->rotation) {
72		case RR_Rotate_0:
73		case RR_Rotate_180:
74		default:
75			crtc_box->x2 = crtc->x + crtc->mode->mode.width;
76			crtc_box->y2 = crtc->y + crtc->mode->mode.height;
77			break;
78		case RR_Rotate_90:
79		case RR_Rotate_270:
80			crtc_box->x2 = crtc->x + crtc->mode->mode.height;
81			crtc_box->y2 = crtc->y + crtc->mode->mode.width;
82			break;
83		}
84	} else
85		crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
86}
87
88static Bool amdgpu_crtc_on(RRCrtcPtr crtc, Bool crtc_is_xf86_hint)
89{
90	if (!crtc) {
91		return FALSE;
92	}
93	if (crtc_is_xf86_hint && crtc->devPrivate) {
94		return amdgpu_crtc_is_enabled(crtc->devPrivate);
95	} else {
96		return !!crtc->mode;
97	}
98}
99
100/*
101 * Return the crtc covering 'box'. If two crtcs cover a portion of
102 * 'box', then prefer the crtc with greater coverage.
103 */
104static RRCrtcPtr
105amdgpu_crtc_covering_box(ScreenPtr pScreen, BoxPtr box, Bool screen_is_xf86_hint)
106{
107	rrScrPrivPtr pScrPriv;
108	RRCrtcPtr crtc, best_crtc, primary_crtc;
109	int coverage, best_coverage;
110	int c;
111	BoxRec crtc_box, cover_box;
112	RROutputPtr primary_output;
113
114	best_crtc = NULL;
115	best_coverage = 0;
116	primary_crtc = NULL;
117	primary_output = NULL;
118
119	if (!dixPrivateKeyRegistered(rrPrivKey))
120		return NULL;
121
122	pScrPriv = rrGetScrPriv(pScreen);
123
124	if (!pScrPriv)
125		return NULL;
126
127	primary_output = RRFirstOutput(pScreen);
128	if (primary_output && primary_output->crtc)
129		primary_crtc = primary_output->crtc;
130
131	for (c = 0; c < pScrPriv->numCrtcs; c++) {
132		crtc = pScrPriv->crtcs[c];
133
134		/* If the CRTC is off, treat it as not covering */
135		if (!amdgpu_crtc_on(crtc, screen_is_xf86_hint))
136			continue;
137
138		amdgpu_crtc_box(crtc, &crtc_box);
139		amdgpu_box_intersect(&cover_box, &crtc_box, box);
140		coverage = amdgpu_box_area(&cover_box);
141		if (coverage > best_coverage ||
142		   (crtc == primary_crtc && coverage == best_coverage)) {
143			best_crtc = crtc;
144			best_coverage = coverage;
145		}
146	}
147
148	return best_crtc;
149}
150
151#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(23, 0)
152static RRCrtcPtr
153amdgpu_crtc_covering_box_on_secondary(ScreenPtr pScreen, BoxPtr box)
154{
155	if (!pScreen->isGPU) {
156		ScreenPtr secondary;
157		RRCrtcPtr crtc = NULL;
158
159		xorg_list_for_each_entry(secondary, &pScreen->secondary_list, secondary_head) {
160			if (!secondary->is_output_secondary)
161				continue;
162
163			crtc = amdgpu_crtc_covering_box(secondary, box, FALSE);
164			if (crtc)
165				return crtc;
166		}
167	}
168
169	return NULL;
170}
171#endif
172
173RRCrtcPtr
174amdgpu_randr_crtc_covering_drawable(DrawablePtr pDraw)
175{
176	ScreenPtr pScreen = pDraw->pScreen;
177	RRCrtcPtr crtc = NULL;
178	BoxRec box;
179
180	box.x1 = pDraw->x;
181	box.y1 = pDraw->y;
182	box.x2 = box.x1 + pDraw->width;
183	box.y2 = box.y1 + pDraw->height;
184
185	crtc = amdgpu_crtc_covering_box(pScreen, &box, TRUE);
186#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(23, 0)
187	if (!crtc) {
188		crtc = amdgpu_crtc_covering_box_on_secondary(pScreen, &box);
189	}
190#endif
191	return crtc;
192}
193
194xf86CrtcPtr
195amdgpu_pick_best_crtc(ScreenPtr pScreen,
196		      int x1, int x2, int y1, int y2)
197{
198	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
199
200	if (!pScrn->vtSema)
201		return NULL;
202
203	RRCrtcPtr crtc = NULL;
204	BoxRec box;
205
206	box.x1 = x1;
207	box.x2 = x2;
208	box.y1 = y1;
209	box.y2 = y2;
210
211	crtc = amdgpu_crtc_covering_box(pScreen, &box, TRUE);
212	if (crtc) {
213		return crtc->devPrivate;
214	}
215	return NULL;
216}
217
218void AMDGPUInitVideo(ScreenPtr pScreen)
219{
220	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
221	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
222	XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
223	XF86VideoAdaptorPtr texturedAdaptor = NULL;
224	int num_adaptors;
225
226	num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
227	newAdaptors =
228	    malloc((num_adaptors + 2) * sizeof(*newAdaptors));
229	if (!newAdaptors)
230		return;
231
232	memcpy(newAdaptors, adaptors,
233	       num_adaptors * sizeof(XF86VideoAdaptorPtr));
234	adaptors = newAdaptors;
235
236	if (info->use_glamor) {
237		texturedAdaptor = amdgpu_glamor_xv_init(pScreen, 16);
238		if (texturedAdaptor != NULL) {
239			adaptors[num_adaptors++] = texturedAdaptor;
240			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
241				   "Set up textured video (glamor)\n");
242		} else
243			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
244				   "Failed to set up textured video (glamor)\n");
245	}
246
247	if (num_adaptors)
248		xf86XVScreenInit(pScreen, adaptors, num_adaptors);
249
250	if (newAdaptors)
251		free(newAdaptors);
252
253}
254