1 /*
2 Copyright 2011-2017 Jay Sorg
3 
4 Permission to use, copy, modify, distribute, and sell this software and its
5 documentation for any purpose is hereby granted without fee, provided that
6 the above copyright notice appear in all copies and that both that
7 copyright notice and this permission notice appear in supporting
8 documentation.
9 
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
12 
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
16 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 
20 RandR draw calls
21 
22 */
23 
24 #if defined(HAVE_CONFIG_H)
25 #include "config_ac.h"
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 /* this should be before all X11 .h files */
33 #include <xorg-server.h>
34 #include <xorgVersion.h>
35 
36 /* all driver need this */
37 #include <xf86.h>
38 #include <xf86_OSproc.h>
39 
40 #include <mipointer.h>
41 #include <fb.h>
42 #include <micmap.h>
43 #include <mi.h>
44 
45 #include "rdp.h"
46 #include "rdpDraw.h"
47 #include "rdpReg.h"
48 #include "rdpMisc.h"
49 #include "rdpRandR.h"
50 
51 #if defined(XORGXRDP_GLAMOR)
52 #include <glamor.h>
53 #endif
54 
55 static int g_panning = 0;
56 
57 /******************************************************************************/
58 #define LOG_LEVEL 1
59 #define LLOGLN(_level, _args) \
60     do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
61 
62 /******************************************************************************/
63 Bool
rdpRRRegisterSize(ScreenPtr pScreen,int width,int height)64 rdpRRRegisterSize(ScreenPtr pScreen, int width, int height)
65 {
66     int mmwidth;
67     int mmheight;
68     RRScreenSizePtr pSize;
69     ScrnInfoPtr pScrn;
70 
71     LLOGLN(0, ("rdpRRRegisterSize: width %d height %d", width, height));
72     pScrn = xf86Screens[pScreen->myNum];
73     mmwidth = PixelToMM(width, pScrn->xDpi);
74     mmheight = PixelToMM(height, pScrn->yDpi);
75     pSize = RRRegisterSize(pScreen, width, height, mmwidth, mmheight);
76     /* Tell RandR what the current config is */
77     RRSetCurrentConfig(pScreen, RR_Rotate_0, 0, pSize);
78     return TRUE;
79 }
80 
81 /******************************************************************************/
82 Bool
rdpRRSetConfig(ScreenPtr pScreen,Rotation rotateKind,int rate,RRScreenSizePtr pSize)83 rdpRRSetConfig(ScreenPtr pScreen, Rotation rotateKind, int rate,
84                RRScreenSizePtr pSize)
85 {
86     LLOGLN(0, ("rdpRRSetConfig:"));
87     return TRUE;
88 }
89 
90 /******************************************************************************/
91 Bool
rdpRRGetInfo(ScreenPtr pScreen,Rotation * pRotations)92 rdpRRGetInfo(ScreenPtr pScreen, Rotation *pRotations)
93 {
94     LLOGLN(0, ("rdpRRGetInfo:"));
95     *pRotations = RR_Rotate_0;
96     return TRUE;
97 }
98 
99 #if defined(XORGXRDP_GLAMOR)
100 /*****************************************************************************/
101 static int
rdpRRSetPixmapVisitWindow(WindowPtr window,void * data)102 rdpRRSetPixmapVisitWindow(WindowPtr window, void *data)
103 {
104     ScreenPtr screen;
105 
106     LLOGLN(10, ("rdpRRSetPixmapVisitWindow:"));
107     screen = window->drawable.pScreen;
108     if (screen->GetWindowPixmap(window) == data)
109     {
110         screen->SetWindowPixmap(window, screen->GetScreenPixmap(screen));
111         return WT_WALKCHILDREN;
112     }
113     return WT_DONTWALKCHILDREN;
114 }
115 #endif
116 
117 /******************************************************************************/
118 Bool
rdpRRScreenSetSize(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)119 rdpRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height,
120                    CARD32 mmWidth, CARD32 mmHeight)
121 {
122     WindowPtr root;
123     PixmapPtr screenPixmap;
124     BoxRec box;
125     rdpPtr dev;
126 
127     LLOGLN(0, ("rdpRRScreenSetSize: width %d height %d mmWidth %d mmHeight %d",
128            width, height, (int)mmWidth, (int)mmHeight));
129     dev = rdpGetDevFromScreen(pScreen);
130     if (dev->allow_screen_resize == 0)
131     {
132         if ((width == pScreen->width) && (height == pScreen->height) &&
133             (mmWidth == pScreen->mmWidth) && (mmHeight == pScreen->mmHeight))
134         {
135             LLOGLN(0, ("rdpRRScreenSetSize: already this size"));
136             return TRUE;
137         }
138         LLOGLN(0, ("rdpRRScreenSetSize: not allowing resize"));
139         return FALSE;
140     }
141     root = rdpGetRootWindowPtr(pScreen);
142     if ((width < 1) || (height < 1))
143     {
144         LLOGLN(10, ("  error width %d height %d", width, height));
145         return FALSE;
146     }
147     dev->width = width;
148     dev->height = height;
149     dev->paddedWidthInBytes = PixmapBytePad(dev->width, dev->depth);
150     dev->sizeInBytes = dev->paddedWidthInBytes * dev->height;
151     pScreen->width = width;
152     pScreen->height = height;
153     pScreen->mmWidth = mmWidth;
154     pScreen->mmHeight = mmHeight;
155     screenPixmap = dev->screenSwPixmap;
156     free(dev->pfbMemory_alloc);
157     dev->pfbMemory_alloc = g_new0(uint8_t, dev->sizeInBytes + 16);
158     dev->pfbMemory = (uint8_t *) RDPALIGN(dev->pfbMemory_alloc, 16);
159     pScreen->ModifyPixmapHeader(screenPixmap, width, height,
160                                 -1, -1,
161                                 dev->paddedWidthInBytes,
162                                 dev->pfbMemory);
163     if (dev->glamor)
164     {
165 #if defined(XORGXRDP_GLAMOR)
166         PixmapPtr old_screen_pixmap;
167         uint32_t screen_tex;
168         old_screen_pixmap = pScreen->GetScreenPixmap(pScreen);
169         screenPixmap = pScreen->CreatePixmap(pScreen,
170                                              pScreen->width,
171                                              pScreen->height,
172                                              pScreen->rootDepth,
173                                              GLAMOR_CREATE_NO_LARGE);
174         if (screenPixmap == NULL)
175         {
176             return FALSE;
177         }
178         screen_tex = glamor_get_pixmap_texture(screenPixmap);
179         LLOGLN(0, ("rdpRRScreenSetSize: screen_tex 0x%8.8x", screen_tex));
180         pScreen->SetScreenPixmap(screenPixmap);
181         if ((pScreen->root != NULL) && (pScreen->SetWindowPixmap != NULL))
182         {
183             TraverseTree(pScreen->root, rdpRRSetPixmapVisitWindow, old_screen_pixmap);
184         }
185         pScreen->DestroyPixmap(old_screen_pixmap);
186 #endif
187     }
188     box.x1 = 0;
189     box.y1 = 0;
190     box.x2 = width;
191     box.y2 = height;
192     rdpRegionInit(&root->winSize, &box, 1);
193     rdpRegionInit(&root->borderSize, &box, 1);
194     rdpRegionReset(&root->borderClip, &box);
195     rdpRegionBreak(&root->clipList);
196     root->drawable.width = width;
197     root->drawable.height = height;
198     ResizeChildrenWinSize(root, 0, 0, 0, 0);
199     RRGetInfo(pScreen, 1);
200     LLOGLN(0, ("  screen resized to %dx%d", pScreen->width, pScreen->height));
201     RRScreenSizeNotify(pScreen);
202 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 13, 0, 0, 0)
203     xf86EnableDisableFBAccess(pScreen->myNum, FALSE);
204     xf86EnableDisableFBAccess(pScreen->myNum, TRUE);
205 #else
206     xf86EnableDisableFBAccess(xf86Screens[pScreen->myNum], FALSE);
207     xf86EnableDisableFBAccess(xf86Screens[pScreen->myNum], TRUE);
208 #endif
209     return TRUE;
210 }
211 
212 /******************************************************************************/
213 Bool
rdpRRCrtcSet(ScreenPtr pScreen,RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,int numOutputs,RROutputPtr * outputs)214 rdpRRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
215              int x, int y, Rotation rotation, int numOutputs,
216              RROutputPtr *outputs)
217 {
218     LLOGLN(0, ("rdpRRCrtcSet:"));
219     return TRUE;
220 }
221 
222 /******************************************************************************/
223 Bool
rdpRRCrtcSetGamma(ScreenPtr pScreen,RRCrtcPtr crtc)224 rdpRRCrtcSetGamma(ScreenPtr pScreen, RRCrtcPtr crtc)
225 {
226     LLOGLN(0, ("rdpRRCrtcSetGamma:"));
227     return TRUE;
228 }
229 
230 /******************************************************************************/
231 Bool
rdpRRCrtcGetGamma(ScreenPtr pScreen,RRCrtcPtr crtc)232 rdpRRCrtcGetGamma(ScreenPtr pScreen, RRCrtcPtr crtc)
233 {
234     LLOGLN(0, ("rdpRRCrtcGetGamma: %p %p %p %p", crtc, crtc->gammaRed,
235            crtc->gammaBlue, crtc->gammaGreen));
236     return TRUE;
237 }
238 
239 /******************************************************************************/
240 Bool
rdpRROutputSetProperty(ScreenPtr pScreen,RROutputPtr output,Atom property,RRPropertyValuePtr value)241 rdpRROutputSetProperty(ScreenPtr pScreen, RROutputPtr output, Atom property,
242                        RRPropertyValuePtr value)
243 {
244     LLOGLN(0, ("rdpRROutputSetProperty:"));
245     return TRUE;
246 }
247 
248 /******************************************************************************/
249 Bool
rdpRROutputValidateMode(ScreenPtr pScreen,RROutputPtr output,RRModePtr mode)250 rdpRROutputValidateMode(ScreenPtr pScreen, RROutputPtr output,
251                         RRModePtr mode)
252 {
253     LLOGLN(0, ("rdpRROutputValidateMode:"));
254     return TRUE;
255 }
256 
257 /******************************************************************************/
258 void
rdpRRModeDestroy(ScreenPtr pScreen,RRModePtr mode)259 rdpRRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
260 {
261     LLOGLN(0, ("rdpRRModeDestroy:"));
262 }
263 
264 /******************************************************************************/
265 Bool
rdpRROutputGetProperty(ScreenPtr pScreen,RROutputPtr output,Atom property)266 rdpRROutputGetProperty(ScreenPtr pScreen, RROutputPtr output, Atom property)
267 {
268     LLOGLN(0, ("rdpRROutputGetProperty:"));
269     return TRUE;
270 }
271 
272 /******************************************************************************/
273 #if 0
274 static int
275 get_rect(rdpPtr dev, const char *name, BoxPtr rect)
276 {
277     if (strcmp(name, "rdp0") == 0)
278     {
279         rect->x1 = dev->minfo[0].left;
280         rect->y1 = dev->minfo[0].top;
281         rect->x2 = dev->minfo[0].right + 1;
282         rect->y2 = dev->minfo[0].bottom + 1;
283     }
284     else if (strcmp(name, "rdp1") == 0)
285     {
286         rect->x1 = dev->minfo[1].left;
287         rect->y1 = dev->minfo[1].top;
288         rect->x2 = dev->minfo[1].right + 1;
289         rect->y2 = dev->minfo[1].bottom + 1;
290     }
291     else if (strcmp(name, "rdp2") == 0)
292     {
293         rect->x1 = dev->minfo[2].left;
294         rect->y1 = dev->minfo[2].top;
295         rect->x2 = dev->minfo[2].right + 1;
296         rect->y2 = dev->minfo[2].bottom + 1;
297     }
298     else if (strcmp(name, "rdp3") == 0)
299     {
300         rect->x1 = dev->minfo[3].left;
301         rect->y1 = dev->minfo[3].top;
302         rect->x2 = dev->minfo[3].right + 1;
303         rect->y2 = dev->minfo[3].bottom + 1;
304     }
305     return 0;
306 }
307 #endif
308 
309 /******************************************************************************/
310 Bool
rdpRRGetPanning(ScreenPtr pScreen,RRCrtcPtr crtc,BoxPtr totalArea,BoxPtr trackingArea,INT16 * border)311 rdpRRGetPanning(ScreenPtr pScreen, RRCrtcPtr crtc, BoxPtr totalArea,
312                 BoxPtr trackingArea, INT16 *border)
313 {
314     rdpPtr dev;
315     BoxRec totalAreaRect;
316     BoxRec trackingAreaRect;
317 
318     LLOGLN(10, ("rdpRRGetPanning: totalArea %p trackingArea %p border %p",
319                 totalArea, trackingArea, border));
320 
321     if (!g_panning)
322     {
323         return FALSE;
324     }
325 
326     dev = rdpGetDevFromScreen(pScreen);
327 
328     totalAreaRect.x1 = 0;
329     totalAreaRect.y1 = 0;
330     totalAreaRect.x2 = dev->width;
331     totalAreaRect.y2 = dev->height;
332 
333     trackingAreaRect.x1 = 0;
334     trackingAreaRect.y1 = 0;
335     trackingAreaRect.x2 = dev->width;
336     trackingAreaRect.y2 = dev->height;
337 
338     if (totalArea != 0)
339     {
340         *totalArea = totalAreaRect;
341     }
342 
343     if (trackingArea != 0)
344     {
345         *trackingArea = trackingAreaRect;
346     }
347 
348     if (border != 0)
349     {
350         border[0] = 0;
351         border[1] = 0;
352         border[2] = 0;
353         border[3] = 0;
354     }
355     return TRUE;
356 }
357 
358 /******************************************************************************/
359 Bool
rdpRRSetPanning(ScreenPtr pScreen,RRCrtcPtr crtc,BoxPtr totalArea,BoxPtr trackingArea,INT16 * border)360 rdpRRSetPanning(ScreenPtr pScreen, RRCrtcPtr crtc, BoxPtr totalArea,
361                 BoxPtr trackingArea, INT16 *border)
362 {
363     LLOGLN(0, ("rdpRRSetPanning:"));
364     return TRUE;
365 }
366 
367 /******************************************************************************/
368 static RROutputPtr
rdpRRAddOutput(rdpPtr dev,const char * aname,int x,int y,int width,int height)369 rdpRRAddOutput(rdpPtr dev, const char *aname, int x, int y, int width, int height)
370 {
371     RRModePtr mode;
372     RRCrtcPtr crtc;
373     RROutputPtr output;
374     xRRModeInfo modeInfo;
375     char name[64];
376     const int vfreq = 50;
377     int i;
378 
379     sprintf (name, "%dx%d", width, height);
380     memset (&modeInfo, 0, sizeof(modeInfo));
381     modeInfo.width = width;
382     modeInfo.height = height;
383     modeInfo.hTotal = width;
384     modeInfo.vTotal = height;
385     modeInfo.dotClock = vfreq * width * height;
386     modeInfo.nameLength = strlen(name);
387     mode = RRModeGet(&modeInfo, name);
388     if (mode == 0)
389     {
390         LLOGLN(0, ("rdpRRAddOutput: RRModeGet failed"));
391         return 0;
392     }
393 
394     crtc = RRCrtcCreate(dev->pScreen, NULL);
395     if (crtc == 0)
396     {
397         LLOGLN(0, ("rdpRRAddOutput: RRCrtcCreate failed"));
398         RRModeDestroy(mode);
399         return 0;
400     }
401     /* Create and initialise (unused) gamma ramps */
402     RRCrtcGammaSetSize (crtc, 256);
403     for (i = 0 ; i < crtc->gammaSize; ++i)
404     {
405         unsigned short val = (0xffff * i) / (crtc->gammaSize - 1);
406         crtc->gammaRed[i] = val;
407         crtc->gammaGreen[i] = val;
408         crtc->gammaBlue[i] = val;
409     }
410 
411     output = RROutputCreate(dev->pScreen, aname, strlen(aname), NULL);
412     if (output == 0)
413     {
414         LLOGLN(0, ("rdpRRAddOutput: RROutputCreate failed"));
415         RRCrtcDestroy(crtc);
416         RRModeDestroy(mode);
417         return 0;
418     }
419     if (!RROutputSetClones(output, NULL, 0))
420     {
421         LLOGLN(0, ("rdpRRAddOutput: RROutputSetClones failed"));
422     }
423     if (!RROutputSetModes(output, &mode, 1, 0))
424     {
425         LLOGLN(0, ("rdpRRAddOutput: RROutputSetModes failed"));
426     }
427     if (!RROutputSetCrtcs(output, &crtc, 1))
428     {
429         LLOGLN(0, ("rdpRRAddOutput: RROutputSetCrtcs failed"));
430     }
431     if (!RROutputSetConnection(output, RR_Connected))
432     {
433         LLOGLN(0, ("rdpRRAddOutput: RROutputSetConnection failed"));
434     }
435     RRCrtcNotify(crtc, mode, x, y, RR_Rotate_0, NULL, 1, &output);
436     return output;
437 }
438 
439 /******************************************************************************/
440 static RROutputPtr
rdpRRUpdateOutput(RROutputPtr output,RRCrtcPtr crtc,int x,int y,int width,int height)441 rdpRRUpdateOutput(RROutputPtr output, RRCrtcPtr crtc,
442                   int x, int y, int width, int height)
443 {
444     RRModePtr mode;
445     xRRModeInfo modeInfo;
446     char name[64];
447     const int vfreq = 50;
448 
449     LLOGLN(0, ("rdpRRUpdateOutput:"));
450     sprintf (name, "%dx%d", width, height);
451     memset (&modeInfo, 0, sizeof(modeInfo));
452     modeInfo.width = width;
453     modeInfo.height = height;
454     modeInfo.hTotal = width;
455     modeInfo.vTotal = height;
456     modeInfo.dotClock = vfreq * width * height;
457     modeInfo.nameLength = strlen(name);
458     mode = RRModeGet(&modeInfo, name);
459     if (mode == 0)
460     {
461         LLOGLN(0, ("rdpRRUpdateOutput: RRModeGet failed"));
462         return 0;
463     }
464     if (!RROutputSetModes(output, &mode, 1, 0))
465     {
466         LLOGLN(0, ("rdpRRUpdateOutput: RROutputSetModes failed"));
467     }
468     RRCrtcNotify(crtc, mode, x, y, RR_Rotate_0, NULL, 1, &output);
469     RROutputChanged(output, 1);
470     return output;
471 }
472 
473 /******************************************************************************/
474 static void
RRSetPrimaryOutput(rrScrPrivPtr pScrPriv,RROutputPtr output)475 RRSetPrimaryOutput(rrScrPrivPtr pScrPriv, RROutputPtr output)
476 {
477     if (pScrPriv->primaryOutput == output)
478     {
479         return;
480     }
481     /* clear the old primary */
482     if (pScrPriv->primaryOutput)
483     {
484         RROutputChanged(pScrPriv->primaryOutput, 0);
485         pScrPriv->primaryOutput = NULL;
486     }
487     /* set the new primary */
488     if (output)
489     {
490         pScrPriv->primaryOutput = output;
491         RROutputChanged(output, 0);
492     }
493     pScrPriv->layoutChanged = TRUE;
494 }
495 
496 /******************************************************************************/
497 static int
rdpRRRemoveExtra(rrScrPrivPtr pRRScrPriv,int count)498 rdpRRRemoveExtra(rrScrPrivPtr pRRScrPriv, int count)
499 {
500     int index;
501 
502     while (pRRScrPriv->numCrtcs > count)
503     {
504         index = pRRScrPriv->numCrtcs - 1;
505         RRCrtcDestroy(pRRScrPriv->crtcs[index]);
506         pRRScrPriv->crtcs[index] = NULL;
507     }
508     while (pRRScrPriv->numOutputs > count)
509     {
510         index = pRRScrPriv->numOutputs - 1;
511         RROutputDestroy(pRRScrPriv->outputs[index]);
512         pRRScrPriv->outputs[index] = NULL;
513     }
514     return 0;
515 }
516 
517 /******************************************************************************/
518 int
rdpRRSetRdpOutputs(rdpPtr dev)519 rdpRRSetRdpOutputs(rdpPtr dev)
520 {
521     rrScrPrivPtr pRRScrPriv;
522     int index;
523     int left;
524     int top;
525     int width;
526     int height;
527     char text[256];
528     RROutputPtr output;
529 
530     pRRScrPriv = rrGetScrPriv(dev->pScreen);
531     LLOGLN(0, ("rdpRRSetRdpOutputs: numCrtcs %d numOutputs %d monitorCount %d",
532            pRRScrPriv->numCrtcs, pRRScrPriv->numOutputs, dev->monitorCount));
533     if (dev->monitorCount <= 0)
534     {
535         left = 0;
536         top = 0;
537         width = dev->width;
538         height = dev->height;
539         if (pRRScrPriv->numCrtcs > 0)
540         {
541             /* update */
542             LLOGLN(0, ("rdpRRSetRdpOutputs: update output %d "
543                    "left %d top %d width %d height %d",
544                    0, left, top, width, height));
545             output = rdpRRUpdateOutput(pRRScrPriv->outputs[0],
546                                        pRRScrPriv->crtcs[0],
547                                        left, top, width, height);
548         }
549         else
550         {
551             /* add */
552             LLOGLN(0, ("rdpRRSetRdpOutputs: add output %d "
553                    "left %d top %d width %d height %d",
554                    0, left, top, width, height));
555             snprintf(text, 255, "rdp%d", 0);
556             output = rdpRRAddOutput(dev, text,
557                                     left, top, width, height);
558         }
559         if (output == NULL)
560         {
561             LLOGLN(0, ("rdpRRSetRdpOutputs: rdpRRUpdateOutput failed"));
562             return 1;
563         }
564         /* remove any entra */
565         rdpRRRemoveExtra(pRRScrPriv, 1);
566     }
567     else
568     {
569         for (index = 0; index < dev->monitorCount; index++)
570         {
571             left = dev->minfo[index].left;
572             top = dev->minfo[index].top;
573             width = dev->minfo[index].right - dev->minfo[index].left + 1;
574             height = dev->minfo[index].bottom - dev->minfo[index].top + 1;
575             if (index < pRRScrPriv->numCrtcs)
576             {
577                 /* update */
578                 LLOGLN(0, ("rdpRRSetRdpOutputs: update output %d "
579                        "left %d top %d width %d height %d",
580                        index, left, top, width, height));
581                 output = rdpRRUpdateOutput(pRRScrPriv->outputs[index],
582                                            pRRScrPriv->crtcs[index],
583                                            left, top, width, height);
584             }
585             else
586             {
587                 /* add */
588                 LLOGLN(0, ("rdpRRSetRdpOutputs: add output %d "
589                        "left %d top %d width %d height %d",
590                        index, left, top, width, height));
591                 snprintf(text, 255, "rdp%d", index);
592                 output = rdpRRAddOutput(dev, text,
593                                         left, top, width, height);
594             }
595             if ((output != 0) && (dev->minfo[index].is_primary))
596             {
597                 RRSetPrimaryOutput(pRRScrPriv, output);
598             }
599             if (output == NULL)
600             {
601                 LLOGLN(0, ("rdpRRSetRdpOutputs: rdpRRUpdateOutput failed"));
602                 return 1;
603             }
604         }
605         /* remove any entra */
606         rdpRRRemoveExtra(pRRScrPriv, dev->monitorCount);
607     }
608     return 0;
609 }
610 
611