/******************************Module*Header*******************************\
* Module Name: subbatch.h
*
* OpenGL batching macros.
*
* Copyright (c) 1993 Microsoft Corporation
\**************************************************************************/

#ifndef __SUBBATCH_H__
#define __SUBBATCH_H__

#ifdef DOGLMSGBATCHSTATS
#define STATS_INC_CLIENTCALLS()     (pMsgBatchInfo->BatchStats.ClientCalls++)
#else
#define STATS_INC_CLIENTCALLS()
#endif

// Put a message into shared area.  If it does not fit, flush what is
// currently in the buffer and then put the message at start of the buffer
//
// NOTE: glsbAttentionAlt() updates pMsgBatchInfo->NextOffset on return.
//       If you modify this macro, you have to fix the glsbAttentionAlt()
//       function!

#define GLCLIENT_BEGIN(ProcName,MsgStruct)                                  \
{                                                                           \
    GLMSGBATCHINFO *pMsgBatchInfo;                                          \
    GLMSG_##MsgStruct *pMsg;                                                \
    ULONG CurrentOffset;                                                    \
                                                                            \
    /* Get shared memory window from the TEB */                             \
    pMsgBatchInfo = GLTEB_SHAREDMEMORYSECTION();                            \
    STATS_INC_CLIENTCALLS();                                                \
                                                                            \
    /* Get and update the offset of the next message */                     \
    CurrentOffset = pMsgBatchInfo->NextOffset;                              \
    pMsgBatchInfo->NextOffset += GLMSG_ALIGN(sizeof(GLMSG_##MsgStruct));    \
                                                                            \
    /* Flush message if shared memory window is full */                     \
    if (pMsgBatchInfo->NextOffset > pMsgBatchInfo->MaximumOffset)           \
        CurrentOffset = glsbAttentionAlt(CurrentOffset);                    \
                                                                            \
    /* Add message to the batch */                                          \
    pMsg = (GLMSG_##MsgStruct *)(((BYTE *)pMsgBatchInfo) + CurrentOffset);  \
    pMsg->ProcOffset = offsetof(GLSRVSBPROCTABLE, glsrv##ProcName);

#define GLCLIENT_END        }

// Large Messages have a variable amount of data associated with them.
// Unlike the non-clientside version, however, we will not attempt to
// copy the message into the buffer.  Instead, we will pass the pointer
// and flush.  Unlike CSR, we will not have to copy data in/out of a
// shared memory section to do this.

#define GLCLIENT_BEGIN_LARGE(bSet,ProcName,MsgStruct,pData,Size,OffData)    \
{                                                                           \
    GLMSGBATCHINFO *pMsgBatchInfo;                                          \
    GLMSG_##MsgStruct *pMsg;                                                \
    ULONG CurrentOffset;                                                    \
                                                                            \
    /* Get shared memory window from the TEB */                             \
    pMsgBatchInfo = GLTEB_SHAREDMEMORYSECTION();                            \
    STATS_INC_CLIENTCALLS();                                                \
                                                                            \
    /* Get and update the offset of the next message */                     \
    CurrentOffset = pMsgBatchInfo->NextOffset;                              \
    pMsgBatchInfo->NextOffset += GLMSG_ALIGN(sizeof(GLMSG_##MsgStruct));    \
                                                                            \
    /* Flush message if shared memory window is full */                     \
    if (pMsgBatchInfo->NextOffset > pMsgBatchInfo->MaximumOffset)           \
        CurrentOffset = glsbAttentionAlt(CurrentOffset);                    \
                                                                            \
    /* Set up message header */                                             \
    pMsg = (GLMSG_##MsgStruct *)(((BYTE *)pMsgBatchInfo) + CurrentOffset);  \
    pMsg->ProcOffset = offsetof(GLSRVSBPROCTABLE, glsrv##ProcName);         \
    pMsg->##OffData = (ULONG_PTR) pData;                                        \
                                                                            \
    DBGLEVEL2(LEVEL_INFO, "GLCLIENT_BEGIN_LARGE %s pdata 0x%x\n",           \
        #ProcName, pData);

#define GLCLIENT_END_LARGE_SET                                              \
    glsbAttention();                                                        \
}

#define GLCLIENT_END_LARGE_GET                                              \
    glsbAttention();                                                        \
}

#define GLCLIENT_BEGIN_LARGE_SET(ProcName,MsgStruct,pData,Size,OffData)     \
        GLCLIENT_BEGIN_LARGE(TRUE,ProcName,MsgStruct,pData,Size,OffData)

#define GLCLIENT_BEGIN_LARGE_GET(ProcName,MsgStruct,pData,Size,OffData)     \
        GLCLIENT_BEGIN_LARGE(FALSE,ProcName,MsgStruct,pData,Size,OffData)

#define GLMSG_MEMCPY(dest,src,size)     memcpy(dest,src,size)

#endif /* !__SUBBATCH_H__ */