From b7f536964c772b5e6ca6a2221339cf712490b097 Mon Sep 17 00:00:00 2001
From: Steve Browne <swbrowne@gmail.com>
Date: Sat, 16 May 2015 07:31:49 -0400
Subject: [PATCH] Added a new API function vaCopySubSurfaceGLX.

Signed-off-by: Steve Browne <swbrowne@gmail.com>
---
 va/glx/va_backend_glx.h | 12 ++++++++++
 va/glx/va_glx.c         | 21 ++++++++++++++++++
 va/glx/va_glx.h         | 32 +++++++++++++++++++++++++++
 va/glx/va_glx_impl.c    | 59 ++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/va/glx/va_backend_glx.h b/va/glx/va_backend_glx.h
index d110485..14891f8 100644
--- a/va/glx/va_backend_glx.h
+++ b/va/glx/va_backend_glx.h
@@ -49,6 +49,18 @@ struct VADriverVTableGLX {
         VASurfaceID             surface,
         unsigned int            flags
     );
+
+    /* Optional: copy part of a VA surface to a VA/GLX surface */
+    VAStatus (*vaCopySubSurfaceGLX)(
+        struct VADriverContext *ctx,
+        void                   *gl_surface,
+        VASurfaceID             surface,
+        short                   src_x,
+        short                   src_y,
+        unsigned short          src_width,
+        unsigned short          src_height,
+        unsigned int            flags
+    );
 };
 
 #endif /* VA_BACKEND_GLX_H */
diff --git a/va/glx/va_glx.c b/va/glx/va_glx.c
index 25ef005..591600a 100644
--- a/va/glx/va_glx.c
+++ b/va/glx/va_glx.c
@@ -165,3 +165,24 @@ VAStatus vaCopySurfaceGLX(
     INVOKE(ctx, CopySurface, (ctx, gl_surface, surface, flags));
     return status;
 }
+
+// Copy part of a VA surface to a VA/GLX surface
+VAStatus vaCopySubSurfaceGLX(
+    VADisplay    dpy,
+    void        *gl_surface,
+    VASurfaceID  surface,
+    short src_x,
+    short src_y,
+    unsigned short src_width,
+    unsigned short src_height,
+    unsigned int flags
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, CopySubSurface, (ctx, gl_surface, surface, src_x, src_y, src_width, src_height, flags));
+    return status;
+}
diff --git a/va/glx/va_glx.h b/va/glx/va_glx.h
index 1a0624d..24500a8 100644
--- a/va/glx/va_glx.h
+++ b/va/glx/va_glx.h
@@ -102,6 +102,38 @@ VAStatus vaCopySurfaceGLX(
     unsigned int flags
 );
 
+/**
+ * Copy part of a VA surface to a VA/GLX surface
+ *
+ * This function will not return until the copy is completed. At this
+ * point, the underlying GL texture will contain the surface pixels
+ * in an RGB format defined by the user.
+ *
+ * The application shall maintain the live GLX context itself.
+ * Implementations are free to use glXGetCurrentContext() and
+ * glXGetCurrentDrawable() functions for internal purposes.
+ *
+ * @param[in]  dpy        the VA display
+ * @param[in]  gl_surface the VA/GLX destination surface
+ * @param[in]  surface    the VA source surface
+ * @param[in]  src_x      the x offset of the surface
+ * @param[in]  src_y      the y offset of the surface
+ * @param[in]  src_width  the width of the sub rect from the surface
+ * @param[in]  src_height the height of the sub rect from the surface
+ * @param[in]  flags      the PutSurface flags
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaCopySubSurfaceGLX(
+    VADisplay    dpy,
+    void        *gl_surface,
+    VASurfaceID  surface,
+    short src_x, /* upper left offset in surface */
+    short src_y,
+    unsigned short src_width,
+    unsigned short src_height,
+    unsigned int flags
+);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/va/glx/va_glx_impl.c b/va/glx/va_glx_impl.c
index c066582..1f0465a 100644
--- a/va/glx/va_glx_impl.c
+++ b/va/glx/va_glx_impl.c
@@ -858,6 +858,22 @@ vaCopySurfaceGLX_impl_driver(
     return VA_STATUS_SUCCESS;
 }
 
