diff --git a/module/amd64/Makefile.am b/module/amd64/Makefile.am
index cd2a020..7bff1c5 100644
--- a/module/amd64/Makefile.am
+++ b/module/amd64/Makefile.am
@@ -3,6 +3,7 @@ NAFLAGS += -DASM_ARCH_AMD64
 ASMSOURCES = \
   a8r8g8b8_to_a8b8g8r8_box_amd64_sse2.asm \
   a8r8g8b8_to_nv12_box_amd64_sse2.asm \
+  a8r8g8b8_to_nv12_709fr_box_amd64_sse2.asm \
   cpuid_amd64.asm \
   i420_to_rgb32_amd64_sse2.asm \
   uyvy_to_rgb32_amd64_sse2.asm \
diff --git a/module/amd64/a8r8g8b8_to_nv12_709fr_box_amd64_sse2.asm b/module/amd64/a8r8g8b8_to_nv12_709fr_box_amd64_sse2.asm
new file mode 100644
index 0000000..c18e9d6
--- /dev/null
+++ b/module/amd64/a8r8g8b8_to_nv12_709fr_box_amd64_sse2.asm
@@ -0,0 +1,304 @@
+;
+;Copyright 2015 Jay Sorg
+;
+;Permission to use, copy, modify, distribute, and sell this software and its
+;documentation for any purpose is hereby granted without fee, provided that
+;the above copyright notice appear in all copies and that both that
+;copyright notice and this permission notice appear in supporting
+;documentation.
+;
+;The above copyright notice and this permission notice shall be included in
+;all copies or substantial portions of the Software.
+;
+;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+;OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+;AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+;
+;ARGB to NV12 709 full range
+;amd64 SSE2
+;
+; notes
+;   address s8 should be aligned on 16 bytes, will be slower if not
+;   width should be multiple of 8 and > 0
+;   height should be even and > 0
+
+%include "common.asm"
+
+PREPARE_RODATA
+    cd255  times 4 dd 255
+
+    cw255  times 8 dw 255
+    cw128  times 8 dw 128
+    cw54   times 8 dw 54
+    cw183  times 8 dw 183
+    cw18   times 8 dw 18
+    cw29   times 8 dw 29
+    cw99   times 8 dw 99
+    cw116  times 8 dw 116
+    cw12   times 8 dw 12
+    cw2    times 8 dw 2
+
+%define LS8            [rsp +   0] ; s8
+%define LSRC_STRIDE    [rsp +   8] ; src_stride
+%define LD8_Y          [rsp +  16] ; d8_y
+%define LDST_Y_STRIDE  [rsp +  24] ; dst_stride_y
+%define LD8_UV         [rsp +  32] ; d8_uv
+%define LDST_UV_STRIDE [rsp +  40] ; dst_stride_uv
+%define LU1            [rsp +  48] ; first line U, 8 bytes
+%define LV1            [rsp +  56] ; first line V, 8 bytes
+%define LU2            [rsp +  64] ; second line U, 8 bytes
+%define LV2            [rsp +  72] ; second line V, 8 bytes
+
+%define LWIDTH         [rsp + 104] ; width
+%define LHEIGHT        [rsp + 112] ; height
+
+;The first six integer or pointer arguments are passed in registers
+; RDI, RSI, RDX, RCX, R8, and R9
+
+;int
+;a8r8g8b8_to_nv12_709fr_box_amd64_sse2(const char *s8, int src_stride,
+;                                      char *d8_y, int dst_stride_y,
+;                                      char *d8_uv, int dst_stride_uv,
+;                                      int width, int height);
+PROC a8r8g8b8_to_nv12_709fr_box_amd64_sse2
+    push rbx
+    push rbp
+    sub rsp, 80                ; local vars, 80 bytes
+
+    mov LS8, rdi               ; s8
+    mov LSRC_STRIDE, rsi       ; src_stride
+    mov LD8_Y, rdx             ; d8_y
+    mov LDST_Y_STRIDE, rcx     ; dst_stride_y
+    mov LD8_UV, r8             ; d8_uv
+    mov LDST_UV_STRIDE, r9     ; dst_stride_uv
+
+    pxor xmm7, xmm7
+
+    mov ebx, LHEIGHT           ; ebx = height
+    shr ebx, 1                 ; doing 2 lines at a time
+
+row_loop1:
+    mov rsi, LS8               ; s8
+    mov rdi, LD8_Y             ; d8_y
+    mov rdx, LD8_UV            ; d8_uv
+
+    mov ecx, LWIDTH            ; ecx = width
+    shr ecx, 3                 ; doing 8 pixels at a time
+
+loop1:
+    ; first line
+    movdqu xmm0, [rsi]         ; 4 pixels, 16 bytes
+    movdqa xmm1, xmm0          ; blue
+    pand xmm1, [lsym(cd255)]   ; blue
+    movdqa xmm2, xmm0          ; green
+    psrld xmm2, 8              ; green
+    pand xmm2, [lsym(cd255)]   ; green
+    movdqa xmm3, xmm0          ; red
+    psrld xmm3, 16             ; red
+    pand xmm3, [lsym(cd255)]   ; red
+
+    movdqu xmm0, [rsi + 16]    ; 4 pixels, 16 bytes
+    movdqa xmm4, xmm0          ; blue
+    pand xmm4, [lsym(cd255)]   ; blue
+    movdqa xmm5, xmm0          ; green
+    psrld xmm5, 8              ; green
+    pand xmm5, [lsym(cd255)]   ; green
+    movdqa xmm6, xmm0          ; red
+    psrld xmm6, 16             ; red
+    pand xmm6, [lsym(cd255)]   ; red
+
+    packssdw xmm1, xmm4        ; xmm1 = 8 blues
+    packssdw xmm2, xmm5        ; xmm2 = 8 greens
+    packssdw xmm3, xmm6        ; xmm3 = 8 reds
+
+    ; _Y = (( 54 * _R + 183 * _G +  18 * _B) >> 8);
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw18)]
+    pmullw xmm5, [lsym(cw183)]
+    pmullw xmm6, [lsym(cw54)]
+    paddw xmm4, xmm5
+    paddw xmm4, xmm6
+    psrlw xmm4, 8
+    packuswb xmm4, xmm7
+    movq [rdi], xmm4           ; out 8 bytes yyyyyyyy
+
+    ; _U = ((-29 * _R -  99 * _G + 128 * _B) >> 8) + 128;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw99)]
+    pmullw xmm6, [lsym(cw29)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LU1, xmm4             ; save for later
+
+    ; _V = ((128 * _R - 116 * _G -  12 * _B) >> 8) + 128;
+    movdqa xmm6, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm4, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw116)]
+    pmullw xmm6, [lsym(cw12)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LV1, xmm4             ; save for later
+
+    ; go down to second line
+    add rsi, LSRC_STRIDE
+    add rdi, LDST_Y_STRIDE
+
+    ; second line
+    movdqu xmm0, [rsi]         ; 4 pixels, 16 bytes
+    movdqa xmm1, xmm0          ; blue
+    pand xmm1, [lsym(cd255)]   ; blue
+    movdqa xmm2, xmm0          ; green
+    psrld xmm2, 8              ; green
+    pand xmm2, [lsym(cd255)]   ; green
+    movdqa xmm3, xmm0          ; red
+    psrld xmm3, 16             ; red
+    pand xmm3, [lsym(cd255)]   ; red
+
+    movdqu xmm0, [rsi + 16]    ; 4 pixels, 16 bytes
+    movdqa xmm4, xmm0          ; blue
+    pand xmm4, [lsym(cd255)]   ; blue
+    movdqa xmm5, xmm0          ; green
+    psrld xmm5, 8              ; green
+    pand xmm5, [lsym(cd255)]   ; green
+    movdqa xmm6, xmm0          ; red
+    psrld xmm6, 16             ; red
+    pand xmm6, [lsym(cd255)]   ; red
+
+    packssdw xmm1, xmm4        ; xmm1 = 8 blues
+    packssdw xmm2, xmm5        ; xmm2 = 8 greens
+    packssdw xmm3, xmm6        ; xmm3 = 8 reds
+
+    ; _Y = (( 54 * _R + 183 * _G +  18 * _B) >> 8);
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw18)]
+    pmullw xmm5, [lsym(cw183)]
+    pmullw xmm6, [lsym(cw54)]
+    paddw xmm4, xmm5
+    paddw xmm4, xmm6
+    psrlw xmm4, 8
+    packuswb xmm4, xmm7
+    movq [rdi], xmm4           ; out 8 bytes yyyyyyyy
+
+    ; _U = ((-29 * _R -  99 * _G + 128 * _B) >> 8) + 128;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw99)]
+    pmullw xmm6, [lsym(cw29)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LU2, xmm4             ; save for later
+
+    ; _V = ((128 * _R - 116 * _G -  12 * _B) >> 8) + 128;
+    movdqa xmm6, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm4, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw116)]
+    pmullw xmm6, [lsym(cw12)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LV2, xmm4             ; save for later
+
+    ; uv add and divide(average)
+    movq mm1, LU1              ; u from first line
+    movq mm3, mm1
+    pand mm1, [lsym(cw255)]
+    psrlw mm3, 8
+    pand mm3, [lsym(cw255)]
+    paddw mm1, mm3             ; add
+    movq mm2, LU2              ; u from second line
+    movq mm3, mm2
+    pand mm2, [lsym(cw255)]
+    paddw mm1, mm2             ; add
+    psrlw mm3, 8
+    pand mm3, [lsym(cw255)]
+    paddw mm1, mm3             ; add
+    paddw mm1, [lsym(cw2)]     ; add 2
+    psrlw mm1, 2               ; div 4
+
+    movq mm2, LV1              ; v from first line
+    movq mm4, mm2
+    pand mm2, [lsym(cw255)]
+    psrlw mm4, 8
+    pand mm4, [lsym(cw255)]
+    paddw mm2, mm4             ; add
+    movq mm3, LV2              ; v from second line
+    movq mm4, mm3
+    pand mm3, [lsym(cw255)]
+    paddw mm2, mm3             ; add
+    psrlw mm4, 8
+    pand mm4, [lsym(cw255)]
+    paddw mm2, mm4             ; add
+    paddw mm2, [lsym(cw2)]     ; add 2
+    psrlw mm2, 2               ; div 4
+
+    packuswb mm1, mm1
+    packuswb mm2, mm2
+
+    punpcklbw mm1, mm2         ; uv
+    movq [rdx], mm1            ; out 8 bytes uvuvuvuv
+
+    ; go up to first line
+    sub rsi, LSRC_STRIDE
+    sub rdi, LDST_Y_STRIDE
+
+    ; move right
+    lea rsi, [rsi + 32]
+    lea rdi, [rdi + 8]
+    lea rdx, [rdx + 8]
+
+    dec ecx
+    jnz loop1
+
+    ; update s8
+    mov rax, LS8               ; s8
+    add rax, LSRC_STRIDE       ; s8 += src_stride
+    add rax, LSRC_STRIDE       ; s8 += src_stride
+    mov LS8, rax
+
+    ; update d8_y
+    mov rax, LD8_Y             ; d8_y
+    add rax, LDST_Y_STRIDE     ; d8_y += dst_stride_y
+    add rax, LDST_Y_STRIDE     ; d8_y += dst_stride_y
+    mov LD8_Y, rax
+
+    ; update d8_uv
+    mov rax, LD8_UV            ; d8_uv
+    add rax, LDST_UV_STRIDE    ; d8_uv += dst_stride_uv
+    mov LD8_UV, rax
+
+    dec ebx
+    jnz row_loop1
+
+    mov rax, 0                 ; return value
+    add rsp, 80                ; local vars, 80 bytes
+    pop rbp
+    pop rbx
+    ret
+END_OF_FILE
diff --git a/module/amd64/funcs_amd64.h b/module/amd64/funcs_amd64.h
index ae38c53..0af2fe8 100644
--- a/module/amd64/funcs_amd64.h
+++ b/module/amd64/funcs_amd64.h
@@ -43,6 +43,11 @@ a8r8g8b8_to_nv12_box_amd64_sse2(const uint8_t *s8, int src_stride,
                                 uint8_t *d8_y, int dst_stride_y,
                                 uint8_t *d8_uv, int dst_stride_uv,
                                 int width, int height);
+int
+a8r8g8b8_to_nv12_709fr_box_amd64_sse2(const uint8_t *s8, int src_stride,
+                                      uint8_t *d8_y, int dst_stride_y,
+                                      uint8_t *d8_uv, int dst_stride_uv,
+                                      int width, int height);
 
 #endif
 
diff --git a/module/rdp.h b/module/rdp.h
index 04ce191..ec9d04f 100644
--- a/module/rdp.h
+++ b/module/rdp.h
@@ -81,6 +81,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 /* XRDP_nv12 */
 #define XRDP_i420 \
 ((12 << 24) | (65 << 16) | (0 << 12) | (0 << 8) | (0 << 4) | 0)
+/* XRDP_nv12_709fr */
+#define XRDP_nv12_709fr \
+((12 << 24) | (66 << 16) | (0 << 12) | (0 << 8) | (0 << 4) | 0)
 
 #define PixelToMM(_size, _dpi) (((_size) * 254 + (_dpi) * 5) / ((_dpi) * 10))
 
@@ -312,6 +315,7 @@ struct _rdpRec
 
     copy_box_proc a8r8g8b8_to_a8b8g8r8_box;
     copy_box_dst2_proc a8r8g8b8_to_nv12_box;
+    copy_box_dst2_proc a8r8g8b8_to_nv12_709fr_box;
 
     /* multimon */
     struct monitor_info minfo[16]; /* client monitor data */
@@ -319,16 +323,20 @@ struct _rdpRec
     int monitorCount;
     /* glamor */
     Bool glamor;
+    Bool nvidia;
     PixmapPtr screenSwPixmap;
     void *xvPutImage;
     /* dri */
     int fd;
     /* egl */
     void *egl;
+
+    DamagePtr damage;
+
 };
 typedef struct _rdpRec rdpRec;
 typedef struct _rdpRec * rdpPtr;
