1/*
2 * Copyright © 2007 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Zhenyu Wang <zhenyu.z.wang@sna.com>
25 *
26 */
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#define _SNA_XVMC_SERVER_
32#include "sna.h"
33#include "sna_video_hwmc.h"
34
35#include <X11/extensions/Xv.h>
36#include <X11/extensions/XvMC.h>
37#include <fourcc.h>
38
39extern DevPrivateKey XF86XvScreenKey;
40
41static int create_subpicture(XvMCSubpicturePtr sub, int *size, CARD32 **priv)
42{
43	return Success;
44}
45
46static void destroy_subpicture(XvMCSubpicturePtr sub)
47{
48}
49
50static int create_surface(XvMCSurfacePtr surface, int *size, CARD32 **priv)
51{
52	return Success;
53}
54
55static void destroy_surface(XvMCSurfacePtr surface)
56{
57}
58
59static int create_context(XvPortPtr port, XvMCContextPtr ctx,
60			  int *size, CARD32 **out)
61{
62	struct sna *sna = to_sna_from_screen(ctx->pScreen);
63	struct intel_xvmc_hw_context {
64		unsigned int type;
65		union {
66			struct {
67				unsigned int use_phys_addr : 1;
68			} i915;
69			struct {
70				unsigned int is_g4x:1;
71				unsigned int is_965_q:1;
72				unsigned int is_igdng:1;
73			} i965;
74		};
75	} *priv;
76
77	ctx->port_priv = port->devPriv.ptr;
78
79	priv = calloc(1, sizeof(*priv));
80	if (priv == NULL)
81		return BadAlloc;
82
83	if (sna->kgem.gen >= 040) {
84		int devid = intel_get_device_id(sna->dev);
85
86		if (sna->kgem.gen >= 045)
87			priv->type = XVMC_I965_MPEG2_VLD;
88		else
89			priv->type = XVMC_I965_MPEG2_MC;
90		priv->i965.is_g4x = sna->kgem.gen == 045;
91		priv->i965.is_965_q = devid == PCI_CHIP_I965_Q;
92		priv->i965.is_igdng = sna->kgem.gen == 050;
93	} else
94		priv->type = XVMC_I915_MPEG2_MC;
95
96	*size = sizeof(*priv) >> 2;
97	*out = (CARD32 *)priv;
98	return Success;
99}
100
101static void destroy_context(XvMCContextPtr ctx)
102{
103}
104
105/* i915 hwmc support */
106static XvMCSurfaceInfoRec i915_YV12_mpg2_surface = {
107	FOURCC_YV12,
108	XVMC_CHROMA_FORMAT_420,
109	0,
110	720,
111	576,
112	720,
113	576,
114	XVMC_MPEG_2,
115	/* XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING, */
116	0,
117	/* &yv12_subpicture_list */
118	NULL,
119};
120
121static XvMCSurfaceInfoRec i915_YV12_mpg1_surface = {
122	FOURCC_YV12,
123	XVMC_CHROMA_FORMAT_420,
124	0,
125	720,
126	576,
127	720,
128	576,
129	XVMC_MPEG_1,
130	/* XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING, */
131	0,
132	NULL,
133};
134
135static XvMCSurfaceInfoPtr surface_info_i915[2] = {
136	&i915_YV12_mpg2_surface,
137	&i915_YV12_mpg1_surface
138};
139
140/* i965 and later hwmc support */
141#ifndef XVMC_VLD
142#define XVMC_VLD  0x00020000
143#endif
144
145static XvMCSurfaceInfoRec yv12_mpeg2_vld_surface = {
146	FOURCC_YV12,
147	XVMC_CHROMA_FORMAT_420,
148	0,
149	1936,
150	1096,
151	1920,
152	1080,
153	XVMC_MPEG_2 | XVMC_VLD,
154	XVMC_INTRA_UNSIGNED,
155	NULL
156};
157
158static XvMCSurfaceInfoRec yv12_mpeg2_i965_surface = {
159	FOURCC_YV12,
160	XVMC_CHROMA_FORMAT_420,
161	0,
162	1936,
163	1096,
164	1920,
165	1080,
166	XVMC_MPEG_2 | XVMC_MOCOMP,
167	/* XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING, */
168	XVMC_INTRA_UNSIGNED,
169	/* &yv12_subpicture_list */
170	NULL
171};
172
173static XvMCSurfaceInfoRec yv12_mpeg1_i965_surface = {
174	FOURCC_YV12,
175	XVMC_CHROMA_FORMAT_420,
176	0,
177	1920,
178	1080,
179	1920,
180	1080,
181	XVMC_MPEG_1 | XVMC_MOCOMP,
182	/*XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING |
183	   XVMC_INTRA_UNSIGNED, */
184	XVMC_INTRA_UNSIGNED,
185
186	/*&yv12_subpicture_list */
187	NULL
188};
189
190static XvMCSurfaceInfoPtr surface_info_i965[] = {
191	&yv12_mpeg2_i965_surface,
192	&yv12_mpeg1_i965_surface
193};
194
195static XvMCSurfaceInfoPtr surface_info_vld[] = {
196	&yv12_mpeg2_vld_surface,
197	&yv12_mpeg2_i965_surface,
198};
199
200/* check chip type and load xvmc driver */
201void sna_video_xvmc_setup(struct sna *sna, ScreenPtr screen)
202{
203	XvMCAdaptorRec *adaptors;
204	struct pci_device *pci;
205	const char *name;
206	char bus[64];
207	int i;
208
209	pci = xf86GetPciInfoForEntity(sna->pEnt->index);
210	if (pci == NULL)
211		return;
212
213	if (!sna->xv.num_adaptors)
214		return;
215
216	if (!xf86LoaderCheckSymbol("XvMCScreenInit"))
217		return;
218
219	/* Needs KMS support. */
220	if (sna->kgem.gen < 031)
221		return;
222
223	/* Not implemented */
224	if (sna->kgem.gen >= 060)
225		return;
226
227	adaptors = calloc(sna->xv.num_adaptors, sizeof(XvMCAdaptorRec));
228	if (adaptors == NULL)
229		return;
230
231	for (i = 0; i< sna->xv.num_adaptors; i++) {
232		adaptors[i].xv_adaptor = &sna->xv.adaptors[i];
233
234		adaptors[i].num_subpictures = 0;
235		adaptors[i].subpictures = NULL;
236		adaptors[i].CreateContext = create_context;
237		adaptors[i].DestroyContext = destroy_context;
238		adaptors[i].CreateSurface = create_surface;
239		adaptors[i].DestroySurface = destroy_surface;
240		adaptors[i].CreateSubpicture = create_subpicture;
241		adaptors[i].DestroySubpicture = destroy_subpicture;
242
243		if (sna->kgem.gen >= 045) {
244			adaptors[i].num_surfaces = ARRAY_SIZE(surface_info_vld);
245			adaptors[i].surfaces = surface_info_vld;
246		} else if (sna->kgem.gen >= 040) {
247			adaptors[i].num_surfaces = ARRAY_SIZE(surface_info_i965);
248			adaptors[i].surfaces = surface_info_i965;
249		} else {
250			adaptors[i].num_surfaces = ARRAY_SIZE(surface_info_i915);
251			adaptors[i].surfaces = surface_info_i915;
252		}
253	}
254
255	if (XvMCScreenInit(screen, i, adaptors) != Success) {
256		xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
257			   "[XvMC] Failed to initialize XvMC.\n");
258		free(adaptors);
259		return;
260	}
261
262	sprintf(bus, "pci:%04x:%02x:%02x.%d",
263		pci->domain, pci->bus, pci->dev, pci->func);
264
265	xf86XvMCRegisterDRInfo(screen, (char *)SNA_XVMC_LIBNAME, bus,
266			       SNA_XVMC_MAJOR, SNA_XVMC_MINOR,
267			       SNA_XVMC_PATCHLEVEL);
268
269	if (sna->kgem.gen >= 045)
270		name = "xvmc_vld";
271	else if (sna->kgem.gen >= 040)
272		name = "i965_xvmc";
273	else
274		name = "i915_xvmc";
275	xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
276		   "[XvMC] %s driver initialized.\n",
277		   name);
278}
279