/** @file
 * VirtualBox OpenGL command pack/unpack header
 */

/*
 *
 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#ifndef ___VBox_HostService_VBoxOGLOp_h
#define ___VBox_HostService_VBoxOGLOp_h

#ifdef VBOX_OGL_GUEST_SIDE
/************************************************************************************************************
 * Guest side macro's for packing OpenGL function calls into the command buffer.                            *
 *                                                                                                          *
 ************************************************************************************************************/

#define VBOX_OGL_NAME_PREFIX(Function)                    gl##Function

#define OGL_CMD(op, numpar, size)                                                           \
    VBoxCmdStart(VBOX_OGL_OP_##op, numpar, size);

#define OGL_PARAM(val, size)                                                                \
    VBoxCmdSaveParameter((uint8_t *)&val, size);

#define OGL_MEMPARAM(ptr, size)                                                             \
    VBoxCmdSaveMemParameter((uint8_t *)ptr, size);

#define OGL_CMD_END(op)                                                                     \
    VBoxCmdStop(VBOX_OGL_OP_##op);


#define VBOX_OGL_GEN_OP(op)                                                                 \
    OGL_CMD(op, 0, 0);                                                                      \
    OGL_CMD_END(op);
    
#define VBOX_OGL_GEN_OP1(op, p1)                                                            \
    OGL_CMD(op, 1, sizeof(p1));                                                             \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP2(op, p1, p2)                                                        \
    OGL_CMD(op, 2, sizeof(p1)+sizeof(p2));                                                  \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP3(op, p1, p2, p3)                                                    \
    OGL_CMD(op, 3, sizeof(p1)+sizeof(p2)+sizeof(p3));                                       \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP4(op, p1, p2, p3, p4)                                                \
    OGL_CMD(op, 4, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4));                            \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_PARAM(p4, sizeof(p4));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP5(op, p1, p2, p3, p4, p5)                                            \
    OGL_CMD(op, 5, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5));                 \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_PARAM(p4, sizeof(p4));                                                              \
    OGL_PARAM(p5, sizeof(p5));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP6(op, p1, p2, p3, p4, p5, p6)                                        \
    OGL_CMD(op, 6, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6));      \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_PARAM(p4, sizeof(p4));                                                              \
    OGL_PARAM(p5, sizeof(p5));                                                              \
    OGL_PARAM(p6, sizeof(p6));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP7(op, p1, p2, p3, p4, p5, p6, p7)                                    \
    OGL_CMD(op, 7, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+sizeof(p7));    \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_PARAM(p4, sizeof(p4));                                                              \
    OGL_PARAM(p5, sizeof(p5));                                                              \
    OGL_PARAM(p6, sizeof(p6));                                                              \
    OGL_PARAM(p7, sizeof(p7));                                                              \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP8(op, p1, p2, p3, p4, p5, p6, p7, p8)                                \
    OGL_CMD(op, 8, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+sizeof(p7)+sizeof(p8));    \
    OGL_PARAM(p1, sizeof(p1));                                                              \
    OGL_PARAM(p2, sizeof(p2));                                                              \
    OGL_PARAM(p3, sizeof(p3));                                                              \
    OGL_PARAM(p4, sizeof(p4));                                                              \
    OGL_PARAM(p5, sizeof(p5));                                                              \
    OGL_PARAM(p6, sizeof(p6));                                                              \
    OGL_PARAM(p7, sizeof(p7));                                                              \
    OGL_PARAM(p8, sizeof(p8));                                                              \
    OGL_CMD_END(op);