-#define XRDPPTR(_p) ((rdpPtr)((_p)->driverPrivate))
+#define XRDPPTR(_p) ((rdpPtr)((_p)->reservedPtr[0]))
 
 struct _rdpGCRec
 {
diff --git a/module/rdpCapture.c b/module/rdpCapture.c
index 524edf4..53a3303 100644
--- a/module/rdpCapture.c
+++ b/module/rdpCapture.c
@@ -532,11 +532,109 @@ a8r8g8b8_to_nv12_box(const uint8_t *s8, int src_stride,
     return 0;
 }
 
+/******************************************************************************/
+int
+a8r8g8b8_to_nv12_709fr_box(const uint8_t *s8, int src_stride,
+                           uint8_t *d8_y, int dst_stride_y,
+                           uint8_t *d8_uv, int dst_stride_uv,
+                           int width, int height)
+{
+    int index;
+    int jndex;
+    int R;
+    int G;
+    int B;
+    int Y;
+    int U;
+    int V;
+    int U_sum;
+    int V_sum;
+    int pixel;
+    const uint32_t *s32a;
+    const uint32_t *s32b;
+    uint8_t *d8ya;
+    uint8_t *d8yb;
+    uint8_t *d8uv;
+
+    for (jndex = 0; jndex < height; jndex += 2)
+    {
+        s32a = (const uint32_t *) (s8 + src_stride * jndex);
+        s32b = (const uint32_t *) (s8 + src_stride * (jndex + 1));
+        d8ya = d8_y + dst_stride_y * jndex;
+        d8yb = d8_y + dst_stride_y * (jndex + 1);
+        d8uv = d8_uv + dst_stride_uv * (jndex / 2);
+        for (index = 0; index < width; index += 2)
+        {
+            U_sum = 0;
+            V_sum = 0;
+
+            pixel = s32a[0];
+            s32a++;
+            R = (pixel >> 16) & 0xff;
+            G = (pixel >>  8) & 0xff;
+            B = (pixel >>  0) & 0xff;
+            Y =  ( 54 * R + 183 * G +  18 * B) >> 8;
+            U = ((-29 * R -  99 * G + 128 * B) >> 8) + 128;
+            V = ((128 * R - 116 * G -  12 * B) >> 8) + 128;
+            d8ya[0] = RDPCLAMP(Y, 0, 255);
+            d8ya++;
+            U_sum += RDPCLAMP(U, 0, 255);
+            V_sum += RDPCLAMP(V, 0, 255);
+
+            pixel = s32a[0];
+            s32a++;
+            R = (pixel >> 16) & 0xff;
+            G = (pixel >>  8) & 0xff;
+            B = (pixel >>  0) & 0xff;
+            Y =  ( 54 * R + 183 * G +  18 * B) >> 8;
+            U = ((-29 * R -  99 * G + 128 * B) >> 8) + 128;
+            V = ((128 * R - 116 * G -  12 * B) >> 8) + 128;
+            d8ya[0] = RDPCLAMP(Y, 0, 255);
+            d8ya++;
+            U_sum += RDPCLAMP(U, 0, 255);
+            V_sum += RDPCLAMP(V, 0, 255);
+
+            pixel = s32b[0];
+            s32b++;
+            R = (pixel >> 16) & 0xff;
+            G = (pixel >>  8) & 0xff;
+            B = (pixel >>  0) & 0xff;
+            Y =  ( 54 * R + 183 * G +  18 * B) >> 8;
+            U = ((-29 * R -  99 * G + 128 * B) >> 8) + 128;
+            V = ((128 * R - 116 * G -  12 * B) >> 8) + 128;
+            d8yb[0] = RDPCLAMP(Y, 0, 255);
+            d8yb++;
+            U_sum += RDPCLAMP(U, 0, 255);
+            V_sum += RDPCLAMP(V, 0, 255);
+
+            pixel = s32b[0];
+            s32b++;
+            R = (pixel >> 16) & 0xff;
+            G = (pixel >>  8) & 0xff;
+            B = (pixel >>  0) & 0xff;
+            Y =  ( 54 * R + 183 * G +  18 * B) >> 8;
+            U = ((-29 * R -  99 * G + 128 * B) >> 8) + 128;
+            V = ((128 * R - 116 * G -  12 * B) >> 8) + 128;
+            d8yb[0] = RDPCLAMP(Y, 0, 255);
+            d8yb++;
+            U_sum += RDPCLAMP(U, 0, 255);
+            V_sum += RDPCLAMP(V, 0, 255);
+
+            d8uv[0] = (U_sum + 2) / 4;
+            d8uv++;
+            d8uv[0] = (V_sum + 2) / 4;
+            d8uv++;
+        }
+    }
+    return 0;
+}
+
 /******************************************************************************/
 /* copy rects with no error checking */
 static int
 rdpCopyBox_a8r8g8b8_to_nv12(rdpClientCon *clientCon,
-                            const uint8_t *src, int src_stride, int srcx, int srcy,
+                            const uint8_t *src, int src_stride,
+                            int srcx, int srcy,
                             uint8_t *dst_y, int dst_stride_y,
                             uint8_t *dst_uv, int dst_stride_uv,
                             int dstx, int dsty,
@@ -569,6 +667,44 @@ rdpCopyBox_a8r8g8b8_to_nv12(rdpClientCon *clientCon,
     return 0;
 }
 
+/******************************************************************************/
+/* copy rects with no error checking */
+static int
+rdpCopyBox_a8r8g8b8_to_nv12_709fr(rdpClientCon *clientCon,
+                                  const uint8_t *src, int src_stride,
+                                  int srcx, int srcy,
+                                  uint8_t *dst_y, int dst_stride_y,
+                                  uint8_t *dst_uv, int dst_stride_uv,
+                                  int dstx, int dsty,
+                                  BoxPtr rects, int num_rects)
+{
+    const uint8_t *s8;
+    uint8_t *d8_y;
+    uint8_t *d8_uv;
+    int index;
+    int width;
+    int height;
+    BoxPtr box;
+
+    for (index = 0; index < num_rects; index++)
+    {
+        box = rects + index;
+        s8 = src + (box->y1 - srcy) * src_stride;
+        s8 += (box->x1 - srcx) * 4;
+        d8_y = dst_y + (box->y1 - dsty) * dst_stride_y;
+        d8_y += (box->x1 - dstx) * 1;
+        d8_uv = dst_uv + ((box->y1 - dsty) / 2) * dst_stride_uv;
+        d8_uv += (box->x1 - dstx) * 1;
+        width = box->x2 - box->x1;
+        height = box->y2 - box->y1;
+        clientCon->dev->a8r8g8b8_to_nv12_709fr_box(s8, src_stride,
+                                                   d8_y, dst_stride_y,
+                                                   d8_uv, dst_stride_uv,
+                                                   width, height);
+    }
+    return 0;
+}
+
 /******************************************************************************/
 static Bool
 rdpCapture0(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
@@ -980,6 +1116,17 @@ rdpCapture3(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
                                         dst, dst_stride, 0, 0,
                                         *out_rects, num_rects);
     }
+    else if (dst_format == XRDP_nv12_709fr)
+    {
+        dst_uv = dst;
+        dst_uv += clientCon->cap_width * clientCon->cap_height;
+        rdpCopyBox_a8r8g8b8_to_nv12_709fr(clientCon,
+                                          src, src_stride, 0, 0,
+                                          dst, dst_stride,
+                                          dst_uv, dst_stride,
+                                          0, 0,
+                                          *out_rects, num_rects);
+    }
     else if (dst_format == XRDP_nv12)
     {
         dst_uv = dst;
@@ -1058,6 +1205,63 @@ copy_vmem(rdpPtr dev, RegionPtr in_reg)
 }
 #endif
 
+
+/******************************************************************************/
+static int
+copy_vmem_nvidia(rdpPtr dev, RegionPtr in_reg)
+{
+    PixmapPtr hwPixmap;
+    PixmapPtr swPixmap;
+    BoxPtr pbox;
+    ScreenPtr pScreen;
+    GCPtr copyGC;
+    ChangeGCVal tmpval[1];
+    int count;
+    int index;
+    int left;
+    int top;
+    int width;
+    int height;
+    char pix1[16];
+
+    /* copy the dirty area from the screen hw pixmap to a sw pixmap
+       this should do a dma */
+    pScreen = dev->pScreen;
+    hwPixmap = pScreen->GetScreenPixmap(pScreen);
+    swPixmap = dev->screenSwPixmap;
+    copyGC = GetScratchGC(dev->depth, pScreen);
+    if (copyGC != NULL)
+    {
+        tmpval[0].val = GXcopy;
+        ChangeGC(NullClient, copyGC, GCFunction, tmpval);
+        ValidateGC(&(hwPixmap->drawable), copyGC);
+        count = REGION_NUM_RECTS(in_reg);
+        pbox = REGION_RECTS(in_reg);
+        for (index = 0; index < count; index++)
+        {
+            left = pbox[index].x1;
+            top = pbox[index].y1;
+            width = pbox[index].x2 - pbox[index].x1;
+            height = pbox[index].y2 - pbox[index].y1;
+            if ((width > 0) && (height > 0))
+            {
+                copyGC->ops->CopyArea(&(hwPixmap->drawable),
+                                      &(swPixmap->drawable),
+                                      copyGC, left, top,
+                                      width, height, left, top);
+            }
+        }
+        FreeScratchGC(copyGC);
+    }
+    else
+    {
+        return 1;
+    }
+    pScreen->GetImage(&(swPixmap->drawable), 0, 0, 1, 1, ZPixmap,
+                      0xffffffff, pix1);
+    return 0;
+}
+
 /**
  * Copy an array of rectangles from one memory area to another
  *****************************************************************************/
@@ -1080,6 +1284,10 @@ rdpCapture(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
         copy_vmem(clientCon->dev, in_reg);
 #endif
     }
+    if (clientCon->dev->nvidia)
+    {
+        copy_vmem_nvidia(clientCon->dev, in_reg);
+    }
     switch (mode)
     {
         case 0:
diff --git a/module/rdpCapture.h b/module/rdpCapture.h
index 2696b00..97ae1d5 100644
--- a/module/rdpCapture.h
+++ b/module/rdpCapture.h
@@ -46,5 +46,10 @@ a8r8g8b8_to_nv12_box(const uint8_t *s8, int src_stride,
                      uint8_t *d8_y, int dst_stride_y,
                      uint8_t *d8_uv, int dst_stride_uv,
                      int width, int height);
+extern _X_EXPORT int
+a8r8g8b8_to_nv12_709fr_box(const uint8_t *s8, int src_stride,
+                           uint8_t *d8_y, int dst_stride_y,
+                           uint8_t *d8_uv, int dst_stride_uv,
+                           int width, int height);
 
 #endif
diff --git a/module/rdpDraw.h b/module/rdpDraw.h
index 7326380..0f5fad2 100644
--- a/module/rdpDraw.h
+++ b/module/rdpDraw.h
@@ -49,7 +49,8 @@ misc draw calls
     ) || \
     ( \
         ((_drw)->type == DRAWABLE_PIXMAP) && \
-        (((PixmapPtr)(_drw))->devPrivate.ptr == (_dev)->pfbMemory) \
+            (_drw)->pScreen->GetScreenPixmap((_drw)->pScreen) == \
+            (PixmapPtr)(_drw) \
     ) \
 )
 
diff --git a/module/rdpMain.c b/module/rdpMain.c
index 59b7e02..192cd70 100644
--- a/module/rdpMain.c
+++ b/module/rdpMain.c
@@ -41,12 +41,29 @@ rdp module main
 #include <fb.h>
 #include <micmap.h>
 #include <mi.h>
+#include <mipointrst.h>
+
+#include <xf86xv.h>
+#include <xf86Crtc.h>
 
 #include "rdp.h"
 #include "rdpInput.h"
 #include "rdpDraw.h"
 #include "rdpClientCon.h"
 #include "rdpMain.h"
+#include "rdpPri.h"
+#include "rdpPixmap.h"
+#include "rdpGC.h"
+#include "rdpMisc.h"
+#include "rdpComposite.h"
+#include "rdpGlyphs.h"
+#include "rdpTrapezoids.h"
+#include "rdpTriangles.h"
+#include "rdpCompositeRects.h"
+#include "rdpCursor.h"
+#include "rdpSimd.h"
+#include "rdpRandR.h"
+#include "rdpReg.h"
 
 /******************************************************************************/
 #define LOG_LEVEL 1
@@ -55,6 +72,384 @@ rdp module main
 
 static Bool g_initialised = FALSE;
 
+static Bool g_nvidia_wrap_done = FALSE;
+static DriverRec g_saved_driver;
+
+static xf86PreInitProc *g_orgPreInit = NULL;
+static xf86ScreenInitProc *g_orgScreenInit = NULL;
+
+static OsTimerPtr g_timer = NULL;
+
+extern DriverPtr *xf86DriverList;
+extern int xf86NumDrivers;
+
+/*****************************************************************************/
+static Bool
+xorgxrdpPreInit(ScrnInfoPtr pScrn, int flags)
+{
+    Bool rv;
+
+    LLOGLN(0, ("xorgxrdpPreInit:"));
+    rv = g_orgPreInit(pScrn, flags);
+    if (rv)
+    {
+        pScrn->reservedPtr[0] = xnfcalloc(sizeof(rdpRec), 1);
+    }
+    return rv;
+}
+
+/******************************************************************************/
+static miPointerSpriteFuncRec g_rdpSpritePointerFuncs =
+{
+    /* these are in rdpCursor.c */
+    rdpSpriteRealizeCursor,
+    rdpSpriteUnrealizeCursor,
+    rdpSpriteSetCursor,
+    rdpSpriteMoveCursor,
+    rdpSpriteDeviceCursorInitialize,
+    rdpSpriteDeviceCursorCleanup
+};
+
+/******************************************************************************/
+static void
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 5, 0, 0)
+rdpBlockHandler1(pointer blockData, OSTimePtr pTimeout, pointer pReadmask)
+#else
+rdpBlockHandler1(void *blockData, void *pTimeout)
+#endif
+{
+}
+
+/******************************************************************************/
+static void
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 5, 0, 0)
+rdpWakeupHandler1(pointer blockData, int result, pointer pReadmask)
+#else
+rdpWakeupHandler1(void *blockData, int result)
+#endif
+{
+    rdpClientConCheck((ScreenPtr)blockData);
+}
+
+/*****************************************************************************/
+static Bool
+rdpCreateScreenResources(ScreenPtr pScreen)
+{
+    Bool ret;
+    rdpPtr dev;
+
+    LLOGLN(0, ("rdpCreateScreenResources:"));
+    dev = rdpGetDevFromScreen(pScreen);
+    pScreen->CreateScreenResources = dev->CreateScreenResources;
+    ret = pScreen->CreateScreenResources(pScreen);
+    pScreen->CreateScreenResources = rdpCreateScreenResources;
+    if (!ret)
+    {
+        return FALSE;
+    }
+    dev->screenSwPixmap = pScreen->CreatePixmap(pScreen,
+                                                dev->width, dev->height,
+                                                dev->depth,
+                                                CREATE_PIXMAP_USAGE_SHARED);
+    dev->pfbMemory = dev->screenSwPixmap->devPrivate.ptr;
+    dev->paddedWidthInBytes = dev->screenSwPixmap->devKind;
+    dev->sizeInBytes = dev->paddedWidthInBytes * dev->height;
+    return TRUE;
+}
+
+/******************************************************************************/
+static Bool
+xorgxrdpRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height,
+                        CARD32 mmWidth, CARD32 mmHeight)
+{
+    Bool rv;
+    rdpPtr dev;
+    rrScrPrivPtr pRRScrPriv;
+
+    LLOGLN(0, ("xorgxrdpRRScreenSetSize: width %d height %d", width, height));
+    dev = rdpGetDevFromScreen(pScreen);
+
+    pRRScrPriv = rrGetScrPriv(pScreen);
+    pRRScrPriv->rrScreenSetSize = dev->rrScreenSetSize;
+    rv = pRRScrPriv->rrScreenSetSize(pScreen, width, height, mmWidth, mmHeight);
+    pRRScrPriv->rrScreenSetSize = xorgxrdpRRScreenSetSize;
+
+    dev->width = width;
+    dev->height = height;
+
+    pScreen->DestroyPixmap(dev->screenSwPixmap);
+    dev->screenSwPixmap = pScreen->CreatePixmap(pScreen,
+                                                dev->width, dev->height,
+                                                dev->depth,
+                                                CREATE_PIXMAP_USAGE_SHARED);
+    dev->pfbMemory = dev->screenSwPixmap->devPrivate.ptr;
+    dev->paddedWidthInBytes = dev->screenSwPixmap->devKind;
+    dev->sizeInBytes = dev->paddedWidthInBytes * dev->height;
+    return rv;
+}
+
+/*****************************************************************************/
+static void
+xorgxrdpDamageReport(DamagePtr pDamage, RegionPtr pRegion, void *closure)
+{
+    rdpPtr dev;
+    ScreenPtr pScreen;
+
+    LLOGLN(10, ("xorgxrdpDamageReport:"));
+    pScreen = (ScreenPtr)closure;
+    dev = rdpGetDevFromScreen(pScreen);
+    rdpClientConAddAllReg(dev, pRegion, &(pScreen->root->drawable));
+}
+
+/*****************************************************************************/
+static void
+xorgxrdpDamageDestroy(DamagePtr pDamage, void *closure)
+{
+    LLOGLN(0, ("xorgxrdpDamageDestroy:"));
+}
+
+/******************************************************************************/
+/* returns error */
+static CARD32
+xorgxrdpDeferredStartup(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+    rdpPtr dev;
+    ScreenPtr pScreen;
+
+    LLOGLN(0, ("xorgxrdpDeferredStartup:"));
+    pScreen = (ScreenPtr)arg;
+    if (pScreen->root != NULL)
+    {
+        dev = rdpGetDevFromScreen(pScreen);
+        dev->damage = DamageCreate(xorgxrdpDamageReport, xorgxrdpDamageDestroy,
+                                   DamageReportRawRegion, TRUE,
+                                   pScreen, pScreen);
+        if (dev->damage != NULL)
+        {
+            DamageSetReportAfterOp(dev->damage, TRUE);
+            DamageRegister(&(pScreen->root->drawable), dev->damage);
+            LLOGLN(0, ("xorgxrdpSetupDamage: DamageRegister ok"));
+            TimerFree(g_timer);
+            g_timer = NULL;
+            return 0;
+        }
+    }
+    g_timer = TimerSet(g_timer, 0, 100, xorgxrdpDeferredStartup, pScreen);
+    return 0;
+}
+
+/*****************************************************************************/
+static Bool
+xorgxrdpScreenInit(ScreenPtr pScreen, int argc, char** argv)
+{
+    Bool rv;
+    rdpPtr dev;
+    ScrnInfoPtr pScrn;
+    PictureScreenPtr ps;
+    miPointerScreenPtr PointPriv;
+    rrScrPrivPtr pRRScrPriv;
+
+    LLOGLN(0, ("xorgxrdpScreenInit:"));
+    rv = g_orgScreenInit(pScreen, argc, argv);
+    if (rv)
+    {
+        pScrn = xf86Screens[pScreen->myNum];
+        dev = XRDPPTR(pScrn);
+        dev->nvidia = TRUE;
+        dev->pScreen = pScreen;
+        dev->depth = pScrn->depth;
+        dev->width = pScrn->virtualX;
+        dev->height = pScrn->virtualY;
+        dev->paddedWidthInBytes = PixmapBytePad(dev->width, dev->depth);
+        dev->bitsPerPixel = rdpBitsPerPixel(dev->depth);
+        dev->sizeInBytes = dev->paddedWidthInBytes * dev->height;
+
+        LLOGLN(0, ("xorgxrdpScreenInit: width %d height %d", dev->width, dev->height));
+
+        PointPriv = dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
+        PointPriv->spriteFuncs = &g_rdpSpritePointerFuncs;
+
+        dev->privateKeyRecGC = rdpAllocateGCPrivate(pScreen, sizeof(rdpGCRec));
+        dev->privateKeyRecPixmap = rdpAllocatePixmapPrivate(pScreen, sizeof(rdpPixmapRec));
+
+        dev->CloseScreen = pScreen->CloseScreen;
+        pScreen->CloseScreen = rdpCloseScreen;
+
+        dev->CopyWindow = pScreen->CopyWindow;
+        pScreen->CopyWindow = rdpCopyWindow;
+
+        dev->CreateGC = pScreen->CreateGC;
+        pScreen->CreateGC = rdpCreateGC;
+
+        dev->CreatePixmap = pScreen->CreatePixmap;
+        pScreen->CreatePixmap = rdpCreatePixmap;
+
+        dev->DestroyPixmap = pScreen->DestroyPixmap;
+        pScreen->DestroyPixmap = rdpDestroyPixmap;
+
+        dev->ModifyPixmapHeader = pScreen->ModifyPixmapHeader;
+        pScreen->ModifyPixmapHeader = rdpModifyPixmapHeader;
+
+        ps = GetPictureScreenIfSet(pScreen);
+        if (ps != 0)
+        {
+            /* composite */
+            dev->Composite = ps->Composite;
+            ps->Composite = rdpComposite;
+            /* glyphs */
+            dev->Glyphs = ps->Glyphs;
+            ps->Glyphs = rdpGlyphs;
+            /* trapezoids */
+            dev->Trapezoids = ps->Trapezoids;
+            ps->Trapezoids = rdpTrapezoids;
+            /* triangles */
+            dev->Triangles = ps->Triangles;
+            ps->Triangles = rdpTriangles;
+            /* composite rects */
+            dev->CompositeRects = ps->CompositeRects;
+            ps->CompositeRects = rdpCompositeRects;
+        }
+
+        dev->CreateScreenResources = pScreen->CreateScreenResources;
+        pScreen->CreateScreenResources = rdpCreateScreenResources;
+
+        RegisterBlockAndWakeupHandlers(rdpBlockHandler1, rdpWakeupHandler1, pScreen);
+
+        if (rdpClientConInit(dev) != 0)
+        {
+            LLOGLN(0, ("xorgxrdpScreenInit: rdpClientConInit failed"));
+        }
+
+        dev->Bpp_mask = 0x00FFFFFF;
+        dev->Bpp = 4;
+        dev->bitsPerPixel = 32;
+
+        rdpSimdInit(pScreen, pScrn);
+
+        pRRScrPriv = rrGetScrPriv(pScreen);
+        if (pRRScrPriv != NULL)
+        {
+            dev->rrSetConfig          = pRRScrPriv->rrSetConfig;
+            dev->rrGetInfo            = pRRScrPriv->rrGetInfo;
+            dev->rrScreenSetSize      = pRRScrPriv->rrScreenSetSize;
+            dev->rrCrtcSet            = pRRScrPriv->rrCrtcSet;
+            dev->rrCrtcSetGamma       = pRRScrPriv->rrCrtcSetGamma;
+            dev->rrCrtcGetGamma       = pRRScrPriv->rrCrtcGetGamma;
+            dev->rrOutputSetProperty  = pRRScrPriv->rrOutputSetProperty;
+            dev->rrOutputValidateMode = pRRScrPriv->rrOutputValidateMode;
+            dev->rrModeDestroy        = pRRScrPriv->rrModeDestroy;
+            dev->rrOutputGetProperty  = pRRScrPriv->rrOutputGetProperty;
+            dev->rrGetPanning         = pRRScrPriv->rrGetPanning;
+            dev->rrSetPanning         = pRRScrPriv->rrSetPanning;
+            pRRScrPriv->rrScreenSetSize = xorgxrdpRRScreenSetSize;
+        }
+
+        g_timer = TimerSet(g_timer, 0, 100, xorgxrdpDeferredStartup, pScreen);
+
+    }
+    return rv;
+}
+
+/*****************************************************************************/
+static Bool
+xorgxrdpWrapPreIntScreenInit(Bool ok)
+{
+    if (ok && (g_orgPreInit == NULL))
+    {
+        if ((xf86Screens != NULL) && (xf86Screens[0] != NULL))
+        {
+            if ((xf86Screens[0]->PreInit != NULL) &&
+                (xf86Screens[0]->ScreenInit != NULL))
+            {
+                g_orgPreInit = xf86Screens[0]->PreInit;
+                xf86Screens[0]->PreInit = xorgxrdpPreInit;
+                g_orgScreenInit = xf86Screens[0]->ScreenInit;
+                xf86Screens[0]->ScreenInit = xorgxrdpScreenInit;
+            }
+            else
+            {
+                LLOGLN(0, ("xorgxrdpWrapPreIntScreenInit: error"));
+            }
+        }
+        else
+        {
+            LLOGLN(0, ("xorgxrdpWrapPreIntScreenInit: error"));
+        }
+    }
+    return ok;
+}
+
+/*****************************************************************************/
+static Bool
+xorgxrdpPciProbe(struct _DriverRec * drv, int entity_num,
+                 struct pci_device * dev, intptr_t match_data)
+{
+    Bool rv;
+
+    LLOGLN(0, ("xorgxrdpPciProbe:"));
+    rv = g_saved_driver.PciProbe(drv, entity_num, dev, match_data);
+    return xorgxrdpWrapPreIntScreenInit(rv);
+}
+
+/*****************************************************************************/
+static Bool
+xorgxrdpPlatformProbe(struct _DriverRec * drv, int entity_num, int flags,
+                      struct xf86_platform_device * dev, intptr_t match_data)
+{
+    Bool rv;
+
+    LLOGLN(0, ("xorgxrdpPlatformProbe:"));
+    rv = g_saved_driver.platformProbe(drv, entity_num, flags, dev, match_data);
+    return xorgxrdpWrapPreIntScreenInit(rv);
+}
+
+/*****************************************************************************/
+static Bool
+xorgxrdpDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
+{
+    xorgHWFlags *flags;
+    Bool rv;
+
+    LLOGLN(0, ("xorgxrdpDriverFunc:"));
+    rv = g_saved_driver.driverFunc(pScrn, op, ptr);
+    if (op == GET_REQUIRED_HW_INTERFACES)
+    {
+        flags = (xorgHWFlags *) ptr;
+        *flags = HW_SKIP_CONSOLE;
+        rv = TRUE;
+    }
+    return rv;
+}
+
+/*****************************************************************************/
+int
+xorgxrdpCheckWrap(void)
+{
+    if (g_nvidia_wrap_done)
+    {
+        return 0;
+    }
+    if (xf86NumDrivers < 1)
+    {
+        return 0;
+    }
+    if ((xf86DriverList == NULL) || (xf86DriverList[0] == NULL) ||
+        (xf86DriverList[0]->driverName == NULL))
+    {
+        return 0;
+    }
+    if (strcmp(xf86DriverList[0]->driverName, "NVIDIA") == 0)
+    {
+        g_saved_driver = *(xf86DriverList[0]);
+        g_nvidia_wrap_done = TRUE;
+        LLOGLN(0, ("xorgxrdpCheckWrap: NVIDIA driver found"));
+        xf86DriverList[0]->PciProbe = xorgxrdpPciProbe;
+        xf86DriverList[0]->platformProbe = xorgxrdpPlatformProbe;
+        xf86DriverList[0]->driverFunc = xorgxrdpDriverFunc;
+    }
+    return 0;
+}
+
 /*****************************************************************************/
 static pointer
 xorgxrdpSetup(pointer Module, pointer Options,
diff --git a/module/rdpMain.h b/module/rdpMain.h
index b351198..2a92a25 100644
--- a/module/rdpMain.h
+++ b/module/rdpMain.h
@@ -28,6 +28,8 @@ rdp module main
 #include <xorgVersion.h>
 #include <xf86.h>
 
+extern _X_EXPORT int
+xorgxrdpCheckWrap(void);
 extern _X_EXPORT void
 xorgxrdpDownDown(ScreenPtr pScreen);
 
diff --git a/module/rdpRandR.c b/module/rdpRandR.c
index f96da0a..d0ba85d 100644
--- a/module/rdpRandR.c
+++ b/module/rdpRandR.c
@@ -530,6 +530,10 @@ rdpRRSetRdpOutputs(rdpPtr dev)
     pRRScrPriv = rrGetScrPriv(dev->pScreen);
     LLOGLN(0, ("rdpRRSetRdpOutputs: numCrtcs %d numOutputs %d monitorCount %d",
            pRRScrPriv->numCrtcs, pRRScrPriv->numOutputs, dev->monitorCount));
+    if (dev->nvidia)
+    {
+        return 0;
+    }
     if (dev->monitorCount <= 0)
     {
         left = 0;
diff --git a/module/rdpSimd.c b/module/rdpSimd.c
index 49a3653..88f23fa 100644
--- a/module/rdpSimd.c
+++ b/module/rdpSimd.c
@@ -62,6 +62,126 @@ int g_simd_use_accel = 1;
 #define LLOGLN(_level, _args) \
     do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
 
+#if SIMD_USE_ACCEL
+#if defined(__x86_64__) || defined(__AMD64__) || defined (_M_AMD64)
+/******************************************************************************/
+static int
+a8r8g8b8_to_nv12_box_amd64_sse2_wrap(const uint8_t *s8, int src_stride,
+                                     uint8_t *d8_y, int dst_stride_y,
+                                     uint8_t *d8_uv, int dst_stride_uv,
+                                     int width, int height)
+{
+    int awidth;
+    int lwidth;
+
+    awidth = width & ~7;
+    lwidth = width - awidth;
+    if (awidth > 0)
+    {
+        a8r8g8b8_to_nv12_box_amd64_sse2(s8, src_stride,
+                                        d8_y, dst_stride_y,
+                                        d8_uv, dst_stride_uv,
+                                        awidth, height);
+    }
+    if (lwidth > 0)
+    {
+        a8r8g8b8_to_nv12_box(s8 + awidth * 4, src_stride,
+                             d8_y + awidth, dst_stride_y,
+                             d8_uv + awidth, dst_stride_uv,
+                             lwidth, height);
+    }
+    return 0;
+}
+
+/******************************************************************************/
+static int
+a8r8g8b8_to_nv12_709fr_box_amd64_sse2_wrap(const uint8_t *s8, int src_stride,
+                                           uint8_t *d8_y, int dst_stride_y,
+                                           uint8_t *d8_uv, int dst_stride_uv,
+                                           int width, int height)
+{
+    int awidth;
+    int lwidth;
+
+    awidth = width & ~7;
+    lwidth = width - awidth;
+    if (awidth > 0)
+    {
+        a8r8g8b8_to_nv12_709fr_box_amd64_sse2(s8, src_stride,
+                                              d8_y, dst_stride_y,
+                                              d8_uv, dst_stride_uv,
+                                              awidth, height);
+    }
+    if (lwidth > 0)
+    {
+        a8r8g8b8_to_nv12_709fr_box(s8 + awidth * 4, src_stride,
+                                   d8_y + awidth, dst_stride_y,
+                                   d8_uv + awidth, dst_stride_uv,
+                                   lwidth, height);
+    }
+    return 0;
+}
+#elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
+/******************************************************************************/
+static int
+a8r8g8b8_to_nv12_box_x86_sse2_wrap(const uint8_t *s8, int src_stride,
+                                   uint8_t *d8_y, int dst_stride_y,
+                                   uint8_t *d8_uv, int dst_stride_uv,
+                                   int width, int height)
+{
+    int awidth;
+    int lwidth;
+
+    awidth = width & ~7;
+    lwidth = width - awidth;
+    if (awidth > 0)
+    {
+        a8r8g8b8_to_nv12_box_x86_sse2(s8, src_stride,
+                                      d8_y, dst_stride_y,
+                                      d8_uv, dst_stride_uv,
+                                      awidth, height);
+    }
+    if (lwidth > 0)
+    {
+        a8r8g8b8_to_nv12_box(s8 + awidth * 4, src_stride,
+                             d8_y + awidth, dst_stride_y,
+                             d8_uv + awidth, dst_stride_uv,
+                             lwidth, height);
+    }
+    return 0;
+}
+
+/******************************************************************************/
+static int
+a8r8g8b8_to_nv12_709fr_box_x86_sse2_wrap(const uint8_t *s8, int src_stride,
+                                         uint8_t *d8_y, int dst_stride_y,
+                                         uint8_t *d8_uv, int dst_stride_uv,
+                                         int width, int height)
+{
+    int awidth;
+    int lwidth;
+
+    awidth = width & ~7;
+    lwidth = width - awidth;
+    if (awidth > 0)
+    {
+        a8r8g8b8_to_nv12_709fr_box_x86_sse2(s8, src_stride,
+                                            d8_y, dst_stride_y,
+                                            d8_uv, dst_stride_uv,
+                                            awidth, height);
+    }
+    if (lwidth > 0)
+    {
+        a8r8g8b8_to_nv12_709fr_box(s8 + awidth * 4, src_stride,
+                                   d8_y + awidth, dst_stride_y,
+                                   d8_uv + awidth, dst_stride_uv,
+                                   lwidth, height);
+    }
+    return 0;
+}
+#endif
+#endif
+
 /*****************************************************************************/
 Bool
 rdpSimdInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
@@ -77,6 +197,7 @@ rdpSimdInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
     dev->uyvy_to_rgb32 = UYVY_to_RGB32;
     dev->a8r8g8b8_to_a8b8g8r8_box = a8r8g8b8_to_a8b8g8r8_box;
     dev->a8r8g8b8_to_nv12_box = a8r8g8b8_to_nv12_box;
+    dev->a8r8g8b8_to_nv12_709fr_box = a8r8g8b8_to_nv12_709fr_box;
 #if SIMD_USE_ACCEL
     if (g_simd_use_accel)
     {
@@ -92,7 +213,8 @@ rdpSimdInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
             dev->yuy2_to_rgb32 = yuy2_to_rgb32_amd64_sse2;
             dev->uyvy_to_rgb32 = uyvy_to_rgb32_amd64_sse2;
             dev->a8r8g8b8_to_a8b8g8r8_box = a8r8g8b8_to_a8b8g8r8_box_amd64_sse2;
-            dev->a8r8g8b8_to_nv12_box = a8r8g8b8_to_nv12_box_amd64_sse2;
+            dev->a8r8g8b8_to_nv12_box = a8r8g8b8_to_nv12_box_amd64_sse2_wrap;
+            dev->a8r8g8b8_to_nv12_709fr_box = a8r8g8b8_to_nv12_709fr_box_amd64_sse2_wrap;
             LLOGLN(0, ("rdpSimdInit: sse2 amd64 yuv functions assigned"));
         }
 #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
@@ -107,7 +229,8 @@ rdpSimdInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
             dev->yuy2_to_rgb32 = yuy2_to_rgb32_x86_sse2;
             dev->uyvy_to_rgb32 = uyvy_to_rgb32_x86_sse2;
             dev->a8r8g8b8_to_a8b8g8r8_box = a8r8g8b8_to_a8b8g8r8_box_x86_sse2;
-            dev->a8r8g8b8_to_nv12_box = a8r8g8b8_to_nv12_box_x86_sse2;
+            dev->a8r8g8b8_to_nv12_box = a8r8g8b8_to_nv12_box_x86_sse2_wrap;
+            dev->a8r8g8b8_to_nv12_709fr_box = a8r8g8b8_to_nv12_709fr_box_x86_sse2_wrap;
             LLOGLN(0, ("rdpSimdInit: sse2 x86 yuv functions assigned"));
         }
 #endif
diff --git a/module/x86/Makefile.am b/module/x86/Makefile.am
index ed10686..b004e8a 100644
--- a/module/x86/Makefile.am
+++ b/module/x86/Makefile.am
@@ -3,6 +3,7 @@ NAFLAGS += -DASM_ARCH_I386
 ASMSOURCES = \
   a8r8g8b8_to_a8b8g8r8_box_x86_sse2.asm \
   a8r8g8b8_to_nv12_box_x86_sse2.asm \
+  a8r8g8b8_to_nv12_709fr_box_x86_sse2.asm \
   cpuid_x86.asm \
   i420_to_rgb32_x86_sse2.asm \
   uyvy_to_rgb32_x86_sse2.asm \
diff --git a/module/x86/a8r8g8b8_to_nv12_709fr_box_x86_sse2.asm b/module/x86/a8r8g8b8_to_nv12_709fr_box_x86_sse2.asm
new file mode 100644
index 0000000..262f1af
--- /dev/null
+++ b/module/x86/a8r8g8b8_to_nv12_709fr_box_x86_sse2.asm
@@ -0,0 +1,300 @@
+;
+;Copyright 2015 Jay Sorg
+;Copyright 2017 mirabilos
+;
+;Permission to use, copy, modify, distribute, and sell this software and its
+;documentation for any purpose is hereby granted without fee, provided that
+;the above copyright notice appear in all copies and that both that
+;copyright notice and this permission notice appear in supporting
+;documentation.
+;
+;The above copyright notice and this permission notice shall be included in
+;all copies or substantial portions of the Software.
+;
+;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+;OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+;AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+;CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+;
+;ARGB to NV12 709 full range
+;x86 SSE2
+;
+; notes
+;   address s8 should be aligned on 16 bytes, will be slower if not
+;   width should be multiple of 8 and > 0
+;   height should be even and > 0
+
+%include "common.asm"
+
+PREPARE_RODATA
+    cd255  times 4 dd 255
+
+    cw255  times 8 dw 255
+    cw128  times 8 dw 128
+    cw54   times 8 dw 54
+    cw183  times 8 dw 183
+    cw18   times 8 dw 18
+    cw29   times 8 dw 29
+    cw99   times 8 dw 99
+    cw116  times 8 dw 116
+    cw12   times 8 dw 12
+    cw2    times 8 dw 2
+
+%define LU1            [esp +  0] ; first line U, 8 bytes
+%define LV1            [esp +  8] ; first line V, 8 bytes
+%define LU2            [esp + 16] ; second line U, 8 bytes
+%define LV2            [esp + 24] ; second line V, 8 bytes
+
+%define LS8            [esp + 52] ; s8
+%define LSRC_STRIDE    [esp + 56] ; src_stride
+%define LD8_Y          [esp + 60] ; d8_y
+%define LDST_Y_STRIDE  [esp + 64] ; dst_stride_y
+%define LD8_UV         [esp + 68] ; d8_uv
+%define LDST_UV_STRIDE [esp + 72] ; dst_stride_uv
+%define LWIDTH         [esp + 76] ; width
+%define LHEIGHT        [esp + 80] ; height
+
+;int
+;a8r8g8b8_to_nv12_709fr_box_x86_sse2(const char *s8, int src_stride,
+;                                    char *d8_y, int dst_stride_y,
+;                                    char *d8_uv, int dst_stride_uv,
+;                                    int width, int height);
+PROC a8r8g8b8_to_nv12_709fr_box_x86_sse2
+    push ebx
+    RETRIEVE_RODATA
+    push esi
+    push edi
+    push ebp
+    sub esp, 32                ; local vars, 32 bytes
+
+    pxor xmm7, xmm7
+
+    mov ebp, LHEIGHT           ; ebp = height
+    shr ebp, 1                 ; doing 2 lines at a time
+
+row_loop1:
+    mov esi, LS8               ; s8
+    mov edi, LD8_Y             ; d8_y
+    mov edx, LD8_UV            ; d8_uv
+
+    mov ecx, LWIDTH            ; ecx = width
+    shr ecx, 3                 ; doing 8 pixels at a time
+
+loop1:
+    ; first line
+    movdqu xmm0, [esi]         ; 4 pixels, 16 bytes
+    movdqa xmm1, xmm0          ; blue
+    pand xmm1, [lsym(cd255)]   ; blue
+    movdqa xmm2, xmm0          ; green
+    psrld xmm2, 8              ; green
+    pand xmm2, [lsym(cd255)]   ; green
+    movdqa xmm3, xmm0          ; red
+    psrld xmm3, 16             ; red
+    pand xmm3, [lsym(cd255)]   ; red
+
+    movdqu xmm0, [esi + 16]    ; 4 pixels, 16 bytes
+    movdqa xmm4, xmm0          ; blue
+    pand xmm4, [lsym(cd255)]   ; blue
+    movdqa xmm5, xmm0          ; green
+    psrld xmm5, 8              ; green
+    pand xmm5, [lsym(cd255)]   ; green
+    movdqa xmm6, xmm0          ; red
+    psrld xmm6, 16             ; red
+    pand xmm6, [lsym(cd255)]   ; red
+
+    packssdw xmm1, xmm4        ; xmm1 = 8 blues
+    packssdw xmm2, xmm5        ; xmm2 = 8 greens
+    packssdw xmm3, xmm6        ; xmm3 = 8 reds
+
+    ; _Y = (( 66 * _R + 129 * _G +  25 * _B) >> 8) +  16;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw18)]
+    pmullw xmm5, [lsym(cw183)]
+    pmullw xmm6, [lsym(cw54)]
+    paddw xmm4, xmm5
+    paddw xmm4, xmm6
+    psrlw xmm4, 8
+    packuswb xmm4, xmm7
+    movq [edi], xmm4           ; out 8 bytes yyyyyyyy
+
+    ; _U = ((-38 * _R -  74 * _G + 112 * _B) >> 8) + 128;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw99)]
+    pmullw xmm6, [lsym(cw29)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LU1, xmm4             ; save for later
+
+    ; _V = ((112 * _R -  94 * _G -  18 * _B) >> 8) + 128;
+    movdqa xmm6, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm4, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw116)]
+    pmullw xmm6, [lsym(cw12)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LV1, xmm4             ; save for later
+
+    ; go down to second line
+    add esi, LSRC_STRIDE
+    add edi, LDST_Y_STRIDE
+
+    ; second line
+    movdqu xmm0, [esi]         ; 4 pixels, 16 bytes
+    movdqa xmm1, xmm0          ; blue
+    pand xmm1, [lsym(cd255)]   ; blue
+    movdqa xmm2, xmm0          ; green
+    psrld xmm2, 8              ; green
+    pand xmm2, [lsym(cd255)]   ; green
+    movdqa xmm3, xmm0          ; red
+    psrld xmm3, 16             ; red
+    pand xmm3, [lsym(cd255)]   ; red
+
+    movdqu xmm0, [esi + 16]    ; 4 pixels, 16 bytes
+    movdqa xmm4, xmm0          ; blue
+    pand xmm4, [lsym(cd255)]   ; blue
+    movdqa xmm5, xmm0          ; green
+    psrld xmm5, 8              ; green
+    pand xmm5, [lsym(cd255)]   ; green
+    movdqa xmm6, xmm0          ; red
+    psrld xmm6, 16             ; red
+    pand xmm6, [lsym(cd255)]   ; red
+
+    packssdw xmm1, xmm4        ; xmm1 = 8 blues
+    packssdw xmm2, xmm5        ; xmm2 = 8 greens
+    packssdw xmm3, xmm6        ; xmm3 = 8 reds
+
+    ; _Y = (( 66 * _R + 129 * _G +  25 * _B) >> 8) +  16;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw18)]
+    pmullw xmm5, [lsym(cw183)]
+    pmullw xmm6, [lsym(cw54)]
+    paddw xmm4, xmm5
+    paddw xmm4, xmm6
+    psrlw xmm4, 8
+    packuswb xmm4, xmm7
+    movq [edi], xmm4           ; out 8 bytes yyyyyyyy
+
+    ; _U = ((-38 * _R -  74 * _G + 112 * _B) >> 8) + 128;
+    movdqa xmm4, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm6, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw99)]
+    pmullw xmm6, [lsym(cw29)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LU2, xmm4             ; save for later
+
+    ; _V = ((112 * _R -  94 * _G -  18 * _B) >> 8) + 128;
+    movdqa xmm6, xmm1          ; blue
+    movdqa xmm5, xmm2          ; green
+    movdqa xmm4, xmm3          ; red
+    pmullw xmm4, [lsym(cw128)]
+    pmullw xmm5, [lsym(cw116)]
+    pmullw xmm6, [lsym(cw12)]
+    psubw xmm4, xmm5
+    psubw xmm4, xmm6
+    psraw xmm4, 8
+    paddw xmm4, [lsym(cw128)]
+    packuswb xmm4, xmm7
+    movq LV2, xmm4             ; save for later
+
+    ; uv add and divide(average)
+    movq mm1, LU1              ; u from first line
+    movq mm3, mm1
+    pand mm1, [lsym(cw255)]
+    psrlw mm3, 8
+    pand mm3, [lsym(cw255)]
+    paddw mm1, mm3             ; add
+    movq mm2, LU2              ; u from second line
+    movq mm3, mm2
+    pand mm2, [lsym(cw255)]
+    paddw mm1, mm2             ; add
+    psrlw mm3, 8
+    pand mm3, [lsym(cw255)]
+    paddw mm1, mm3             ; add
+    paddw mm1, [lsym(cw2)]     ; add 2
+    psrlw mm1, 2               ; div 4
+
+    movq mm2, LV1              ; v from first line
+    movq mm4, mm2
+    pand mm2, [lsym(cw255)]
+    psrlw mm4, 8
+    pand mm4, [lsym(cw255)]
+    paddw mm2, mm4             ; add
+    movq mm3, LV2              ; v from second line
+    movq mm4, mm3
+    pand mm3, [lsym(cw255)]
+    paddw mm2, mm3             ; add
+    psrlw mm4, 8
+    pand mm4, [lsym(cw255)]
+    paddw mm2, mm4             ; add
+    paddw mm2, [lsym(cw2)]     ; add 2
+    psrlw mm2, 2               ; div 4
+
+    packuswb mm1, mm1
+    packuswb mm2, mm2
+
+    punpcklbw mm1, mm2         ; uv
+    movq [edx], mm1            ; out 8 bytes uvuvuvuv
+
+    ; go up to first line
+    sub esi, LSRC_STRIDE
+    sub edi, LDST_Y_STRIDE
+
+    ; move right
+    lea esi, [esi + 32]
+    lea edi, [edi + 8]
+    lea edx, [edx + 8]
+
+    dec ecx
+    jnz loop1
+
+    ; update s8
+    mov eax, LS8               ; s8
+    add eax, LSRC_STRIDE       ; s8 += src_stride
+    add eax, LSRC_STRIDE       ; s8 += src_stride
+    mov LS8, eax
+
+    ; update d8_y
+    mov eax, LD8_Y             ; d8_y
+    add eax, LDST_Y_STRIDE     ; d8_y += dst_stride_y
+    add eax, LDST_Y_STRIDE     ; d8_y += dst_stride_y
+    mov LD8_Y, eax
+
+    ; update d8_uv
+    mov eax, LD8_UV            ; d8_uv
+    add eax, LDST_UV_STRIDE    ; d8_uv += dst_stride_uv
+    mov LD8_UV, eax
+
+    dec ebp
+    jnz row_loop1
+
+    mov eax, 0                 ; return value
+    add esp, 32                ; local vars, 32 bytes
+    pop ebp
+    pop edi
+    pop esi
+    pop ebx
+    ret
+END_OF_FILE
diff --git a/xrdpdev/Makefile.am b/xrdpdev/Makefile.am
index 6787c66..14fb14f 100644
--- a/xrdpdev/Makefile.am
+++ b/xrdpdev/Makefile.am
@@ -34,5 +34,5 @@ xrdpdev_drv_la_LIBADD =
 xrdpdevsysconfdir=$(sysconfdir)/X11/xrdp
 
 dist_xrdpdevsysconf_DATA = \
-  xorg.conf
+  xorg.conf xorg_nvidia.conf
 
diff --git a/xrdpdev/xorg_nvidia.conf b/xrdpdev/xorg_nvidia.conf
new file mode 100644
index 0000000..c8f4a4c
--- /dev/null
+++ b/xrdpdev/xorg_nvidia.conf
@@ -0,0 +1,40 @@
+Section "ServerLayout"
+  Identifier "layout"
+  Screen 0 "dGPU"
+  InputDevice "xrdpMouse" "CorePointer"
+  InputDevice "xrdpKeyboard" "CoreKeyboard"
+EndSection
+
+Section "ServerFlags"
+  Option "DontVTSwitch" "on"
+  Option "AutoAddDevices" "off"
+EndSection
+
+Section "Module"
+  Load "xorgxrdp"
+EndSection
+
+Section "InputDevice"
+  Identifier "xrdpKeyboard"
+  Driver "xrdpkeyb"
+EndSection
+
+Section "InputDevice"
+  Identifier "xrdpMouse"
+  Driver "xrdpmouse"
+EndSection
+
+Section "Screen"
+  Identifier "dGPU"
+  Device "dGPU"
+  Option "DPI" "96 x 96"
+EndSection
+
+Section "Device"
+  Identifier "dGPU"
+  Driver "nvidia"
+  Option "UseDisplayDevice" "none"
+  Option "ConnectToAcpid" "false"
+  BusID "PCI:2:0:0"
+EndSection
+
diff --git a/xrdpdev/xrdpdev.c b/xrdpdev/xrdpdev.c
index 2dcce60..6df80db 100644
--- a/xrdpdev/xrdpdev.c
+++ b/xrdpdev/xrdpdev.c
@@ -124,7 +124,7 @@ rdpAllocRec(ScrnInfoPtr pScrn)
         return TRUE;
     }
     /* xnfcalloc exits if alloc failed */
-    pScrn->driverPrivate = xnfcalloc(sizeof(rdpRec), 1);
+    pScrn->reservedPtr[0] = xnfcalloc(sizeof(rdpRec), 1);
     return TRUE;
 }
 
diff --git a/xrdpkeyb/rdpKeyboard.c b/xrdpkeyb/rdpKeyboard.c
index 4061b53..85add3e 100644
--- a/xrdpkeyb/rdpKeyboard.c
+++ b/xrdpkeyb/rdpKeyboard.c
@@ -52,6 +52,7 @@ xrdp keyboard module
 #include "rdpInput.h"
 #include "rdpDraw.h"
 #include "rdpMisc.h"
+#include "rdpMain.h"
 
 /******************************************************************************/
 #define LOG_LEVEL 1
@@ -789,6 +790,7 @@ rdpkeybPlug(pointer module, pointer options, int *errmaj, int *errmin)
 {
     LLOGLN(0, ("rdpkeybPlug:"));
     xf86AddInputDriver(&rdpkeyb, module, 0);
+    xorgxrdpCheckWrap();
     return module;
 }
 
