1/*
2 * Copyright © 2008 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 * Author:
24 *    Zou Nan hai <nanhai.zou@intel.com>
25 *
26 */
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <X11/extensions/Xv.h>
32#include <X11/extensions/XvMC.h>
33#include <fourcc.h>
34#include <errno.h>
35
36#include "i830.h"
37#include "i830_dri.h"
38#define _INTEL_XVMC_SERVER_
39#include "i830_hwmc.h"
40#include "i965_hwmc.h"
41#include "intel_bufmgr.h"
42
43#define STRIDE(w)               (w)
44#define SIZE_YUV420(w, h)       (h * (STRIDE(w) + STRIDE(w >> 1)))
45#define VLD_MAX_SLICE_LEN	(32*1024)
46
47#ifndef XVMC_VLD
48#define XVMC_VLD  0x00020000
49#endif
50
51static PutImageFuncPtr XvPutImage;
52
53
54static int create_context(ScrnInfoPtr pScrn,
55	XvMCContextPtr context, int *num_privates, CARD32 **private)
56{
57    struct i965_xvmc_context *private_context, *context_dup;
58    I830Ptr I830 = I830PTR(pScrn);
59
60    unsigned int blocknum =
61	(((context->width + 15)/16)*((context->height+15)/16));
62    unsigned int blocksize = 6*blocknum*64*sizeof(short);
63    blocksize = (blocksize + 4095)&(~4095);
64    if ((private_context = Xcalloc(sizeof(*private_context))) == NULL) {
65	ErrorF("XVMC Can not allocate private context\n");
66	return BadAlloc;
67    }
68
69    if ((context_dup = Xcalloc(sizeof(*private_context))) == NULL) {
70	ErrorF("XVMC Can not allocate private context\n");
71	return BadAlloc;
72    }
73
74    private_context->is_g4x = IS_G4X(I830);
75    private_context->is_965_q = IS_965_Q(I830);
76    private_context->is_igdng = IS_IGDNG(I830);
77    private_context->comm.kernel_exec_fencing = I830->kernel_exec_fencing;
78    private_context->comm.type = xvmc_driver->flag;
79
80    *num_privates = sizeof(*private_context)/sizeof(CARD32);
81    *private = (CARD32 *)private_context;
82    memcpy(context_dup, private_context, sizeof(*private_context));
83    context->driver_priv = context_dup;
84
85    return Success;
86}
87
88static void destroy_context(ScrnInfoPtr pScrn, XvMCContextPtr context)
89{
90    struct i965_xvmc_context *private_context;
91    private_context = context->driver_priv;
92    Xfree(private_context);
93}
94
95static int create_surface(ScrnInfoPtr pScrn, XvMCSurfacePtr surface,
96  int *num_priv, CARD32 **priv)
97{
98	XvMCContextPtr ctx = surface->context;
99
100	struct i965_xvmc_surface *priv_surface, *surface_dup;
101	struct i965_xvmc_context *priv_ctx = ctx->driver_priv;
102	int i;
103	for (i = 0 ; i < I965_MAX_SURFACES; i++) {
104	    if (priv_ctx->surfaces[i] == NULL) {
105		priv_surface = Xcalloc(sizeof(*priv_surface));
106		if (priv_surface == NULL)
107		    return BadAlloc;
108		surface_dup = Xcalloc(sizeof(*priv_surface));
109		if (surface_dup == NULL)
110		    return BadAlloc;
111
112		priv_surface->no = i;
113		priv_surface->handle = priv_surface;
114		priv_surface->w = ctx->width;
115		priv_surface->h = ctx->height;
116		priv_ctx->surfaces[i] = surface->driver_priv
117		    = priv_surface;
118		memcpy(surface_dup, priv_surface, sizeof(*priv_surface));
119		*num_priv = sizeof(*priv_surface)/sizeof(CARD32);
120		*priv = (CARD32 *)surface_dup;
121		break;
122	    }
123	}
124
125	if (i >= I965_MAX_SURFACES) {
126	    ErrorF("I965 XVMC too many surfaces in one context\n");
127	    return BadAlloc;
128	}
129
130	return Success;
131}
132
133static void destory_surface(ScrnInfoPtr pScrn, XvMCSurfacePtr surface)
134{
135	XvMCContextPtr ctx = surface->context;
136	struct i965_xvmc_surface *priv_surface = surface->driver_priv;
137	struct i965_xvmc_context *priv_ctx = ctx->driver_priv;
138	priv_ctx->surfaces[priv_surface->no] = NULL;
139	Xfree(priv_surface);
140}
141
142static int create_subpicture(ScrnInfoPtr pScrn, XvMCSubpicturePtr subpicture,
143  int *num_priv, CARD32 **priv)
144{
145	return Success;
146}
147
148static void destroy_subpicture(ScrnInfoPtr pScrn, XvMCSubpicturePtr subpicture)
149{
150}
151
152static int put_image(ScrnInfoPtr pScrn,
153        short src_x, short src_y,
154        short drw_x, short drw_y, short src_w,
155        short src_h, short drw_w, short drw_h,
156        int id, unsigned char *buf, short width,
157        short height, Bool sync, RegionPtr clipBoxes, pointer data,
158        DrawablePtr pDraw)
159{
160	I830Ptr pI830 = I830PTR(pScrn);
161	struct intel_xvmc_command *cmd = (struct intel_xvmc_command *)buf;
162	dri_bo *bo;
163
164	if (id == FOURCC_XVMC) {
165            bo = intel_bo_gem_create_from_name(pI830->bufmgr, "surface", cmd->handle);
166            dri_bo_pin(bo, 0x1000);
167	    buf = pI830->FbBase + bo->offset;
168	}
169	XvPutImage(pScrn, src_x, src_y, drw_x, drw_y, src_w, src_h,
170		drw_w, drw_h, id, buf, width, height, sync, clipBoxes,
171		data, pDraw);
172
173	if (id == FOURCC_XVMC) {
174	    dri_bo_unpin(bo);
175	    dri_bo_unreference(bo);
176	}
177
178	return Success;
179}
180
181static Bool init(ScrnInfoPtr screen_info, XF86VideoAdaptorPtr adaptor)
182{
183    XvPutImage = adaptor->PutImage;
184    adaptor->PutImage = put_image;
185
186    return TRUE;
187}
188
189static void fini(ScrnInfoPtr screen_info)
190{
191}
192
193static XF86MCSurfaceInfoRec yv12_mpeg2_vld_surface =
194{
195    FOURCC_YV12,
196    XVMC_CHROMA_FORMAT_420,
197    0,
198    1936,
199    1096,
200    1920,
201    1080,
202    XVMC_MPEG_2|XVMC_VLD,
203    XVMC_INTRA_UNSIGNED,
204    NULL
205};
206
207static XF86MCSurfaceInfoRec yv12_mpeg2_surface =
208{
209    FOURCC_YV12,
210    XVMC_CHROMA_FORMAT_420,
211    0,
212    1936,
213    1096,
214    1920,
215    1080,
216    XVMC_MPEG_2|XVMC_MOCOMP,
217    /* XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING,*/
218    XVMC_INTRA_UNSIGNED,
219    /* &yv12_subpicture_list*/
220    NULL
221};
222
223static XF86MCSurfaceInfoRec yv12_mpeg1_surface =
224{
225    FOURCC_YV12,
226    XVMC_CHROMA_FORMAT_420,
227    0,
228    1920,
229    1080,
230    1920,
231    1080,
232    XVMC_MPEG_1|XVMC_MOCOMP,
233    /*XVMC_OVERLAID_SURFACE | XVMC_SUBPICTURE_INDEPENDENT_SCALING |
234    XVMC_INTRA_UNSIGNED,*/
235    XVMC_INTRA_UNSIGNED,
236
237    /*&yv12_subpicture_list*/
238    NULL
239};
240
241static XF86MCSurfaceInfoPtr surface_info[] = {
242    &yv12_mpeg2_surface,
243    &yv12_mpeg1_surface
244};
245
246static XF86MCSurfaceInfoPtr surface_info_vld[] = {
247    &yv12_mpeg2_vld_surface,
248    &yv12_mpeg2_surface,
249};
250
251static XF86MCAdaptorRec adaptor_vld = {
252    .name               = "Intel(R) Textured Video",
253    .num_surfaces       = sizeof(surface_info_vld)/sizeof(surface_info_vld[0]),
254    .surfaces           = surface_info_vld,
255
256    .CreateContext 	= create_context,
257    .DestroyContext	= destroy_context,
258    .CreateSurface 	= create_surface,
259    .DestroySurface 	= destory_surface,
260    .CreateSubpicture   = create_subpicture,
261    .DestroySubpicture  = destroy_subpicture
262};
263
264static XF86MCAdaptorRec adaptor = {
265    .name               = "Intel(R) Textured Video",
266    .num_surfaces       = sizeof(surface_info)/sizeof(surface_info[0]),
267    .surfaces           = surface_info,
268
269    .CreateContext 	= create_context,
270    .DestroyContext	= destroy_context,
271    .CreateSurface 	= create_surface,
272    .DestroySurface 	= destory_surface,
273    .CreateSubpicture   = create_subpicture,
274    .DestroySubpicture  = destroy_subpicture
275};
276
277struct intel_xvmc_driver i965_xvmc_driver = {
278    .name               = "i965_xvmc",
279    .adaptor            = &adaptor,
280    .flag               = XVMC_I965_MPEG2_MC,
281    .init 		= init,
282    .fini		= fini
283};
284
285struct intel_xvmc_driver vld_xvmc_driver =  {
286    .name               = "xvmc_vld",
287    .adaptor            = &adaptor_vld,
288    .flag               = XVMC_I965_MPEG2_VLD,
289    .init 		= init,
290    .fini		= fini
291};
292
293