/* last parameter is a memory block */
#define VBOX_OGL_GEN_OP1PTR(op, size, p1ptr)                                                        \
    OGL_CMD(op, 1, size);                                                                         \
    OGL_MEMPARAM(p1ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP2PTR(op, p1, size, p2ptr)                                                    \
    OGL_CMD(op, 2, sizeof(p1)+size);                                                              \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_MEMPARAM(p2ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP3PTR(op, p1, p2, size, p3ptr)                                                \
    OGL_CMD(op, 3, sizeof(p1)+sizeof(p2)+size);                                                   \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_MEMPARAM(p3ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP4PTR(op, p1, p2, p3, size, p4ptr)                                            \
    OGL_CMD(op, 4, sizeof(p1)+sizeof(p2)+sizeof(p3)+size);                                        \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_MEMPARAM(p4ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP5PTR(op, p1, p2, p3, p4, size, p5ptr)                                        \
    OGL_CMD(op, 5, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+size);                             \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_MEMPARAM(p5ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP6PTR(op, p1, p2, p3, p4, p5, size, p6ptr)                                    \
    OGL_CMD(op, 6, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+size);                  \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_PARAM(p5, sizeof(p5));                                                                     \
    OGL_MEMPARAM(p6ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP7PTR(op, p1, p2, p3, p4, p5, p6, size, p7ptr)                                \
    OGL_CMD(op, 7, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+size);       \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_PARAM(p5, sizeof(p5));                                                                     \
    OGL_PARAM(p6, sizeof(p6));                                                                     \
    OGL_MEMPARAM(p7ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP8PTR(op, p1, p2, p3, p4, p5, p6, p7, size, p8ptr)                            \
    OGL_CMD(op, 8, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+sizeof(p7)+size);       \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_PARAM(p5, sizeof(p5));                                                                     \
    OGL_PARAM(p6, sizeof(p6));                                                                     \
    OGL_PARAM(p7, sizeof(p7));                                                                     \
    OGL_MEMPARAM(p8ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP9PTR(op, p1, p2, p3, p4, p5, p6, p7, p8, size, p9ptr)                        \
    OGL_CMD(op, 9, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+sizeof(p7)+sizeof(p8)+size);       \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_PARAM(p5, sizeof(p5));                                                                     \
    OGL_PARAM(p6, sizeof(p6));                                                                     \
    OGL_PARAM(p7, sizeof(p7));                                                                     \
    OGL_PARAM(p8, sizeof(p8));                                                                     \
    OGL_MEMPARAM(p9ptr, size);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP10PTR(op, p1, p2, p3, p4, p5, p6, p7, p8, p9, size, p10ptr)                  \
    OGL_CMD(op, 10, sizeof(p1)+sizeof(p2)+sizeof(p3)+sizeof(p4)+sizeof(p5)+sizeof(p6)+sizeof(p7)+sizeof(p8)+sizeof(p9)+size);       \
    OGL_PARAM(p1, sizeof(p1));                                                                     \
    OGL_PARAM(p2, sizeof(p2));                                                                     \
    OGL_PARAM(p3, sizeof(p3));                                                                     \
    OGL_PARAM(p4, sizeof(p4));                                                                     \
    OGL_PARAM(p5, sizeof(p5));                                                                     \
    OGL_PARAM(p6, sizeof(p6));                                                                     \
    OGL_PARAM(p7, sizeof(p7));                                                                     \
    OGL_PARAM(p8, sizeof(p8));                                                                     \
    OGL_PARAM(p9, sizeof(p9));                                                                     \
    OGL_MEMPARAM(p10ptr, size);                                                                    \
    OGL_CMD_END(op);


/* two memory blocks */
#define VBOX_OGL_GEN_OP2PTRPTR(op, size1, p1ptr, size2, p2ptr)                                      \
    OGL_CMD(op, 2, size1+size2);                                                                    \
    OGL_MEMPARAM(p1ptr, size1);                                                                     \
    OGL_MEMPARAM(p2ptr, size2);                                                                     \
    OGL_CMD_END(op);

#define VBOX_OGL_GEN_OP3PTRPTR(op, p1, size2, p2ptr, size3, p3ptr)                                  \
    OGL_CMD(op, 3, sizeof(p1)+size2+size3);                                                         \
    OGL_PARAM(p1, sizeof(p1));                                                                      \
    OGL_MEMPARAM(p2ptr, size2);                                                                     \
    OGL_MEMPARAM(p3ptr, size3);                                                                     \
    OGL_CMD_END(op);

/* Note: sync operations always set the last error */
/* sync operation that returns a value */
#define VBOX_OGL_GEN_SYNC_OP_RET(rettype, op)                                                       \
    VBOX_OGL_GEN_OP(op)                                                                             \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP1_RET(rettype, op, p1)                                                  \
    VBOX_OGL_GEN_OP1(op, p1)                                                                        \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP2_RET(rettype, op, p1, p2)                                              \
    VBOX_OGL_GEN_OP2(op, p1, p2)                                                                    \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP3_RET(rettype, op, p1, p2, p3)                                          \
    VBOX_OGL_GEN_OP3(op, p1, p2, p3)                                                                \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP4_RET(rettype, op, p1, p2, p3, p4)                                      \
    VBOX_OGL_GEN_OP4(op, p1, p2, p3, p4)                                                            \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP5_RET(rettype, op, p1, p2, p3, p4, p5)                                  \
    VBOX_OGL_GEN_OP5(op, p1, p2, p3, p4, p5)                                                        \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP6_RET(rettype, op, p1, p2, p3, p4, p5, p6)                              \
    VBOX_OGL_GEN_OP6(op, p1, p2, p3, p4, p5, p6)                                                    \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP7_RET(rettype, op, p1, p2, p3, p4, p5, p6, p7)                          \
    VBOX_OGL_GEN_OP7(op, p1, p2, p3, p4, p5, p6, p7)                                                \
    rettype retval = (rettype)VBoxOGLFlush();


#define VBOX_OGL_GEN_SYNC_OP(op)                                                                    \
    VBOX_OGL_GEN_OP(op)                                                                             \
    VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP1(op, p1)                                                               \
    VBOX_OGL_GEN_OP1(op, p1)                                                                        \
    VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP2(op, p1, p2)                                                           \
    VBOX_OGL_GEN_OP2(op, p1, p2)                                                                    \
    VBoxOGLFlush();


/* Sync operation whose last parameter is a block of memory */
#define VBOX_OGL_GEN_SYNC_OP2_PTR(op, p1, size, p2ptr)                                              \
    VBOX_OGL_GEN_OP2PTR(op, p1, size, p2ptr);                                                       \
    VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP5_PTR(op, p1, p2, p3, p4, size, p5ptr)                                  \
    VBOX_OGL_GEN_OP2PTR(op, p1, p2, p3, p4, size, p5ptr);                                           \
    VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP6_PTR(op, p1, p2, p3, p4, p5, size, p6ptr)                              \
    VBOX_OGL_GEN_OP6PTR(op, p1, p2, p3, p4, p5, size, p6ptr);                                       \
    VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP7_PTR(op, p1, p2, p3, p4, p5, p6, size, p7ptr)                          \
    VBOX_OGL_GEN_OP7PTR(op, p1, p2, p3, p4, p5, p6, size, p7ptr);                                   \
    VBoxOGLFlush();

/* Sync operation whose last parameter is a block of memory in which results are returned */
#define VBOX_OGL_GEN_SYNC_OP1_PASS_PTR(op, size, p1ptr)                                             \
    VBOX_OGL_GEN_OP(op);                                                                            \
    VBoxOGLFlushPtr(p1ptr, size);

#define VBOX_OGL_GEN_SYNC_OP2_PASS_PTR(op, p1, size, p2ptr)                                         \
    VBOX_OGL_GEN_OP1(op, p1);                                                                       \
    VBoxOGLFlushPtr(p2ptr, size);

#define VBOX_OGL_GEN_SYNC_OP3_PASS_PTR(op, p1, p2, size, p3ptr)                                     \
    VBOX_OGL_GEN_OP2(op, p1, p2);                                                                   \
    VBoxOGLFlushPtr(p3ptr, size);

#define VBOX_OGL_GEN_SYNC_OP4_PASS_PTR(op, p1, p2, p3, size, p4ptr)                                 \
    VBOX_OGL_GEN_OP3(op, p1, p2, p3);                                                               \
    VBoxOGLFlushPtr(p4ptr, size);

#define VBOX_OGL_GEN_SYNC_OP5_PASS_PTR(op, p1, p2, p3, p4, size, p5ptr)                             \
    VBOX_OGL_GEN_OP4(op, p1, p2, p3, p4);                                                           \
    VBoxOGLFlushPtr(p5ptr, size);

#define VBOX_OGL_GEN_SYNC_OP6_PASS_PTR(op, p1, p2, p3, p4, p5, size, p6ptr)                         \
    VBOX_OGL_GEN_OP5(op, p1, p2, p3, p4, p5);                                                       \
    VBoxOGLFlushPtr(p6ptr, size);

#define VBOX_OGL_GEN_SYNC_OP7_PASS_PTR(op, p1, p2, p3, p4, p5, p6, size, p7ptr)                     \
    VBOX_OGL_GEN_OP6(op, p1, p2, p3, p4, p5, p6);                                                   \
    VBoxOGLFlushPtr(p7ptr, size);


/* Sync operation whose last parameter is a block of memory and return a value */
#define VBOX_OGL_GEN_SYNC_OP2_PTR_RET(rettype, op, p1, size, p2ptr)                                 \
    VBOX_OGL_GEN_OP2PTR(op, p1, size, p2ptr);                                                       \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP4_PTR_RET(rettype, op, p1, p2, p3, size, p4ptr)                         \
    VBOX_OGL_GEN_OP4PTR(op, p1, p2, p3, size, p4ptr);                                               \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP5_PTR_RET(rettype, op, p1, p2, p3, p4, size, p5ptr)                     \
    VBOX_OGL_GEN_OP5PTR(op, p1, p2, p3, p4, size, p5ptr);                                           \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP6_PTR_RET(rettype, op, p1, p2, p3, p4, p5, size, p6ptr)                 \
    VBOX_OGL_GEN_OP6PTR(op, p1, p2, p3, p4, p5, size, p6ptr);                                       \
    rettype retval = (rettype)VBoxOGLFlush();

#define VBOX_OGL_GEN_SYNC_OP7_PTR_RET(rettype, op, p1, p2, p3, p4, p5, p6, size, p7ptr)             \
    VBOX_OGL_GEN_OP7PTR(op, p1, p2, p3, p4, p5, p6, size, p7ptr);                                   \
    rettype retval = (rettype)VBoxOGLFlush();


/* Sync operation whose last parameter is a block of memory in which results are returned and return a value */
#define VBOX_OGL_GEN_SYNC_OP2_PASS_PTR_RET(rettype, op, p1, size, p2ptr)                            \
    VBOX_OGL_GEN_OP1(op, p1);                                                                       \
    rettype retval = (rettype)VBoxOGLFlushPtr(p2ptr, size);

#define VBOX_OGL_GEN_SYNC_OP4_PASS_PTR_RET(rettype, op, p1, p2, p3, size, p4ptr)                    \
    VBOX_OGL_GEN_OP3(op, p1, p2, p3);                                                               \
    rettype retval = (rettype)VBoxOGLFlushPtr(p4ptr, size);

#define VBOX_OGL_GEN_SYNC_OP5_PASS_PTR_RET(rettype, op, p1, p2, p3, p4, size, p5ptr)                \
    VBOX_OGL_GEN_OP4(op, p1, p2, p3, p4);                                                           \
    rettype retval = (rettype)VBoxOGLFlushPtr(p5ptr, size);

#define VBOX_OGL_GEN_SYNC_OP6_PASS_PTR_RET(rettype, op, p1, p2, p3, p4, p5, size, p6ptr)            \
    VBOX_OGL_GEN_OP5(op, p1, p2, p3, p4, p5);                                                       \
    rettype retval = (rettype)VBoxOGLFlushPtr(p6ptr, size);

#define VBOX_OGL_GEN_SYNC_OP7_PASS_PTR_RET(rettype, op, p1, p2, p3, p4, p5, p6, size, p7ptr)        \
    VBOX_OGL_GEN_OP6(op, p1, p2, p3, p4, p5, p6);                                                   \
    rettype retval = (rettype)VBoxOGLFlushPtr(p7ptr, size);


/* Generate async functions elements in the command queue */
#define GL_GEN_FUNC(Function)                                                       \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (void)                                               \
    {                                                                               \
        VBOX_OGL_GEN_OP(Function);                                                  \
    }

#define GL_GEN_FUNC1(Function, Type)                                                \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a)                                             \
    {                                                                               \
        VBOX_OGL_GEN_OP1(Function, a);                                              \
    }

#define GL_GEN_FUNC1V(Function, Type)                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a)                                             \
    {                                                                               \
        VBOX_OGL_GEN_OP1(Function, a);                                              \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (const Type *v)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP1(Function, v[0]);                                           \
    }                                                                               \

#define GL_GEN_FUNC2(Function, Type)                                                \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b)                                     \
    {                                                                               \
        VBOX_OGL_GEN_OP2(Function, a, b);                                           \
    }

#define GL_GEN_FUNC2V(Function, Type)                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b)                                     \
    {                                                                               \
        VBOX_OGL_GEN_OP2(Function, a, b);                                           \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (const Type *v)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP2(Function, v[0], v[1]);                                     \
    }                                                                               \

#define GL_GEN_FUNC3(Function, Type)                                                \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b, Type c)                             \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, b, c);                                        \
    }

#define GL_GEN_FUNC3V(Function, Type)                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b, Type c)                             \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, b, c);                                        \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (const Type *v)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, v[0], v[1], v[2]);                               \
    }                                                                               \

#define GL_GEN_FUNC4(Function, Type)                                                \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b, Type c, Type d)                     \
    {                                                                               \
        VBOX_OGL_GEN_OP4(Function, a, b, c, d);                                     \
    }

#define GL_GEN_FUNC4V(Function, Type)                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b, Type c, Type d)                     \
    {                                                                               \
        VBOX_OGL_GEN_OP4(Function, a, b, c, d);                                     \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (const Type *v)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP4(Function, v[0], v[1], v[2], v[3]);                         \
    }                                                                               \

#define GL_GEN_FUNC6(Function, Type)                                                \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type a, Type b, Type c, Type d, Type e, Type f)     \
    {                                                                               \
        VBOX_OGL_GEN_OP6(Function, a, b, c, d, e, f);                               \
    }

#define GL_GEN_VPAR_FUNC2(Function, Type1, Type2)                                   \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP2(Function, a, b);                                           \
    }

#define GL_GEN_VPAR_FUNC2V(Function, Type1, Type2)                                  \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b)                                   \
    {                                                                               \
        VBOX_OGL_GEN_OP2(Function, a, b);                                           \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (Type1 a, const Type2 *v)                         \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, v[0], v[1]);                                  \
    }                                                                               \

#define GL_GEN_VPAR_FUNC3(Function, Type1, Type2, Type3)                            \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c)                          \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, b, c);                                        \
    }

#define GL_GEN_VPAR_FUNC3V(Function, Type1, Type2, Type3)                           \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c)                          \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, b, c);                                        \
    }                                                                               \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function)##v (Type1 a, Type2 b, const Type3 *v)                \
    {                                                                               \
        VBOX_OGL_GEN_OP3(Function, a, v[0], v[1]);                                  \
    }                                                                               \

#define GL_GEN_VPAR_FUNC4(Function, Type1, Type2, Type3, Type4)                     \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d)                 \
    {                                                                               \
        VBOX_OGL_GEN_OP4(Function, a, b, c, d);                                     \
    }

#define GL_GEN_VPAR_FUNC5(Function, Type1, Type2, Type3, Type4, Type5)              \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d, Type5 e)        \
    {                                                                               \
        VBOX_OGL_GEN_OP5(Function, a, b, c, d, e);                                  \
    }

#define GL_GEN_VPAR_FUNC6(Function, Type1, Type2, Type3, Type4, Type5, Type6)       \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d, Type5 e, Type6 f)        \
    {                                                                               \
        VBOX_OGL_GEN_OP6(Function, a, b, c, d, e, f);                               \
    }

#define GL_GEN_VPAR_FUNC7(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7)       \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d, Type5 e, Type6 f, Type7 g)        \
    {                                                                               \
        VBOX_OGL_GEN_OP7(Function, a, b, c, d, e, f, g);                               \
    }

#define GL_GEN_VPAR_FUNC8(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8)       \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d, Type5 e, Type6 f, Type7 g, Type8 h)        \
    {                                                                               \
        VBOX_OGL_GEN_OP8(Function, a, b, c, d, e, f, g, h);                               \
    }

#define GL_GEN_VPAR_FUNC9(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8 ,Type9)       \
    void APIENTRY VBOX_OGL_NAME_PREFIX(Function) (Type1 a, Type2 b, Type3 c, Type4 d, Type5 e, Type6 f, Type7 g, Type8 h, Type9 i)        \
    {                                                                               \
        VBOX_OGL_GEN_OP9(Function, a, b, c, d, e, f, g, h, i);                               \
    }

#elif VBOX_OGL_HOST_SIDE

/************************************************************************************************************
 * Host side macro's for generating OpenGL function calls from the packed commands in the command buffer.   *
 *                                                                                                          *
 ************************************************************************************************************/

#include <iprt/assert.h>

#define VBOX_OGL_NAME_PREFIX(Function)                    vboxgl##Function

#ifdef VBOX_OGL_CMD_STRICT
#define VBOX_OGL_CHECK_MAGIC(pParVal)                       Assert(pParVal->Magic == VBOX_OGL_CMD_MAGIC)
#else
#define VBOX_OGL_CHECK_MAGIC(pParVal)
#endif

#define OGL_CMD(op, numpar)                                                                 \
    PVBOX_OGL_CMD pCmd = (PVBOX_OGL_CMD)pCmdBuffer;                                         \
    Assert(pCmd->enmOp == VBOX_OGL_OP_##op);                                                \
    Assert(pCmd->cParams == numpar);                                                        \
    uint8_t      *pParam = (uint8_t *)(pCmd+1);                                             \
    NOREF(pParam)

#define OGL_PARAM(Type, par)                                                                \
    Type         par;                                                                       \
    par = *(Type *)pParam;                                                                  \
    pParam += sizeof(par);                                                                  \
    pParam = RT_ALIGN_PT(pParam, VBOX_OGL_CMD_ALIGN, uint8_t *);

#define OGL_MEMPARAM(Type, par)                                                             \
    PVBOX_OGL_VAR_PARAM pParVal = (PVBOX_OGL_VAR_PARAM)pParam;                              \
    Type        *par;                                                                       \
    VBOX_OGL_CHECK_MAGIC(pParVal);                                                          \
    if (pParVal->cbParam)                                                                   \
        par = (Type *)(pParVal+1);                                                          \
    else                                                                                    \
        par = NULL;                                                                         \
    pParam += sizeof(*pParVal) + pParVal->cbParam;                                          \
    pParam = RT_ALIGN_PT(pParam, VBOX_OGL_CMD_ALIGN, uint8_t *);

#define OGL_MEMPARAM_NODEF(Type, par)                                                       \
    pParVal = (PVBOX_OGL_VAR_PARAM)pParam;                                                  \
    Type        *par;                                                                       \
    VBOX_OGL_CHECK_MAGIC(pParVal);                                                          \
    if (pParVal->cbParam)                                                                   \
        par = (Type *)(pParVal+1);                                                          \
    else                                                                                    \
        par = NULL;                                                                         \
    pParam += sizeof(*pParVal) + pParVal->cbParam;                                          \
    pParam = RT_ALIGN_PT(pParam, VBOX_OGL_CMD_ALIGN, uint8_t *);

#define VBOX_OGL_GEN_OP(op)                                                                 \
    OGL_CMD(op, 0);                                                                         \
    gl##op();
    
#define VBOX_OGL_GEN_OP1(op, Type1)                                                         \
    OGL_CMD(op, 1);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    gl##op(p1);

#define VBOX_OGL_GEN_OP2(op, Type1, Type2)                                                  \
    OGL_CMD(op, 2);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    gl##op(p1, p2);

#define VBOX_OGL_GEN_OP3(op, Type1, Type2, Type3)                                           \
    OGL_CMD(op, 3);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    gl##op(p1, p2, p3);

#define VBOX_OGL_GEN_OP4(op, Type1, Type2, Type3, Type4)                                    \
    OGL_CMD(op, 4);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    OGL_PARAM(Type4, p4);                                                                   \
    gl##op(p1, p2, p3, p4);

#define VBOX_OGL_GEN_OP5(op, Type1, Type2, Type3, Type4, Type5)                             \
    OGL_CMD(op, 5);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    OGL_PARAM(Type4, p4);                                                                   \
    OGL_PARAM(Type5, p5);                                                                   \
    gl##op(p1, p2, p3, p4, p5);

#define VBOX_OGL_GEN_OP6(op, Type1, Type2, Type3, Type4, Type5, Type6)                      \
    OGL_CMD(op, 6);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    OGL_PARAM(Type4, p4);                                                                   \
    OGL_PARAM(Type5, p5);                                                                   \
    OGL_PARAM(Type6, p6);                                                                   \
    gl##op(p1, p2, p3, p4, p5, p6);

#define VBOX_OGL_GEN_OP7(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7)               \
    OGL_CMD(op, 7);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    OGL_PARAM(Type4, p4);                                                                   \
    OGL_PARAM(Type5, p5);                                                                   \
    OGL_PARAM(Type6, p6);                                                                   \
    OGL_PARAM(Type7, p7);                                                                   \
    gl##op(p1, p2, p3, p4, p5, p6, p7);

#define VBOX_OGL_GEN_OP8(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8)        \
    OGL_CMD(op, 8);                                                                         \
    OGL_PARAM(Type1, p1);                                                                   \
    OGL_PARAM(Type2, p2);                                                                   \
    OGL_PARAM(Type3, p3);                                                                   \
    OGL_PARAM(Type4, p4);                                                                   \
    OGL_PARAM(Type5, p5);                                                                   \
    OGL_PARAM(Type6, p6);                                                                   \
    OGL_PARAM(Type7, p7);                                                                   \
    OGL_PARAM(Type8, p8);                                                                   \
    gl##op(p1, p2, p3, p4, p5, p6, p7, p8);


/* last parameter is a memory block */
#define VBOX_OGL_GEN_OP1PTR(op, Type1)                                                          \
    OGL_CMD(op, 1);                                                                             \
    OGL_MEMPARAM(Type1, p1);                                                                        \
    gl##op(p1);

#define VBOX_OGL_GEN_OP2PTR(op, Type1, Type2)                                                   \
    OGL_CMD(op, 2);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_MEMPARAM(Type2, p2);                                                                        \
    gl##op(p1, p2);

#define VBOX_OGL_GEN_OP3PTR(op, Type1, Type2, Type3)                                            \
    OGL_CMD(op, 3);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_MEMPARAM(Type3, p3);                                                                        \
    gl##op(p1, p2, p3);

#define VBOX_OGL_GEN_OP4PTR(op, Type1, Type2, Type3, Type4)                                     \
    OGL_CMD(op, 4);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_MEMPARAM(Type4, p4);                                                                        \
    gl##op(p1, p2, p3, p4);

#define VBOX_OGL_GEN_OP5PTR(op, Type1, Type2, Type3, Type4, Type5)                              \
    OGL_CMD(op, 5);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_MEMPARAM(Type5, p5);                                                                        \
    gl##op(p1, p2, p3, p4, p5);

#define VBOX_OGL_GEN_OP6PTR(op, Type1, Type2, Type3, Type4, Type5, Type6)                       \
    OGL_CMD(op, 6);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_PARAM(Type5, p5);                                                                       \
    OGL_MEMPARAM(Type6, p6);                                                                        \
    gl##op(p1, p2, p3, p4, p5, p6);

#define VBOX_OGL_GEN_OP7PTR(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7)                \
    OGL_CMD(op, 7);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_PARAM(Type5, p5);                                                                       \
    OGL_PARAM(Type6, p6);                                                                       \
    OGL_MEMPARAM(Type7, p7);                                                                        \
    gl##op(p1, p2, p3, p4, p5, p6, p7);

#define VBOX_OGL_GEN_OP8PTR(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8)         \
    OGL_CMD(op, 8);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_PARAM(Type5, p5);                                                                       \
    OGL_PARAM(Type6, p6);                                                                       \
    OGL_PARAM(Type7, p7);                                                                       \
    OGL_MEMPARAM(Type8, p8);                                                                        \
    gl##op(p1, p2, p3, p4, p5, p6, p7, p8);

#define VBOX_OGL_GEN_OP9PTR(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9)  \
    OGL_CMD(op, 9);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_PARAM(Type5, p5);                                                                       \
    OGL_PARAM(Type6, p6);                                                                       \
    OGL_PARAM(Type7, p7);                                                                       \
    OGL_PARAM(Type8, p8);                                                                       \
    OGL_MEMPARAM(Type9, p9);                                                                        \
    gl##op(p1, p2, p3, p4, p5, p6, p7, p8 ,p9);

#define VBOX_OGL_GEN_OP10PTR(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, Type10)                  \
    OGL_CMD(op, 10);                                                                            \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_PARAM(Type3, p3);                                                                       \
    OGL_PARAM(Type4, p4);                                                                       \
    OGL_PARAM(Type5, p5);                                                                       \
    OGL_PARAM(Type6, p6);                                                                       \
    OGL_PARAM(Type7, p7);                                                                       \
    OGL_PARAM(Type8, p8);                                                                       \
    OGL_PARAM(Type9, p9);                                                                       \
    OGL_MEMPARAM(Type10, p10);                                                                       \
    gl##op(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);


/* two memory blocks */
#define VBOX_OGL_GEN_OP2PTRPTR(op, Type1, Type2)                                                \
    OGL_CMD(op, 2);                                                                             \
    OGL_MEMPARAM(Type1, p1);                                                                        \
    OGL_MEMPARAM_NODEF(Type2, p2);                                                                        \
    gl##op(p1, p2);

#define VBOX_OGL_GEN_OP3PTRPTR(op, Type1, Type2, Type3)                                         \
    OGL_CMD(op, 3);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_MEMPARAM(Type2, p2);                                                                        \
    OGL_MEMPARAM_NODEF(Type3, p3);                                                                        \
    gl##op(p1, p2, p3);

/* Note: sync operations always set the last error */
/* sync operation that returns a value */
#define VBOX_OGL_GEN_SYNC_OP_RET(rettype, op)                                                   \
    OGL_CMD(op, 0);                                                                             \
    pClient->lastretval = gl##op();

#define VBOX_OGL_GEN_SYNC_OP1_RET(rettype, op, Type1)                                              \
    OGL_CMD(op, 1);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    pClient->lastretval = gl##op(p1);
    
#define VBOX_OGL_GEN_SYNC_OP2_RET(rettype, op, Type1, Type2)                                          \
    OGL_CMD(op, 2);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    pClient->lastretval = gl##op(p1, p2);

#define VBOX_OGL_GEN_SYNC_OP3_RET(rettype, op, Type1, Type2, Type3)                                          \
    OGL_CMD(op, 3);                                                                             \
    OGL_PARAM(Type1, p1);                                                                       \
    OGL_PARAM(Type2, p2);                                                                       \
    OGL_MEMPARAM(Type3, p3);                                                                        \
    pClient->lastretval = gl##op(p1, p2, p3);

#define VBOX_OGL_GEN_SYNC_OP(op)                                                                    \
    VBOX_OGL_GEN_OP(op);

#define VBOX_OGL_GEN_SYNC_OP1(op, p1)                                                               \
    VBOX_OGL_GEN_OP1(op, p1);

#define VBOX_OGL_GEN_SYNC_OP2(op, p1, p2)                                                           \
    VBOX_OGL_GEN_OP2(op, p1, p2);


/* Sync operation whose last parameter is a block of memory */
#define VBOX_OGL_GEN_SYNC_OP2_PTR(op, p1, p2ptr)                                                    \
    VBOX_OGL_GEN_OP2PTR(op, p1, p2ptr);

#define VBOX_OGL_GEN_SYNC_OP5_PTR(op, p1, p2, p3, p4, p5ptr)                                        \
    VBOX_OGL_GEN_OP2PTR(op, p1, p2, p3, p4, size, p5ptr);

#define VBOX_OGL_GEN_SYNC_OP6_PTR(op, p1, p2, p3, p4, p5, p6ptr)                                    \
    VBOX_OGL_GEN_OP6PTR(op, p1, p2, p3, p4, p5, size, p6ptr);

#define VBOX_OGL_GEN_SYNC_OP7_PTR(op, p1, p2, p3, p4, p5, p6, p7ptr)                                \
    VBOX_OGL_GEN_OP7PTR(op, p1, p2, p3, p4, p5, p6, p7ptr);


/* Sync operation whose last parameter is a block of memory in which results are returned */
#define VBOX_OGL_GEN_SYNC_OP1_PASS_PTR(op, Type1)                                                   \
    OGL_CMD(op, 0);                                                                                 \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op((Type1 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP2_PASS_PTR(op, Type1, Type2)                                            \
    OGL_CMD(op, 1);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, (Type2 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP3_PASS_PTR(op, Type1, Type2, Type3)                                     \
    OGL_CMD(op, 2);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, p2, (Type3 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP4_PASS_PTR(op, Type1, Type2, Type3, Type4)                              \
    OGL_CMD(op, 3);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, p2, p3, (Type4 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP5_PASS_PTR(op, Type1, Type2, Type3, Type4, Type5)                       \
    OGL_CMD(op, 4);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, p2, p3, p4, (Type5 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP6_PASS_PTR(op, Type1, Type2, Type3, Type4, Type5, Type6)                \
    OGL_CMD(op, 5);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    OGL_PARAM(Type5, p5);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, p2, p3, p4, p5, (Type6 *)pClient->pLastParam);

#define VBOX_OGL_GEN_SYNC_OP7_PASS_PTR(op, Type1, Type2, Type3, Type4, Type5, Type6, Type7)         \
    OGL_CMD(op, 6);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    OGL_PARAM(Type5, p5);                                                                           \
    OGL_PARAM(Type6, p6);                                                                           \
    Assert(pClient->pLastParam && pClient->cbLastParam);                                            \
    gl##op(p1, p2, p3, p4, p5, p6, (Type7 *)pClient->pLastParam);


/* Sync operation whose last parameter is a block of memory and returns a value */
#define VBOX_OGL_GEN_SYNC_OP2_PTR_RET(rettype, op, Type1, Type2)                                    \
    OGL_CMD(op, 2);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_MEMPARAM(Type2, p2);                                                                        \
    pClient->lastretval = gl##op(p1);

#define VBOX_OGL_GEN_SYNC_OP4_PTR_RET(rettype, op, Type1, Type2, Type3, Type4)                      \
    OGL_CMD(op, 4);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_MEMPARAM(Type4, p4);                                                                        \
    pClient->lastretval = gl##op(p1, p2, p3, p4);

#define VBOX_OGL_GEN_SYNC_OP5_PTR_RET(rettype, op, Type1, Type2, Type3, Type4, Type5)               \
    OGL_CMD(op, 5);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    OGL_MEMPARAM(Type5, p5);                                                                        \
    pClient->lastretval = gl##op(p1, p2, p3, p4, p5);

#define VBOX_OGL_GEN_SYNC_OP6_PTR_RET(rettype, op, Type1, Type2, Type3, Type4, Type5, Type6)        \
    OGL_CMD(op, 6);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    OGL_PARAM(Type5, p5);                                                                           \
    OGL_MEMPARAM(Type6, p6);                                                                        \
    pClient->lastretval = gl##op(p1, p2, p3, p4, p5, p6);

#define VBOX_OGL_GEN_SYNC_OP7_PTR_RET(rettype, op, Type1, Type2, Type3, Type4, Type5, Type6, Type7) \
    OGL_CMD(op, 7);                                                                                 \
    OGL_PARAM(Type1, p1);                                                                           \
    OGL_PARAM(Type2, p2);                                                                           \
    OGL_PARAM(Type3, p3);                                                                           \
    OGL_PARAM(Type4, p4);                                                                           \
    OGL_PARAM(Type5, p5);                                                                           \
    OGL_PARAM(Type6, p6);                                                                           \
    OGL_MEMPARAM(Type7, p7);                                                                        \
    pClient->lastretval = gl##op(p1, p2, p3, p4, p5, p6, p7);





/* Generate async functions elements in the command queue */
#define GL_GEN_FUNC(Function)                                                                           \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP(Function);                                                                      \
    }

#define GL_GEN_FUNC1(Function, Type)                                                                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP1(Function, Type);                                                               \
    }

#define GL_GEN_FUNC1V(Function, Type)       GL_GEN_FUNC1(Function, Type)

#define GL_GEN_FUNC2(Function, Type)                                                                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP2(Function, Type, Type);                                                         \
    }

#define GL_GEN_FUNC2V(Function, Type)       GL_GEN_FUNC2(Function, Type)

#define GL_GEN_FUNC3(Function, Type)                                                                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP3(Function, Type, Type, Type);                                                   \
    }

#define GL_GEN_FUNC3V(Function, Type)       GL_GEN_FUNC3(Function, Type)

#define GL_GEN_FUNC4(Function, Type)                                                                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP4(Function, Type, Type, Type, Type);                                             \
    }

#define GL_GEN_FUNC4V(Function, Type)       GL_GEN_FUNC4(Function, Type)

#define GL_GEN_FUNC6(Function, Type)                                                                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP6(Function, Type, Type, Type, Type, Type, Type);                                 \
    }

#define GL_GEN_VPAR_FUNC2(Function, Type1, Type2)                                                       \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP2(Function, Type1, Type2);                                                       \
    }

