diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/packer/pack_buffer.c')
-rw-r--r-- | src/VBox/GuestHost/OpenGL/packer/pack_buffer.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c b/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c new file mode 100644 index 00000000..003b76c0 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c @@ -0,0 +1,533 @@ +/* Copyright (c) 2001, Stanford University + * All rights reserved + * + * See the file LICENSE.txt for information on redistributing this software. + */ + +#include "cr_mem.h" +#include "cr_string.h" +#include "packer.h" +#include "cr_error.h" +#include "cr_protocol.h" +#ifndef IN_RING0 +#include "cr_unpack.h" +#endif + +#ifndef IN_RING0 +void crWriteUnalignedDouble( void *buffer, double d ) +{ + unsigned int *ui = (unsigned int *) buffer; + ui[0] = ((unsigned int *) &d)[0]; + ui[1] = ((unsigned int *) &d)[1]; +} + +void crWriteSwappedDouble( void *buffer, double d ) +{ + unsigned int *ui = (unsigned int *) buffer; + ui[0] = SWAP32(((unsigned int *) &d)[1]); + ui[1] = SWAP32(((unsigned int *) &d)[0]); +} + +double crReadUnalignedDouble( const void *buffer ) +{ + const unsigned int *ui = (unsigned int *) buffer; + double d; + ((unsigned int *) &d)[0] = ui[0]; + ((unsigned int *) &d)[1] = ui[1]; + return d; +} +#endif +/* + * We need the packer to run as efficiently as possible. To avoid one + * pointer dereference from the CRPackContext to the current CRPackBuffer, + * we keep a _copy_ of the current CRPackBuffer in the CRPackContext and + * operate on the fields in CRPackContext, rather than the CRPackBuffer. + * + * To keep things in sync, when we change a context's + * buffer, we have to use the crPackSet/GetBuffer() functions. + */ + +void crPackSetBuffer( CRPackContext *pc, CRPackBuffer *buffer ) +{ + CRASSERT( pc ); + CRASSERT( buffer ); + + if (pc->currentBuffer == buffer) + return; /* re-bind is no-op */ + + if (pc->currentBuffer) { + /* Another buffer currently bound to this packer (shouldn't normally occur) + * Release it. Fixes Ensight issue. + */ + crPackReleaseBuffer(pc); + } + + CRASSERT( pc->currentBuffer == NULL); /* release if NULL? */ + CRASSERT( buffer->context == NULL ); + + /* bind context to buffer */ + pc->currentBuffer = buffer; + buffer->context = pc; + + /* update the context's packing fields with those from the buffer */ + pc->buffer = *buffer; /* struct copy */ +} + +#ifndef IN_RING0 +/* This is useful for debugging packer problems */ +void crPackSetBufferDEBUG( const char *file, int line, CRPackContext *pc, CRPackBuffer *buffer) + +{ + crPackSetBuffer( pc, buffer ); + /* record debugging info */ + pc->file = crStrdup(file); + pc->line = line; +} +#endif + +/* + * Release the buffer currently attached to the context. + * Update/resync data structures. + */ +void crPackReleaseBuffer( CRPackContext *pc ) +{ + CRPackBuffer *buf; + CRASSERT( pc ); + + if (!pc->currentBuffer) { + crWarning("crPackReleaseBuffer called with no current buffer"); + return; /* nothing to do */ + } + + CRASSERT( pc->currentBuffer->context == pc ); + + /* buffer to release */ + buf = pc->currentBuffer; + + /* copy context's fields back into the buffer to update it */ + *buf = pc->buffer; /* struct copy */ + + /* unbind buffer from context */ + buf->context = NULL; + pc->currentBuffer = NULL; + + /* zero-out context's packing fields just to be safe */ + crMemZero(&(pc->buffer), sizeof(pc->buffer)); + + /* update the debugging fields */ + if (pc->file) + crFree(pc->file); + pc->file = NULL; + pc->line = -1; +} + +void crPackFlushFunc( CRPackContext *pc, CRPackFlushFunc ff ) +{ + pc->Flush = ff; +} + +void crPackFlushArg( CRPackContext *pc, void *flush_arg ) +{ + pc->flush_arg = flush_arg; +} + +void crPackSendHugeFunc( CRPackContext *pc, CRPackSendHugeFunc shf ) +{ + pc->SendHuge = shf; +} + +/* + * This basically resets the buffer attached to <pc> to the default, empty + * state. + */ +void crPackResetPointers( CRPackContext *pc ) +{ + const GLboolean geom_only = pc->buffer.geometry_only; /* save this flag */ + const GLboolean holds_BeginEnd = pc->buffer.holds_BeginEnd; + const GLboolean in_BeginEnd = pc->buffer.in_BeginEnd; + const GLboolean canBarf = pc->buffer.canBarf; + CRPackBuffer *buf = pc->currentBuffer; + CRASSERT(buf); + crPackInitBuffer( buf, buf->pack, buf->size, buf->mtu +#ifdef IN_RING0 + , 0 +#endif + ); + pc->buffer.geometry_only = geom_only; /* restore the flag */ + pc->buffer.holds_BeginEnd = holds_BeginEnd; + pc->buffer.in_BeginEnd = in_BeginEnd; + pc->buffer.canBarf = canBarf; +} + + +/** + * Return max number of opcodes that'll fit in the given buffer size. + * Each opcode has at least a 1-word payload, so opcodes can occupy at most + * 20% of the space. + */ +int +crPackMaxOpcodes( int buffer_size ) +{ + int n = ( buffer_size - sizeof(CRMessageOpcodes) ) / 5; + /* Don't forget to add one here in case the buffer size is not + * divisible by 4. Thanks to Ken Moreland for finding this. + */ + n++; + /* round up to multiple of 4 */ + n = (n + 0x3) & (~0x3); + return n; +} + + +/** + * Return max number of data bytes that'll fit in the given buffer size. + */ +int +crPackMaxData( int buffer_size ) +{ + int n = buffer_size - sizeof(CRMessageOpcodes); + n -= crPackMaxOpcodes(buffer_size); + return n; +} + + +/** + * Initialize the given CRPackBuffer object. + * The buffer may or may not be currently bound to a CRPackContext. + * + * Opcodes and operands are packed into a buffer in a special way. + * Opcodes start at opcode_start and go downward in memory while operands + * start at data_start and go upward in memory. The buffer is full when we + * either run out of opcode space or operand space. + * + * Diagram (memory addresses increase upward): + * + * data_end -> | | <- buf->pack + buf->size + * +---------+ + * | | + * | | + * | operands| + * | | + * | | + * data_start -> +---------+ + * opcode_start -> | | + * | | + * | opcodes | + * | | + * | | + * opcode_end -> +---------+ <- buf->pack + * + * \param buf the CRPackBuffer to initialize + * \param pack the address of the buffer for packing opcodes/operands. + * \param size size of the buffer, in bytes + * \param mtu max transmission unit size, in bytes. When the buffer + * has 'mtu' bytes in it, we have to send it. The MTU might + * be somewhat smaller than the buffer size. + */ +void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu +#ifdef IN_RING0 + , unsigned int num_opcodes +#endif + ) +{ +#ifndef IN_RING0 + unsigned int num_opcodes; +#endif + + CRASSERT(mtu <= size); + + buf->size = size; + buf->mtu = mtu; + buf->pack = pack; + +#ifdef IN_RING0 + if(num_opcodes) + { + num_opcodes = (num_opcodes + 0x3) & (~0x3); + } + else +#endif + { + num_opcodes = crPackMaxOpcodes( buf->size ); + } + + buf->data_start = + (unsigned char *) buf->pack + num_opcodes + sizeof(CRMessageOpcodes); + buf->data_current = buf->data_start; + buf->data_end = (unsigned char *) buf->pack + buf->size; + + buf->opcode_start = buf->data_start - 1; + buf->opcode_current = buf->opcode_start; + buf->opcode_end = buf->opcode_start - num_opcodes; + + buf->geometry_only = GL_FALSE; + buf->holds_BeginEnd = GL_FALSE; + buf->in_BeginEnd = GL_FALSE; + buf->canBarf = GL_FALSE; + + if (buf->context) { + /* Also reset context's packing fields */ + CRPackContext *pc = buf->context; + CRASSERT(pc->currentBuffer == buf); + /*crMemcpy( &(pc->buffer), buf, sizeof(*buf) );*/ + pc->buffer = *buf; + } +} + + +int crPackCanHoldBuffer( CR_PACKER_CONTEXT_ARGDECL const CRPackBuffer *src ) +{ + const int num_data = crPackNumData(src); + const int num_opcode = crPackNumOpcodes(src); + int res; + CR_GET_PACKER_CONTEXT(pc); + CR_LOCK_PACKER_CONTEXT(pc); + res = crPackCanHoldOpcode( pc, num_opcode, num_data ); + CR_UNLOCK_PACKER_CONTEXT(pc); + return res; +} + + +int crPackCanHoldBoundedBuffer( CR_PACKER_CONTEXT_ARGDECL const CRPackBuffer *src ) +{ + const int len_aligned = (src->data_current - src->opcode_current - 1 + 3) & ~3; + CR_GET_PACKER_CONTEXT(pc); + /* 24 is the size of the bounds-info packet... */ + return crPackCanHoldOpcode( pc, 1, len_aligned + 24 ); +} + +void crPackAppendBuffer( CR_PACKER_CONTEXT_ARGDECL const CRPackBuffer *src ) +{ + CR_GET_PACKER_CONTEXT(pc); + const int num_data = crPackNumData(src); + const int num_opcode = crPackNumOpcodes(src); + + CRASSERT(num_data >= 0); + CRASSERT(num_opcode >= 0); + + CR_LOCK_PACKER_CONTEXT(pc); + + /* don't append onto ourself! */ + CRASSERT(pc->currentBuffer); + CRASSERT(pc->currentBuffer != src); + + if (!crPackCanHoldBuffer(CR_PACKER_CONTEXT_ARG src)) + { + if (src->holds_BeginEnd) + { + crWarning( "crPackAppendBuffer: overflowed the destination!" ); + CR_UNLOCK_PACKER_CONTEXT(pc); + return; + } + else + { + crError( "crPackAppendBuffer: overflowed the destination!" ); + CR_UNLOCK_PACKER_CONTEXT(pc); + } + } + + /* Copy the buffer data/operands which are at the head of the buffer */ + crMemcpy( pc->buffer.data_current, src->data_start, num_data ); + pc->buffer.data_current += num_data; + + /* Copy the buffer opcodes which are at the tail of the buffer */ + CRASSERT( pc->buffer.opcode_current - num_opcode >= pc->buffer.opcode_end ); + crMemcpy( pc->buffer.opcode_current + 1 - num_opcode, src->opcode_current + 1, + num_opcode ); + pc->buffer.opcode_current -= num_opcode; + pc->buffer.holds_BeginEnd |= src->holds_BeginEnd; + pc->buffer.in_BeginEnd = src->in_BeginEnd; + pc->buffer.holds_List |= src->holds_List; + CR_UNLOCK_PACKER_CONTEXT(pc); +} + + +void +crPackAppendBoundedBuffer( CR_PACKER_CONTEXT_ARGDECL const CRPackBuffer *src, const CRrecti *bounds ) +{ + CR_GET_PACKER_CONTEXT(pc); + const GLbyte *payload = (const GLbyte *) src->opcode_current + 1; + const int num_opcodes = crPackNumOpcodes(src); + const int length = src->data_current - src->opcode_current - 1; + + CRASSERT(pc); + CR_LOCK_PACKER_CONTEXT(pc); + CRASSERT(pc->currentBuffer); + CRASSERT(pc->currentBuffer != src); + + /* + * payload points to the block of opcodes immediately followed by operands. + */ + + if ( !crPackCanHoldBoundedBuffer( CR_PACKER_CONTEXT_ARG src ) ) + { + if (src->holds_BeginEnd) + { + crWarning( "crPackAppendBoundedBuffer: overflowed the destination!" ); + CR_UNLOCK_PACKER_CONTEXT(pc); + return; + } + else + { + crError( "crPackAppendBoundedBuffer: overflowed the destination!" ); + CR_UNLOCK_PACKER_CONTEXT(pc); + } + } + + if (pc->swapping) + crPackBoundsInfoCRSWAP( CR_PACKER_CONTEXT_ARG bounds, payload, length, num_opcodes ); + else + crPackBoundsInfoCR( CR_PACKER_CONTEXT_ARG bounds, payload, length, num_opcodes ); + + pc->buffer.holds_BeginEnd |= src->holds_BeginEnd; + pc->buffer.in_BeginEnd = src->in_BeginEnd; + pc->buffer.holds_List |= src->holds_List; + CR_UNLOCK_PACKER_CONTEXT(pc); +} + + +#ifndef CHROMIUM_THREADSAFE +static unsigned char *sanityCheckPointer = NULL; +#endif + + +/* + * Allocate space for a command that might be very large, such as + * glTexImage2D or glBufferDataARB call. + * The command buffer _MUST_ then be transmitted by calling crHugePacket. + */ +void *crPackAlloc( CR_PACKER_CONTEXT_ARGDECL unsigned int size ) +{ + CR_GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + + /* include space for the length and make the payload word-aligned */ + size = ( size + sizeof(unsigned int) + 0x3 ) & ~0x3; + + CR_LOCK_PACKER_CONTEXT(pc); + + if ( crPackCanHoldOpcode( pc, 1, size ) ) + { + /* we can just put it in the current buffer */ + CR_GET_BUFFERED_POINTER_NOLOCK(pc, size ); /* NOTE: this sets data_ptr */ + } + else + { + /* Okay, it didn't fit. Maybe it will after we flush. */ + CR_UNLOCK_PACKER_CONTEXT(pc); + pc->Flush( pc->flush_arg ); + CR_LOCK_PACKER_CONTEXT(pc); + if ( crPackCanHoldOpcode( pc, 1, size ) ) + { + CR_GET_BUFFERED_POINTER_NOLOCK(pc, size ); /* NOTE: this sets data_ptr */ + } + else + { + /* It's really way too big, so allocate a temporary packet + * with space for the single opcode plus the payload & + * header. + */ + data_ptr = (unsigned char *) + crAlloc( sizeof(CRMessageOpcodes) + 4 + size ); + + /* skip the header & opcode space */ + data_ptr += sizeof(CRMessageOpcodes) + 4; + } + } + + /* At the top of the function, we added four to the request size and + * rounded it up to the next multiple of four. + * + * At this point, we have: + * + * HIGH MEM | byte size - 1 | \ + * ... | + * ... | - original 'size' bytes for data + * | operand data | | + * return value -> | operand data | / + * | byte 3 | \ + * | byte 2 | |- These bytes will store 'size' + * | byte 1 | | + * data_ptr -> | byte 0 | / + * | CR opcode | <- Set in packspuHuge() + * | unused | + * | unused | + * | unused | + * | CRMessageOpcodes | + * | CRMessageOpcodes | + * ... + * | CRMessageOpcodes | + * | CRMessageOpcodes | + * LOW MEM +------------------+ + */ + + if (pc->swapping) + { + *((unsigned int *) data_ptr) = SWAP32(size); + crDebug( "Just swapped the length, putting %d on the wire!", *((unsigned int *) data_ptr)); + } + else + { + *((unsigned int *) data_ptr) = size; + } +#ifndef CHROMIUM_THREADSAFE + sanityCheckPointer = data_ptr + 4; +#endif + return data_ptr + 4; +} + +#define IS_BUFFERED( packet ) \ + ((unsigned char *) (packet) >= pc->buffer.data_start && \ + (unsigned char *) (packet) < pc->buffer.data_end) + + +/* + * Transmit a packet which was allocated with crPackAlloc. + */ +void crHugePacket( CR_PACKER_CONTEXT_ARGDECL CROpcode opcode, void *packet ) +{ + CR_GET_PACKER_CONTEXT(pc); +#ifndef CHROMIUM_THREADSAFE + CRASSERT(sanityCheckPointer == packet); + sanityCheckPointer = NULL; +#endif + + if ( IS_BUFFERED( packet ) ) + WRITE_OPCODE( pc, opcode ); + else + pc->SendHuge( opcode, packet ); +} + +void crPackFree( CR_PACKER_CONTEXT_ARGDECL void *packet ) +{ + CR_GET_PACKER_CONTEXT(pc); + + if ( IS_BUFFERED( packet ) ) + { + CR_UNLOCK_PACKER_CONTEXT(pc); + return; + } + + CR_UNLOCK_PACKER_CONTEXT(pc); + + /* the pointer passed in doesn't include the space for the single + * opcode (4 bytes because of the alignment requirement) or the + * length field or the header */ + crFree( (unsigned char *) packet - 8 - sizeof(CRMessageOpcodes) ); +} + +void crNetworkPointerWrite( CRNetworkPointer *dst, void *src ) +{ + /* init CRNetworkPointer with invalid values */ + dst->ptrAlign[0] = 0xDeadBeef; + dst->ptrAlign[1] = 0xCafeBabe; + /* copy the pointer's value into the CRNetworkPointer */ + crMemcpy( dst, &src, sizeof(src) ); + + /* if either assertion fails, it probably means that a packer function + * (which returns a value) was called without setting up the writeback + * pointer, or something like that. + */ + CRASSERT(dst->ptrAlign[0] != 0xffffffff); + CRASSERT(dst->ptrAlign[0] != 0xDeadBeef); +} |