+static VAStatus
+vaCopySubSurfaceGLX_impl_driver(
+    VADriverContextP    ctx,
+    void               *gl_surface,
+    VASurfaceID         surface,
+    short src_x,
+    short src_y,
+    unsigned short src_width,
+    unsigned short src_height,
+    unsigned int        flags
+)
+{
+    INVOKE(ctx, CopySubSurface, (ctx, gl_surface, surface, src_x, src_y, src_width, src_height, flags));
+    return VA_STATUS_SUCCESS;
+}
+
 #undef INVOKE
 
 
@@ -946,6 +962,10 @@ associate_surface(
     VADriverContextP    ctx,
     VASurfaceGLXP       pSurfaceGLX,
     VASurfaceID         surface,
+    short               src_x,
+    short               src_y,
+    unsigned short      src_width,
+    unsigned short      src_height,
     unsigned int        flags
 )
 {
@@ -962,7 +982,7 @@ associate_surface(
         ctx,
         surface,
         (void *)pSurfaceGLX->pixmap,
-        0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
+        src_x, src_y, src_width, src_height,
         0, 0, pSurfaceGLX->width, pSurfaceGLX->height,
         NULL, 0,
         flags
@@ -1015,13 +1035,17 @@ copy_surface(
     VADriverContextP    ctx,
     VASurfaceGLXP       pSurfaceGLX,
     VASurfaceID         surface,
+    short               src_x,
+    short               src_y,
+    unsigned short      src_width,
+    unsigned short      src_height,
     unsigned int        flags
 )
 {
     VAStatus status;
 
     /* Associate VA surface */
-    status = associate_surface(ctx, pSurfaceGLX, surface, flags);
+    status = associate_surface(ctx, pSurfaceGLX, surface, src_x, src_y, src_width, src_height, flags);
     if (status != VA_STATUS_SUCCESS)
         return status;
 
@@ -1056,7 +1080,34 @@ vaCopySurfaceGLX_impl_libva(
     if (!gl_set_current_context(pSurfaceGLX->gl_context, &old_cs))
         return VA_STATUS_ERROR_OPERATION_FAILED;
 
-    status = copy_surface(ctx, pSurfaceGLX, surface, flags);
+    status = copy_surface(ctx, pSurfaceGLX, surface, 0, 0, pSurfaceGLX->width, pSurfaceGLX->height, flags);
+
+    gl_set_current_context(&old_cs, NULL);
+    return status;
+}
+
+static VAStatus
+vaCopySubSurfaceGLX_impl_libva(
+    VADriverContextP    ctx,
+    void               *gl_surface,
+    VASurfaceID         surface,
+    short               src_x,
+    short               src_y,
+    unsigned short      src_width,
+    unsigned short      src_height,
+    unsigned int        flags
+)
+{
+    VASurfaceGLXP pSurfaceGLX;
+    VAStatus status;
+    struct OpenGLContextState old_cs;
+
+    INIT_SURFACE(pSurfaceGLX, gl_surface);
+
+    if (!gl_set_current_context(pSurfaceGLX->gl_context, &old_cs))
+        return VA_STATUS_ERROR_OPERATION_FAILED;
+
+    status = copy_surface(ctx, pSurfaceGLX, surface, src_x, src_y, src_width, src_height, flags);
 
     gl_set_current_context(&old_cs, NULL);
     return status;
@@ -1083,11 +1134,13 @@ VAStatus va_glx_init_context(VADriverContextP ctx)
         vtable->vaCreateSurfaceGLX      = vaCreateSurfaceGLX_impl_driver;
         vtable->vaDestroySurfaceGLX     = vaDestroySurfaceGLX_impl_driver;
         vtable->vaCopySurfaceGLX        = vaCopySurfaceGLX_impl_driver;
+        vtable->vaCopySubSurfaceGLX     = vaCopySubSurfaceGLX_impl_driver;
     }
     else {
         vtable->vaCreateSurfaceGLX      = vaCreateSurfaceGLX_impl_libva;
         vtable->vaDestroySurfaceGLX     = vaDestroySurfaceGLX_impl_libva;
         vtable->vaCopySurfaceGLX        = vaCopySurfaceGLX_impl_libva;
+        vtable->vaCopySubSurfaceGLX     = vaCopySubSurfaceGLX_impl_libva;
 
         if (!glXQueryVersion(ctx->native_dpy, &glx_major, &glx_minor))
             return VA_STATUS_ERROR_UNIMPLEMENTED;
-- 
1.9.5.msysgit.0