#define GL_GEN_VPAR_FUNC2V(Function, Type)       GL_GEN_VPAR_FUNC2(Function, Type)

#define GL_GEN_VPAR_FUNC3(Function, Type1, Type2, Type3)                                                \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP3(Function, Type1, Type2, Type3);                                                \
    }

#define GL_GEN_VPAR_FUNC3V(Function, Type)       GL_GEN_VPAR_FUNC3(Function, Type)

#define GL_GEN_VPAR_FUNC4(Function, Type1, Type2, Type3, Type4)                                         \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP4(Function, Type1, Type2, Type3, Type4);                                         \
    }

#define GL_GEN_VPAR_FUNC5(Function, Type1, Type2, Type3, Type4, Type5)                                  \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP5(Function, Type1, Type2, Type3, Type4 ,Type5);                                  \
    }

#define GL_GEN_VPAR_FUNC6(Function, Type1, Type2, Type3, Type4, Type5, Type6)                           \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP6(Function, Type1, Type2, Type3, Type4 ,Type5, Type6);                           \
    }

#define GL_GEN_VPAR_FUNC7(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7)                    \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP7(Function, Type1, Type2, Type3, Type4 ,Type5, Type6, Type7);                    \
    }

#define GL_GEN_VPAR_FUNC8(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8)             \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP8(Function, Type1, Type2, Type3, Type4 ,Type5, Type6, Type7, Type8);             \
    }

