1 /*
2  * Copyright (c) 1998-2003 by The XFree86 Project, Inc.
3  * Copyright © 2013 Red Hat
4  * Copyright © 2014 Intel Corporation
5  * Copyright © 2016 Red Hat
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  *
26  * Authors:
27  *      Olivier Fourdan <ofourdan@redhat.com>
28  *
29  * Derived from the glamor_xf86_xv, ephyr_glamor_xv and xf86xv
30  * implementations
31  */
32 
33 #include "xwayland.h"
34 #include "glamor_priv.h"
35 
36 #include <X11/extensions/Xv.h>
37 
38 #define NUM_FORMATS    3
39 #define NUM_PORTS      16
40 #define ADAPTOR_NAME   "glamor textured video"
41 #define ENCODER_NAME   "XV_IMAGE"
42 
43 static DevPrivateKeyRec xwlXvScreenPrivateKeyRec;
44 #define xwlXvScreenPrivateKey (&xwlXvScreenPrivateKeyRec)
45 
46 typedef struct {
47     XvAdaptorPtr glxv_adaptor; /* We have only one adaptor, glamor Xv */
48     glamor_port_private *port_privates;
49 
50     CloseScreenProcPtr CloseScreen;
51 } xwlXvScreenRec, *xwlXvScreenPtr;
52 
53 typedef struct {
54     char depth;
55     short class;
56 } xwlVideoFormatRec, *xwlVideoFormatPtr;
57 
58 static xwlVideoFormatRec Formats[NUM_FORMATS] = {
59     {15, TrueColor},
60     {16, TrueColor},
61     {24, TrueColor}
62 };
63 
64 static int
xwl_glamor_xv_stop_video(XvPortPtr pPort,DrawablePtr pDraw)65 xwl_glamor_xv_stop_video(XvPortPtr   pPort,
66                          DrawablePtr pDraw)
67 {
68     glamor_port_private *gpp = (glamor_port_private *) (pPort->devPriv.ptr);
69 
70     if (pDraw->type != DRAWABLE_WINDOW)
71         return BadAlloc;
72 
73     glamor_xv_stop_video(gpp);
74 
75     return Success;
76 }
77 
78 static int
xwl_glamor_xv_set_port_attribute(XvPortPtr pPort,Atom attribute,INT32 value)79 xwl_glamor_xv_set_port_attribute(XvPortPtr pPort,
80                                  Atom      attribute,
81                                  INT32     value)
82 {
83     glamor_port_private *gpp = (glamor_port_private *) (pPort->devPriv.ptr);
84 
85     return glamor_xv_set_port_attribute(gpp, attribute, value);
86 }
87 
88 static int
xwl_glamor_xv_get_port_attribute(XvPortPtr pPort,Atom attribute,INT32 * pValue)89 xwl_glamor_xv_get_port_attribute(XvPortPtr pPort,
90                                  Atom      attribute,
91                                  INT32    *pValue)
92 {
93     glamor_port_private *gpp = (glamor_port_private *) (pPort->devPriv.ptr);
94 
95     return glamor_xv_get_port_attribute(gpp, attribute, pValue);
96 }
97 
98 static int
xwl_glamor_xv_query_best_size(XvPortPtr pPort,CARD8 motion,CARD16 vid_w,CARD16 vid_h,CARD16 drw_w,CARD16 drw_h,unsigned int * p_w,unsigned int * p_h)99 xwl_glamor_xv_query_best_size(XvPortPtr     pPort,
100                               CARD8         motion,
101                               CARD16        vid_w,
102                               CARD16        vid_h,
103                               CARD16        drw_w,
104                               CARD16        drw_h,
105                               unsigned int *p_w,
106                               unsigned int *p_h)
107 {
108     *p_w = drw_w;
109     *p_h = drw_h;
110 
111     return Success;
112 }
113 
114 static int
xwl_glamor_xv_query_image_attributes(XvPortPtr pPort,XvImagePtr format,CARD16 * width,CARD16 * height,int * pitches,int * offsets)115 xwl_glamor_xv_query_image_attributes(XvPortPtr  pPort,
116                                      XvImagePtr format,
117                                      CARD16    *width,
118                                      CARD16    *height,
119                                      int       *pitches,
120                                      int       *offsets)
121 {
122     return glamor_xv_query_image_attributes(format->id,
123                                             width,
124                                             height,
125                                             pitches,
126                                             offsets);
127 }
128 
129 static int
xwl_glamor_xv_put_image(DrawablePtr pDrawable,XvPortPtr pPort,GCPtr pGC,INT16 src_x,INT16 src_y,CARD16 src_w,CARD16 src_h,INT16 drw_x,INT16 drw_y,CARD16 drw_w,CARD16 drw_h,XvImagePtr format,unsigned char * data,Bool sync,CARD16 width,CARD16 height)130 xwl_glamor_xv_put_image(DrawablePtr    pDrawable,
131                         XvPortPtr      pPort,
132                         GCPtr          pGC,
133                         INT16          src_x,
134                         INT16          src_y,
135                         CARD16         src_w,
136                         CARD16         src_h,
137                         INT16          drw_x,
138                         INT16          drw_y,
139                         CARD16         drw_w,
140                         CARD16         drw_h,
141                         XvImagePtr     format,
142                         unsigned char *data,
143                         Bool           sync,
144                         CARD16         width,
145                         CARD16         height)
146 {
147     glamor_port_private *gpp = (glamor_port_private *) (pPort->devPriv.ptr);
148 
149     RegionRec WinRegion;
150     RegionRec ClipRegion;
151     BoxRec WinBox;
152     int ret = Success;
153 
154     if (pDrawable->type != DRAWABLE_WINDOW)
155         return BadWindow;
156 
157     WinBox.x1 = pDrawable->x + drw_x;
158     WinBox.y1 = pDrawable->y + drw_y;
159     WinBox.x2 = WinBox.x1 + drw_w;
160     WinBox.y2 = WinBox.y1 + drw_h;
161 
162     RegionInit(&WinRegion, &WinBox, 1);
163     RegionInit(&ClipRegion, NullBox, 1);
164     RegionIntersect(&ClipRegion, &WinRegion, pGC->pCompositeClip);
165 
166     if (RegionNotEmpty(&ClipRegion))
167         ret = glamor_xv_put_image(gpp,
168                                   pDrawable,
169                                   src_x,
170                                   src_y,
171                                   pDrawable->x + drw_x,
172                                   pDrawable->y + drw_y,
173                                   src_w,
174                                   src_h,
175                                   drw_w,
176                                   drw_h,
177                                   format->id,
178                                   data,
179                                   width,
180                                   height,
181                                   sync,
182                                   &ClipRegion);
183 
184      RegionUninit(&WinRegion);
185      RegionUninit(&ClipRegion);
186 
187      return ret;
188 
189 }
190 
191 static Bool
xwl_glamor_xv_add_formats(XvAdaptorPtr pa)192 xwl_glamor_xv_add_formats(XvAdaptorPtr pa)
193 {
194     ScreenPtr pScreen;
195     XvFormatPtr pFormat, pf;
196     VisualPtr pVisual;
197     int numFormat;
198     int totFormat;
199     int numVisuals;
200     int i;
201 
202     totFormat = NUM_FORMATS;
203     pFormat = xnfcalloc(totFormat, sizeof(XvFormatRec));
204     pScreen = pa->pScreen;
205     for (pf = pFormat, i = 0, numFormat = 0; i < NUM_FORMATS; i++) {
206         numVisuals = pScreen->numVisuals;
207         pVisual = pScreen->visuals;
208 
209         while (numVisuals--) {
210            if ((pVisual->class == Formats[i].class) &&
211                (pVisual->nplanes == Formats[i].depth)) {
212                     if (numFormat >= totFormat) {
213                         void *moreSpace;
214 
215                         totFormat *= 2;
216                         moreSpace = xnfreallocarray(pFormat, totFormat,
217                                                     sizeof(XvFormatRec));
218                         pFormat = moreSpace;
219                         pf = pFormat + numFormat;
220                     }
221 
222                     pf->visual = pVisual->vid;
223                     pf->depth = Formats[i].depth;
224 
225                     pf++;
226                     numFormat++;
227                 }
228             pVisual++;
229         }
230     }
231     pa->nFormats = numFormat;
232     pa->pFormats = pFormat;
233 
234     return numFormat != 0;
235 }
236 
237 static Bool
xwl_glamor_xv_add_ports(XvAdaptorPtr pa)238 xwl_glamor_xv_add_ports(XvAdaptorPtr pa)
239 {
240     XvPortPtr pPorts, pp;
241     xwlXvScreenPtr xwlXvScreen;
242     unsigned long PortResource = 0;
243     int nPorts;
244     int i;
245 
246     pPorts = xnfcalloc(NUM_PORTS, sizeof(XvPortRec));
247     xwlXvScreen = dixLookupPrivate(&(pa->pScreen)->devPrivates,
248                                    xwlXvScreenPrivateKey);
249     xwlXvScreen->port_privates = xnfcalloc(NUM_PORTS,
250                                            sizeof(glamor_port_private));
251 
252     PortResource = XvGetRTPort();
253     for (pp = pPorts, i = 0, nPorts = 0; i < NUM_PORTS; i++) {
254         if (!(pp->id = FakeClientID(0)))
255             continue;
256 
257         pp->pAdaptor = pa;
258 
259         glamor_xv_init_port(&xwlXvScreen->port_privates[i]);
260         pp->devPriv.ptr = &xwlXvScreen->port_privates[i];
261 
262         if (AddResource(pp->id, PortResource, pp)) {
263             pp++;
264             nPorts++;
265         }
266     }
267 
268     pa->base_id = pPorts->id;
269     pa->nPorts = nPorts;
270     pa->pPorts = pPorts;
271 
272     return nPorts != 0;
273 }
274 
275 static void
xwl_glamor_xv_add_attributes(XvAdaptorPtr pa)276 xwl_glamor_xv_add_attributes(XvAdaptorPtr pa)
277 {
278     int i;
279 
280     pa->pAttributes = xnfcalloc(glamor_xv_num_attributes, sizeof(XvAttributeRec));
281     memcpy(pa->pAttributes, glamor_xv_attributes,
282            glamor_xv_num_attributes * sizeof(XvAttributeRec));
283 
284     for (i = 0; i < glamor_xv_num_attributes; i++)
285         pa->pAttributes[i].name = strdup(glamor_xv_attributes[i].name);
286 
287     pa->nAttributes = glamor_xv_num_attributes;
288 }
289 
290 static void
xwl_glamor_xv_add_images(XvAdaptorPtr pa)291 xwl_glamor_xv_add_images(XvAdaptorPtr pa)
292 {
293     pa->pImages = xnfcalloc(glamor_xv_num_images, sizeof(XvImageRec));
294     memcpy(pa->pImages, glamor_xv_images, glamor_xv_num_images * sizeof(XvImageRec));
295 
296     pa->nImages = glamor_xv_num_images;
297 }
298 
299 static void
xwl_glamor_xv_add_encodings(XvAdaptorPtr pa)300 xwl_glamor_xv_add_encodings(XvAdaptorPtr pa)
301 {
302     XvEncodingPtr pe;
303     GLint texsize;
304 
305     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texsize);
306 
307     pe = xnfcalloc(1, sizeof(XvEncodingRec));
308     pe->id = 0;
309     pe->pScreen = pa->pScreen;
310     pe->name = strdup(ENCODER_NAME);
311     pe->width = texsize;
312     pe->height = texsize;
313     pe->rate.numerator = 1;
314     pe->rate.denominator = 1;
315 
316     pa->pEncodings = pe;
317     pa->nEncodings = 1;
318 }
319 
320 static Bool
xwl_glamor_xv_add_adaptors(ScreenPtr pScreen)321 xwl_glamor_xv_add_adaptors(ScreenPtr pScreen)
322 {
323     DevPrivateKey XvScreenKey;
324     XvScreenPtr XvScreen;
325     xwlXvScreenPtr xwlXvScreen;
326     XvAdaptorPtr pa;
327 
328     if (XvScreenInit(pScreen) != Success)
329         return FALSE;
330 
331     XvScreenKey = XvGetScreenKey();
332     XvScreen = dixLookupPrivate(&(pScreen)->devPrivates, XvScreenKey);
333 
334     XvScreen->nAdaptors = 0;
335     XvScreen->pAdaptors = NULL;
336 
337     pa = xnfcalloc(1, sizeof(XvAdaptorRec));
338     pa->pScreen = pScreen;
339     pa->type = (unsigned char) (XvInputMask | XvImageMask);
340     pa->ddStopVideo = xwl_glamor_xv_stop_video;
341     pa->ddPutImage = xwl_glamor_xv_put_image;
342     pa->ddSetPortAttribute = xwl_glamor_xv_set_port_attribute;
343     pa->ddGetPortAttribute = xwl_glamor_xv_get_port_attribute;
344     pa->ddQueryBestSize = xwl_glamor_xv_query_best_size;
345     pa->ddQueryImageAttributes = xwl_glamor_xv_query_image_attributes;
346     pa->name = strdup(ADAPTOR_NAME);
347 
348     xwl_glamor_xv_add_encodings(pa);
349     xwl_glamor_xv_add_images(pa);
350     xwl_glamor_xv_add_attributes(pa);
351     if (!xwl_glamor_xv_add_formats(pa))
352         goto failed;
353     if (!xwl_glamor_xv_add_ports(pa))
354         goto failed;
355 
356     /* We're good now with out Xv adaptor */
357     XvScreen->nAdaptors = 1;
358     XvScreen->pAdaptors = pa;
359 
360     xwlXvScreen = dixLookupPrivate(&(pa->pScreen)->devPrivates,
361                                    xwlXvScreenPrivateKey);
362     xwlXvScreen->glxv_adaptor = pa;
363 
364     return TRUE;
365 
366 failed:
367     XvFreeAdaptor(pa);
368     free(pa);
369 
370     return FALSE;
371 }
372 
373 static Bool
xwl_glamor_xv_close_screen(ScreenPtr pScreen)374 xwl_glamor_xv_close_screen(ScreenPtr pScreen)
375 {
376     xwlXvScreenPtr xwlXvScreen;
377 
378     xwlXvScreen = dixLookupPrivate(&(pScreen)->devPrivates,
379                                    xwlXvScreenPrivateKey);
380 
381     if (xwlXvScreen->glxv_adaptor) {
382         XvFreeAdaptor(xwlXvScreen->glxv_adaptor);
383         free(xwlXvScreen->glxv_adaptor);
384     }
385     free(xwlXvScreen->port_privates);
386 
387     pScreen->CloseScreen = xwlXvScreen->CloseScreen;
388 
389     return pScreen->CloseScreen(pScreen);
390 }
391 
392 Bool
xwl_glamor_xv_init(ScreenPtr pScreen)393 xwl_glamor_xv_init(ScreenPtr pScreen)
394 {
395     xwlXvScreenPtr xwlXvScreen;
396 
397     if (!dixRegisterPrivateKey(xwlXvScreenPrivateKey, PRIVATE_SCREEN,
398                                sizeof(xwlXvScreenRec)))
399         return FALSE;
400 
401     xwlXvScreen = dixLookupPrivate(&(pScreen)->devPrivates,
402                                     xwlXvScreenPrivateKey);
403 
404     xwlXvScreen->port_privates = NULL;
405     xwlXvScreen->glxv_adaptor = NULL;
406     xwlXvScreen->CloseScreen = pScreen->CloseScreen;
407     pScreen->CloseScreen = xwl_glamor_xv_close_screen;
408 
409     glamor_xv_core_init(pScreen);
410 
411     return xwl_glamor_xv_add_adaptors(pScreen);
412 }
413