#define GL_GEN_VPAR_FUNC9(Function, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8 ,Type9)      \
    void  VBOX_OGL_NAME_PREFIX(Function) (VBOXOGLCTX *pClient, uint8_t *pCmdBuffer)             \
    {                                                                                                   \
        VBOX_OGL_GEN_OP9(Function, Type1, Type2, Type3, Type4 ,Type5, Type6, Type7, Type8, Type9);      \
    }

#endif /* VBOX_OGL_HOST_SIDE */




/* OpenGL opcodes */
/* Note: keep all three tables in sync! */
typedef enum 
{
    VBOX_OGL_OP_Illegal                     = 0,
    VBOX_OGL_OP_ArrayElement,
    VBOX_OGL_OP_Begin,
    VBOX_OGL_OP_BindTexture,
    VBOX_OGL_OP_BlendFunc,
    VBOX_OGL_OP_CallList,
    VBOX_OGL_OP_Color3b,
    VBOX_OGL_OP_Color3d,
    VBOX_OGL_OP_Color3f,
    VBOX_OGL_OP_Color3i,
    VBOX_OGL_OP_Color3s,
    VBOX_OGL_OP_Color3ub,
    VBOX_OGL_OP_Color3ui,
    VBOX_OGL_OP_Color3us,
    VBOX_OGL_OP_Color4b,
    VBOX_OGL_OP_Color4d,
    VBOX_OGL_OP_Color4f,
    VBOX_OGL_OP_Color4i,
    VBOX_OGL_OP_Color4s,
    VBOX_OGL_OP_Color4ub,
    VBOX_OGL_OP_Color4ui,
    VBOX_OGL_OP_Color4us,
    VBOX_OGL_OP_Clear,
    VBOX_OGL_OP_ClearAccum,
    VBOX_OGL_OP_ClearColor,
    VBOX_OGL_OP_ClearDepth,
    VBOX_OGL_OP_ClearIndex,
    VBOX_OGL_OP_ClearStencil,
    VBOX_OGL_OP_Accum,
    VBOX_OGL_OP_AlphaFunc,
    VBOX_OGL_OP_Vertex2d,
    VBOX_OGL_OP_Vertex2f,
    VBOX_OGL_OP_Vertex2i,
    VBOX_OGL_OP_Vertex2s,
    VBOX_OGL_OP_Vertex3d,
    VBOX_OGL_OP_Vertex3f,
    VBOX_OGL_OP_Vertex3i,
    VBOX_OGL_OP_Vertex3s,
    VBOX_OGL_OP_Vertex4d,
    VBOX_OGL_OP_Vertex4f,
    VBOX_OGL_OP_Vertex4i,
    VBOX_OGL_OP_Vertex4s,
    VBOX_OGL_OP_TexCoord1d,
    VBOX_OGL_OP_TexCoord1f,
    VBOX_OGL_OP_TexCoord1i,
    VBOX_OGL_OP_TexCoord1s,
    VBOX_OGL_OP_TexCoord2d,
    VBOX_OGL_OP_TexCoord2f,
    VBOX_OGL_OP_TexCoord2i,
    VBOX_OGL_OP_TexCoord2s,
    VBOX_OGL_OP_TexCoord3d,
    VBOX_OGL_OP_TexCoord3f,
    VBOX_OGL_OP_TexCoord3i,
    VBOX_OGL_OP_TexCoord3s,
    VBOX_OGL_OP_TexCoord4d,
    VBOX_OGL_OP_TexCoord4f,
    VBOX_OGL_OP_TexCoord4i,
    VBOX_OGL_OP_TexCoord4s,
    VBOX_OGL_OP_Normal3b,
    VBOX_OGL_OP_Normal3d,
    VBOX_OGL_OP_Normal3f,
    VBOX_OGL_OP_Normal3i,
    VBOX_OGL_OP_Normal3s,
    VBOX_OGL_OP_RasterPos2d,
    VBOX_OGL_OP_RasterPos2f,
    VBOX_OGL_OP_RasterPos2i,
    VBOX_OGL_OP_RasterPos2s,
    VBOX_OGL_OP_RasterPos3d,
    VBOX_OGL_OP_RasterPos3f,
    VBOX_OGL_OP_RasterPos3i,
    VBOX_OGL_OP_RasterPos3s,
    VBOX_OGL_OP_RasterPos4d,
    VBOX_OGL_OP_RasterPos4f,
    VBOX_OGL_OP_RasterPos4i,
    VBOX_OGL_OP_RasterPos4s,
    VBOX_OGL_OP_EvalCoord1d,
    VBOX_OGL_OP_EvalCoord1f,
    VBOX_OGL_OP_EvalCoord2d,
    VBOX_OGL_OP_EvalCoord2f,
    VBOX_OGL_OP_EvalPoint1,
    VBOX_OGL_OP_EvalPoint2,
    VBOX_OGL_OP_Indexd,
    VBOX_OGL_OP_Indexf,
    VBOX_OGL_OP_Indexi,
    VBOX_OGL_OP_Indexs,
    VBOX_OGL_OP_Indexub,
    VBOX_OGL_OP_Rotated,
    VBOX_OGL_OP_Rotatef,
    VBOX_OGL_OP_Scaled,
    VBOX_OGL_OP_Scalef,
    VBOX_OGL_OP_Translated,
    VBOX_OGL_OP_Translatef,
    VBOX_OGL_OP_DepthFunc,
    VBOX_OGL_OP_DepthMask,
    VBOX_OGL_OP_Finish,
    VBOX_OGL_OP_Flush,
    VBOX_OGL_OP_DeleteLists,
    VBOX_OGL_OP_CullFace,
    VBOX_OGL_OP_DeleteTextures,
    VBOX_OGL_OP_DepthRange,
    VBOX_OGL_OP_DisableClientState,
    VBOX_OGL_OP_EnableClientState,
    VBOX_OGL_OP_EvalMesh1,
    VBOX_OGL_OP_EvalMesh2,
    VBOX_OGL_OP_Fogf,
    VBOX_OGL_OP_Fogfv,
    VBOX_OGL_OP_Fogi,
    VBOX_OGL_OP_Fogiv,
    VBOX_OGL_OP_LightModelf,
    VBOX_OGL_OP_LightModelfv,
    VBOX_OGL_OP_LightModeli,
    VBOX_OGL_OP_LightModeliv,
    VBOX_OGL_OP_Lightf,
    VBOX_OGL_OP_Lightfv,
    VBOX_OGL_OP_Lighti,
    VBOX_OGL_OP_Lightiv,
    VBOX_OGL_OP_LineStipple,
    VBOX_OGL_OP_LineWidth,
    VBOX_OGL_OP_ListBase,
    VBOX_OGL_OP_DrawArrays,
    VBOX_OGL_OP_DrawBuffer,
    VBOX_OGL_OP_EdgeFlag,
    VBOX_OGL_OP_End,
    VBOX_OGL_OP_EndList,
    VBOX_OGL_OP_CopyTexImage1D,
    VBOX_OGL_OP_CopyTexImage2D,
    VBOX_OGL_OP_ColorMaterial,
    VBOX_OGL_OP_Materiali,
    VBOX_OGL_OP_Materialf,
    VBOX_OGL_OP_Materialfv,
    VBOX_OGL_OP_Materialiv,
    VBOX_OGL_OP_PopAttrib,
    VBOX_OGL_OP_PopClientAttrib,
    VBOX_OGL_OP_PopMatrix,
    VBOX_OGL_OP_PopName,
    VBOX_OGL_OP_PushAttrib,
    VBOX_OGL_OP_PushClientAttrib,
    VBOX_OGL_OP_PushMatrix,
    VBOX_OGL_OP_PushName,
    VBOX_OGL_OP_ReadBuffer,
    VBOX_OGL_OP_TexGendv,
    VBOX_OGL_OP_TexGenf,
    VBOX_OGL_OP_TexGend,
    VBOX_OGL_OP_TexGeni,
    VBOX_OGL_OP_TexEnvi,
    VBOX_OGL_OP_TexEnvf,
    VBOX_OGL_OP_TexEnviv,
    VBOX_OGL_OP_TexEnvfv,
    VBOX_OGL_OP_TexGeniv,
    VBOX_OGL_OP_TexGenfv,
    VBOX_OGL_OP_TexParameterf,
    VBOX_OGL_OP_TexParameteri,
    VBOX_OGL_OP_TexParameterfv,
    VBOX_OGL_OP_TexParameteriv,
    VBOX_OGL_OP_LoadIdentity,
    VBOX_OGL_OP_LoadName,
    VBOX_OGL_OP_LoadMatrixd,
    VBOX_OGL_OP_LoadMatrixf,
    VBOX_OGL_OP_StencilFunc,
    VBOX_OGL_OP_ShadeModel,
    VBOX_OGL_OP_StencilMask,
    VBOX_OGL_OP_StencilOp,
    VBOX_OGL_OP_Scissor,
    VBOX_OGL_OP_Viewport,
    VBOX_OGL_OP_Rectd,
    VBOX_OGL_OP_Rectf,
    VBOX_OGL_OP_Recti,
    VBOX_OGL_OP_Rects,
    VBOX_OGL_OP_Rectdv,
    VBOX_OGL_OP_Rectfv,
    VBOX_OGL_OP_Rectiv,
    VBOX_OGL_OP_Rectsv,
    VBOX_OGL_OP_MultMatrixd,
    VBOX_OGL_OP_MultMatrixf,
    VBOX_OGL_OP_NewList,
    VBOX_OGL_OP_Hint,
    VBOX_OGL_OP_IndexMask,
    VBOX_OGL_OP_InitNames,
    VBOX_OGL_OP_TexCoordPointer,
    VBOX_OGL_OP_VertexPointer,
    VBOX_OGL_OP_ColorPointer,
    VBOX_OGL_OP_EdgeFlagPointer,
    VBOX_OGL_OP_IndexPointer,
    VBOX_OGL_OP_NormalPointer,
    VBOX_OGL_OP_PolygonStipple,
    VBOX_OGL_OP_CallLists,
    VBOX_OGL_OP_ClipPlane,
    VBOX_OGL_OP_Frustum,
    VBOX_OGL_OP_GenTextures,
    VBOX_OGL_OP_Map1d,
    VBOX_OGL_OP_Map1f,
    VBOX_OGL_OP_Map2d,
    VBOX_OGL_OP_Map2f,
    VBOX_OGL_OP_MapGrid1d,
    VBOX_OGL_OP_MapGrid1f,
    VBOX_OGL_OP_MapGrid2d,
    VBOX_OGL_OP_MapGrid2f,
    VBOX_OGL_OP_CopyPixels,
    VBOX_OGL_OP_TexImage1D,
    VBOX_OGL_OP_TexImage2D,
    VBOX_OGL_OP_TexSubImage1D,
    VBOX_OGL_OP_TexSubImage2D,
    VBOX_OGL_OP_FeedbackBuffer,
    VBOX_OGL_OP_SelectBuffer,
    VBOX_OGL_OP_IsList,
    VBOX_OGL_OP_IsTexture,
    VBOX_OGL_OP_RenderMode,
    VBOX_OGL_OP_ReadPixels,
    VBOX_OGL_OP_IsEnabled,
    VBOX_OGL_OP_GenLists,
    VBOX_OGL_OP_PixelTransferf,
    VBOX_OGL_OP_PixelTransferi,
    VBOX_OGL_OP_PixelZoom,
    VBOX_OGL_OP_PixelStorei,
    VBOX_OGL_OP_PixelStoref,
    VBOX_OGL_OP_PixelMapfv,
    VBOX_OGL_OP_PixelMapuiv,
    VBOX_OGL_OP_PixelMapusv,
    VBOX_OGL_OP_PointSize,
    VBOX_OGL_OP_PolygonMode,
    VBOX_OGL_OP_PolygonOffset,
    VBOX_OGL_OP_PassThrough,
    VBOX_OGL_OP_Ortho,
    VBOX_OGL_OP_MatrixMode,
    VBOX_OGL_OP_LogicOp,
    VBOX_OGL_OP_ColorMask,
    VBOX_OGL_OP_CopyTexSubImage1D,
    VBOX_OGL_OP_CopyTexSubImage2D,
    VBOX_OGL_OP_FrontFace,
    VBOX_OGL_OP_Disable,
    VBOX_OGL_OP_Enable,
    VBOX_OGL_OP_PrioritizeTextures,
    VBOX_OGL_OP_GetBooleanv,
    VBOX_OGL_OP_GetDoublev,
    VBOX_OGL_OP_GetFloatv,
    VBOX_OGL_OP_GetIntegerv,
    VBOX_OGL_OP_GetLightfv,
    VBOX_OGL_OP_GetLightiv,
    VBOX_OGL_OP_GetMaterialfv,
    VBOX_OGL_OP_GetMaterialiv,
    VBOX_OGL_OP_GetPixelMapfv,
    VBOX_OGL_OP_GetPixelMapuiv,
    VBOX_OGL_OP_GetPixelMapusv,
    VBOX_OGL_OP_GetTexEnviv,
    VBOX_OGL_OP_GetTexEnvfv,
    VBOX_OGL_OP_GetTexGendv,
    VBOX_OGL_OP_GetTexGenfv,
    VBOX_OGL_OP_GetTexGeniv,
    VBOX_OGL_OP_GetTexParameterfv,
    VBOX_OGL_OP_GetTexParameteriv,
    VBOX_OGL_OP_GetClipPlane,
    VBOX_OGL_OP_GetPolygonStipple,
    VBOX_OGL_OP_GetTexLevelParameterfv,
    VBOX_OGL_OP_GetTexLevelParameteriv,
    VBOX_OGL_OP_GetTexImage,

    /* Windows ICD exports */
    VBOX_OGL_OP_DrvReleaseContext,
    VBOX_OGL_OP_DrvCreateContext,
    VBOX_OGL_OP_DrvDeleteContext,
    VBOX_OGL_OP_DrvCopyContext,
    VBOX_OGL_OP_DrvSetContext,
    VBOX_OGL_OP_DrvCreateLayerContext,
    VBOX_OGL_OP_DrvShareLists,
    VBOX_OGL_OP_DrvDescribeLayerPlane,
    VBOX_OGL_OP_DrvSetLayerPaletteEntries,
    VBOX_OGL_OP_DrvGetLayerPaletteEntries,
    VBOX_OGL_OP_DrvRealizeLayerPalette,
    VBOX_OGL_OP_DrvSwapLayerBuffers,
    VBOX_OGL_OP_DrvDescribePixelFormat,
    VBOX_OGL_OP_DrvSetPixelFormat,
    VBOX_OGL_OP_DrvSwapBuffers,

    /* OpenGL Extensions */
    VBOX_OGL_OP_wglSwapIntervalEXT,
    VBOX_OGL_OP_wglGetSwapIntervalEXT,

    VBOX_OGL_OP_Last,

    VBOX_OGL_OP_SizeHack                     = 0x7fffffff
} VBOX_OGL_OP;

#if defined(DEBUG) && defined(VBOX_OGL_WITH_CMD_STRINGS)
static const char *pszVBoxOGLCmd[VBOX_OGL_OP_Last] =
{
    "ILLEGAL",
    "glArrayElement",
    "glBegin",
    "glBindTexture",
    "glBlendFunc",
    "glCallList",
    "glColor3b",
    "glColor3d",
    "glColor3f",
    "glColor3i",
    "glColor3s",
    "glColor3ub",
    "glColor3ui",
    "glColor3us",
    "glColor4b",
    "glColor4d",
    "glColor4f",
    "glColor4i",
    "glColor4s",
    "glColor4ub",
    "glColor4ui",
    "glColor4us",
    "glClear",
    "glClearAccum",
    "glClearColor",
    "glClearDepth",
    "glClearIndex",
    "glClearStencil",
    "glAccum",
    "glAlphaFunc",
    "glVertex2d",
    "glVertex2f",
    "glVertex2i",
    "glVertex2s",
    "glVertex3d",
    "glVertex3f",
    "glVertex3i",
    "glVertex3s",
    "glVertex4d",
    "glVertex4f",
    "glVertex4i",
    "glVertex4s",
    "glTexCoord1d",
    "glTexCoord1f",
    "glTexCoord1i",
    "glTexCoord1s",
    "glTexCoord2d",
    "glTexCoord2f",
    "glTexCoord2i",
    "glTexCoord2s",
    "glTexCoord3d",
    "glTexCoord3f",
    "glTexCoord3i",
    "glTexCoord3s",
    "glTexCoord4d",
    "glTexCoord4f",
    "glTexCoord4i",
    "glTexCoord4s",
    "glNormal3b",
    "glNormal3d",
    "glNormal3f",
    "glNormal3i",
    "glNormal3s",
    "glRasterPos2d",
    "glRasterPos2f",
    "glRasterPos2i",
    "glRasterPos2s",
    "glRasterPos3d",
    "glRasterPos3f",
    "glRasterPos3i",
    "glRasterPos3s",
    "glRasterPos4d",
    "glRasterPos4f",
    "glRasterPos4i",
    "glRasterPos4s",
    "glEvalCoord1d",
    "glEvalCoord1f",
    "glEvalCoord2d",
    "glEvalCoord2f",
    "glEvalPoint1",
    "glEvalPoint2",
    "glIndexd",
    "glIndexf",
    "glIndexi",
    "glIndexs",
    "glIndexub",
    "glRotated",
    "glRotatef",
    "glScaled",
    "glScalef",
    "glTranslated",
    "glTranslatef",
    "glDepthFunc",
    "glDepthMask",
    "glFinish",
    "glFlush",
    "glDeleteLists",
    "glCullFace",
    "glDeleteTextures",
    "glDepthRange",
    "glDisableClientState",
    "glEnableClientState",
    "glEvalMesh1",
    "glEvalMesh2",
    "glFogf",
    "glFogfv",
    "glFogi",
    "glFogiv",
    "glLightModelf",
    "glLightModelfv",
    "glLightModeli",
    "glLightModeliv",
    "glLightf",
    "glLightfv",
    "glLighti",
    "glLightiv",
    "glLineStipple",
    "glLineWidth",
    "glListBase",
    "glDrawArrays",
    "glDrawBuffer",
    "glEdgeFlag",
    "glEnd",
    "glEndList",
    "glCopyTexImage1D",
    "glCopyTexImage2D",
    "glColorMaterial",
    "glMateriali",
    "glMaterialf",
    "glMaterialfv",
    "glMaterialiv",
    "glPopAttrib",
    "glPopClientAttrib",
    "glPopMatrix",
    "glPopName",
    "glPushAttrib",
    "glPushClientAttrib",
    "glPushMatrix",
    "glPushName",
    "glReadBuffer",
    "glTexGendv",
    "glTexGenf",
    "glTexGend",
    "glTexGeni",
    "glTexEnvi",
    "glTexEnvf",
    "glTexEnviv",
    "glTexEnvfv",
    "glTexGeniv",
    "glTexGenfv",
    "glTexParameterf",
    "glTexParameteri",
    "glTexParameterfv",
    "glTexParameteriv",
    "glLoadIdentity",
    "glLoadName",
    "glLoadMatrixd",
    "glLoadMatrixf",
    "glStencilFunc",
    "glShadeModel",
    "glStencilMask",
    "glStencilOp",
    "glScissor",
    "glViewport",
    "glRectd",
    "glRectf",
    "glRecti",
    "glRects",
    "glRectdv",
    "glRectfv",
    "glRectiv",
    "glRectsv",
    "glMultMatrixd",
    "glMultMatrixf",
    "glNewList",
    "glHint",
    "glIndexMask",
    "glInitNames",
    "glTexCoordPointer",
    "glVertexPointer",
    "glColorPointer",
    "glEdgeFlagPointer",
    "glIndexPointer",
    "glNormalPointer",
    "glPolygonStipple",
    "glCallLists",
    "glClipPlane",
    "glFrustum",
    "glGenTextures",
    "glMap1d",
    "glMap1f",
    "glMap2d",
    "glMap2f",
    "glMapGrid1d",
    "glMapGrid1f",
    "glMapGrid2d",
    "glMapGrid2f",
    "glCopyPixels",
    "glTexImage1D",
    "glTexImage2D",
    "glTexSubImage1D",
    "glTexSubImage2D",
    "glFeedbackBuffer",
    "glSelectBuffer",
    "glIsList",
    "glIsTexture",
    "glRenderMode",
    "glReadPixels",
    "glIsEnabled",
    "glGenLists",
    "glPixelTransferf",
    "glPixelTransferi",
    "glPixelZoom",
    "glPixelStorei",
    "glPixelStoref",
    "glPixelMapfv",
    "glPixelMapuiv",
    "glPixelMapusv",
    "glPointSize",
    "glPolygonMode",
    "glPolygonOffset",
    "glPassThrough",
    "glOrtho",
    "glMatrixMode",
    "glLogicOp",
    "glColorMask",
    "glCopyTexSubImage1D",
    "glCopyTexSubImage2D",
    "glFrontFace",
    "glDisable",
    "glEnable",
    "glPrioritizeTextures",
    "glGetBooleanv",
    "glGetDoublev",
    "glGetFloatv",
    "glGetIntegerv",
    "glGetLightfv",
    "glGetLightiv",
    "glGetMaterialfv",
    "glGetMaterialiv",
    "glGetPixelMapfv",
    "glGetPixelMapuiv",
    "glGetPixelMapusv",
    "glGetTexEnviv",
    "glGetTexEnvfv",
    "glGetTexGendv",
    "glGetTexGenfv",
    "glGetTexGeniv",
    "glGetTexParameterfv",
    "glGetTexParameteriv",
    "glGetClipPlane",
    "glGetPolygonStipple",
    "glGetTexLevelParameterfv",
    "glGetTexLevelParameteriv",
    "glGetTexImage",

    /* Windows ICD exports */
    "DrvReleaseContext",
    "DrvCreateContext",
    "DrvDeleteContext",
    "DrvCopyContext",
    "DrvSetContext",
    "DrvCreateLayerContext",
    "DrvShareLists",
    "DrvDescribeLayerPlane",
    "DrvSetLayerPaletteEntries",
    "DrvGetLayerPaletteEntries",
    "DrvRealizeLayerPalette",
    "DrvSwapLayerBuffers",
    "DrvDescribePixelFormat",
    "DrvSetPixelFormat",
    "DrvSwapBuffers",

    /* OpenGL Extensions */
    "wglSwapIntervalEXT",
    "wglGetSwapIntervalEXT",
};
#endif

#ifdef VBOX_OGL_WITH_FUNCTION_WRAPPERS
/* OpenGL function wrappers. */
static PFN_VBOXGLWRAPPER pfnOGLWrapper[VBOX_OGL_OP_Last] =
{
    NULL,
    vboxglArrayElement,
    vboxglBegin,
    vboxglBindTexture,
    vboxglBlendFunc,
    vboxglCallList,
    vboxglColor3b,
    vboxglColor3d,
    vboxglColor3f,
    vboxglColor3i,
    vboxglColor3s,
    vboxglColor3ub,
    vboxglColor3ui,
    vboxglColor3us,
    vboxglColor4b,
    vboxglColor4d,
    vboxglColor4f,
    vboxglColor4i,
    vboxglColor4s,
    vboxglColor4ub,
    vboxglColor4ui,
    vboxglColor4us,
    vboxglClear,
    vboxglClearAccum,
    vboxglClearColor,
    vboxglClearDepth,
    vboxglClearIndex,
    vboxglClearStencil,
    vboxglAccum,
    vboxglAlphaFunc,
    vboxglVertex2d,
    vboxglVertex2f,
    vboxglVertex2i,
    vboxglVertex2s,
    vboxglVertex3d,
    vboxglVertex3f,
    vboxglVertex3i,
    vboxglVertex3s,
    vboxglVertex4d,
    vboxglVertex4f,
    vboxglVertex4i,
    vboxglVertex4s,
    vboxglTexCoord1d,
    vboxglTexCoord1f,
    vboxglTexCoord1i,
    vboxglTexCoord1s,
    vboxglTexCoord2d,
    vboxglTexCoord2f,
    vboxglTexCoord2i,
    vboxglTexCoord2s,
    vboxglTexCoord3d,
    vboxglTexCoord3f,
    vboxglTexCoord3i,
    vboxglTexCoord3s,
    vboxglTexCoord4d,
    vboxglTexCoord4f,
    vboxglTexCoord4i,
    vboxglTexCoord4s,
    vboxglNormal3b,
    vboxglNormal3d,
    vboxglNormal3f,
    vboxglNormal3i,
    vboxglNormal3s,
    vboxglRasterPos2d,
    vboxglRasterPos2f,
    vboxglRasterPos2i,
    vboxglRasterPos2s,
    vboxglRasterPos3d,
    vboxglRasterPos3f,
    vboxglRasterPos3i,
    vboxglRasterPos3s,
    vboxglRasterPos4d,
    vboxglRasterPos4f,
    vboxglRasterPos4i,
    vboxglRasterPos4s,
    vboxglEvalCoord1d,
    vboxglEvalCoord1f,
    vboxglEvalCoord2d,
    vboxglEvalCoord2f,
    vboxglEvalPoint1,
    vboxglEvalPoint2,
    vboxglIndexd,
    vboxglIndexf,
    vboxglIndexi,
    vboxglIndexs,
    vboxglIndexub,
    vboxglRotated,
    vboxglRotatef,
    vboxglScaled,
    vboxglScalef,
    vboxglTranslated,
    vboxglTranslatef,
    vboxglDepthFunc,
    vboxglDepthMask,
    vboxglFinish,
    vboxglFlush,
    vboxglDeleteLists,
    vboxglCullFace,
    vboxglDeleteTextures,
    vboxglDepthRange,
    vboxglDisableClientState,
    vboxglEnableClientState,
    vboxglEvalMesh1,
    vboxglEvalMesh2,
    vboxglFogf,
    vboxglFogfv,
    vboxglFogi,
    vboxglFogiv,
    vboxglLightModelf,
    vboxglLightModelfv,
    vboxglLightModeli,
    vboxglLightModeliv,
    vboxglLightf,
    vboxglLightfv,
    vboxglLighti,
    vboxglLightiv,
    vboxglLineStipple,
    vboxglLineWidth,
    vboxglListBase,
    vboxglDrawArrays,
    vboxglDrawBuffer,
    vboxglEdgeFlag,
    vboxglEnd,
    vboxglEndList,
    vboxglCopyTexImage1D,
    vboxglCopyTexImage2D,
    vboxglColorMaterial,
    vboxglMateriali,
    vboxglMaterialf,
    vboxglMaterialfv,
    vboxglMaterialiv,
    vboxglPopAttrib,
    vboxglPopClientAttrib,
    vboxglPopMatrix,
    vboxglPopName,
    vboxglPushAttrib,
    vboxglPushClientAttrib,
    vboxglPushMatrix,
    vboxglPushName,
    vboxglReadBuffer,
    vboxglTexGendv,
    vboxglTexGenf,
    vboxglTexGend,
    vboxglTexGeni,
    vboxglTexEnvi,
    vboxglTexEnvf,
    vboxglTexEnviv,
    vboxglTexEnvfv,
    vboxglTexGeniv,
    vboxglTexGenfv,
    vboxglTexParameterf,
    vboxglTexParameteri,
    vboxglTexParameterfv,
    vboxglTexParameteriv,
    vboxglLoadIdentity,
    vboxglLoadName,
    vboxglLoadMatrixd,
    vboxglLoadMatrixf,
    vboxglStencilFunc,
    vboxglShadeModel,
    vboxglStencilMask,
    vboxglStencilOp,
    vboxglScissor,
    vboxglViewport,
    vboxglRectd,
    vboxglRectf,
    vboxglRecti,
    vboxglRects,
    vboxglRectdv,
    vboxglRectfv,
    vboxglRectiv,
    vboxglRectsv,
    vboxglMultMatrixd,
    vboxglMultMatrixf,
    vboxglNewList,
    vboxglHint,
    vboxglIndexMask,
    vboxglInitNames,
    vboxglTexCoordPointer,
    vboxglVertexPointer,
    vboxglColorPointer,
    vboxglEdgeFlagPointer,
    vboxglIndexPointer,
    vboxglNormalPointer,
    vboxglPolygonStipple,
    vboxglCallLists,
    vboxglClipPlane,
    vboxglFrustum,
    vboxglGenTextures,
    vboxglMap1d,
    vboxglMap1f,
    vboxglMap2d,
    vboxglMap2f,
    vboxglMapGrid1d,
    vboxglMapGrid1f,
    vboxglMapGrid2d,
    vboxglMapGrid2f,
    vboxglCopyPixels,
    vboxglTexImage1D,
    vboxglTexImage2D,
    vboxglTexSubImage1D,
    vboxglTexSubImage2D,
    vboxglFeedbackBuffer,
    vboxglSelectBuffer,
    vboxglIsList,
    vboxglIsTexture,
    vboxglRenderMode,
    vboxglReadPixels,
    vboxglIsEnabled,
    vboxglGenLists,
    vboxglPixelTransferf,
    vboxglPixelTransferi,
    vboxglPixelZoom,
    vboxglPixelStorei,
    vboxglPixelStoref,
    vboxglPixelMapfv,
    vboxglPixelMapuiv,
    vboxglPixelMapusv,
    vboxglPointSize,
    vboxglPolygonMode,
    vboxglPolygonOffset,
    vboxglPassThrough,
    vboxglOrtho,
    vboxglMatrixMode,
    vboxglLogicOp,
    vboxglColorMask,
    vboxglCopyTexSubImage1D,
    vboxglCopyTexSubImage2D,
    vboxglFrontFace,
    vboxglDisable,
    vboxglEnable,
    vboxglPrioritizeTextures,
    vboxglGetBooleanv,
    vboxglGetDoublev,
    vboxglGetFloatv,
    vboxglGetIntegerv,
    vboxglGetLightfv,
    vboxglGetLightiv,
    vboxglGetMaterialfv,
    vboxglGetMaterialiv,
    vboxglGetPixelMapfv,
    vboxglGetPixelMapuiv,
    vboxglGetPixelMapusv,
    vboxglGetTexEnviv,
    vboxglGetTexEnvfv,
    vboxglGetTexGendv,
    vboxglGetTexGenfv,
    vboxglGetTexGeniv,
    vboxglGetTexParameterfv,
    vboxglGetTexParameteriv,
    vboxglGetClipPlane,
    vboxglGetPolygonStipple,
    vboxglGetTexLevelParameterfv,
    vboxglGetTexLevelParameteriv,
    vboxglGetTexImage,

    /* Windows ICD exports */
    vboxglDrvReleaseContext,
    vboxglDrvCreateContext,
    vboxglDrvDeleteContext,
    vboxglDrvCopyContext,
    vboxglDrvSetContext,
    vboxglDrvCreateLayerContext,
    vboxglDrvShareLists,
    vboxglDrvDescribeLayerPlane,
    vboxglDrvSetLayerPaletteEntries,
    vboxglDrvGetLayerPaletteEntries,
    vboxglDrvRealizeLayerPalette,
    vboxglDrvSwapLayerBuffers,
    vboxglDrvDescribePixelFormat,
    vboxglDrvSetPixelFormat,
    vboxglDrvSwapBuffers,

#ifdef RT_OS_WINDOWS
    /* OpenGL Extensions */
    vboxwglSwapIntervalEXT,
    vboxwglGetSwapIntervalEXT,
#endif
};
#endif


#ifdef VBOX_OGL_WITH_EXTENSION_ARRAY
typedef struct
{
    const char *pszExtName;
    const char *pszExtFunctionName;
#ifdef VBOX_OGL_GUEST_SIDE
    RTUINTPTR   pfnFunction;
#else
    RTUINTPTR  *ppfnFunction;
#endif
    bool        fAvailable;
} OPENGL_EXT, *POPENGL_EXT;

#ifdef VBOX_OGL_GUEST_SIDE
#define VBOX_OGL_EXTENSION(a)   (RTUINTPTR)a
#else
#define VBOX_OGL_EXTENSION(a)   (RTUINTPTR *)&pfn##a

static PFNWGLSWAPINTERVALEXTPROC        pfnwglSwapIntervalEXT       = NULL;
static PFNWGLGETSWAPINTERVALEXTPROC     pfnwglGetSwapIntervalEXT    = NULL;

#endif

static OPENGL_EXT OpenGLExtensions[] = 
{
    {   "WGL_EXT_swap_control",             "wglSwapIntervalEXT",               VBOX_OGL_EXTENSION(wglSwapIntervalEXT),                      false },
    {   "WGL_EXT_swap_control",             "wglGetSwapIntervalEXT",            VBOX_OGL_EXTENSION(wglGetSwapIntervalEXT),                   false },
};
#endif /* VBOX_OGL_WITH_EXTENSION_ARRAY */

#endif

