311 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * (C) Copyright IBM Corporation 2005
 | 
						|
 * All Rights Reserved.
 | 
						|
 * 
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
 * copy of this software and associated documentation files (the "Software"),
 | 
						|
 * to deal in the Software without restriction, including without limitation
 | 
						|
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 | 
						|
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
						|
 * Software is furnished to do so, subject to the following conditions:
 | 
						|
 * 
 | 
						|
 * The above copyright notice and this permission notice (including the next
 | 
						|
 * paragraph) shall be included in all copies or substantial portions of the
 | 
						|
 * Software.
 | 
						|
 * 
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
 | 
						|
 * IBM,
 | 
						|
 * AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
						|
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 | 
						|
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
						|
 * SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include <X11/Xmd.h>
 | 
						|
#include <GL/gl.h>
 | 
						|
#include <GL/glxproto.h>
 | 
						|
#include <inttypes.h>
 | 
						|
#include "indirect_size.h"
 | 
						|
#include "indirect_size_get.h"
 | 
						|
#include "indirect_dispatch.h"
 | 
						|
#include "glxserver.h"
 | 
						|
#include "glxbyteorder.h"
 | 
						|
#include "singlesize.h"
 | 
						|
#include "glapitable.h"
 | 
						|
#include "glapi.h"
 | 
						|
#include "glthread.h"
 | 
						|
#include "dispatch.h"
 | 
						|
#include "glxext.h"
 | 
						|
#include "indirect_table.h"
 | 
						|
#include "indirect_util.h"
 | 
						|
 | 
						|
 | 
						|
#define __GLX_PAD(a) (((a)+3)&~3)
 | 
						|
 | 
						|
extern xGLXSingleReply __glXReply;
 | 
						|
 | 
						|
 | 
						|
GLint
 | 
						|
__glGetBooleanv_variable_size( GLenum e )
 | 
						|
{
 | 
						|
    if ( e == GL_COMPRESSED_TEXTURE_FORMATS ) {
 | 
						|
	GLint temp;
 | 
						|
 | 
						|
	CALL_GetIntegerv( GET_DISPATCH(),
 | 
						|
			  (GL_NUM_COMPRESSED_TEXTURE_FORMATS, & temp) );
 | 
						|
	return temp;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Get a properly aligned buffer to hold reply data.
 | 
						|
 *
 | 
						|
 * \warning
 | 
						|
 * This function assumes that \c local_buffer is already properly aligned.
 | 
						|
 * It also assumes that \c alignment is a power of two.
 | 
						|
 */
 | 
						|
void *
 | 
						|
__glXGetAnswerBuffer( __GLXclientState * cl, size_t required_size,
 | 
						|
    void * local_buffer, size_t local_size, unsigned alignment )
 | 
						|
{
 | 
						|
    void * buffer = local_buffer;
 | 
						|
    const unsigned mask = alignment - 1;
 | 
						|
 | 
						|
    if ( local_size < required_size ) {
 | 
						|
        const size_t worst_case_size = required_size + alignment;
 | 
						|
        intptr_t  temp_buf;
 | 
						|
 | 
						|
        if ( cl->returnBufSize < worst_case_size ) {
 | 
						|
	    void * temp = xrealloc( cl->returnBuf, worst_case_size );
 | 
						|
	    
 | 
						|
	    if ( temp == NULL ) {
 | 
						|
	        return NULL;
 | 
						|
	    }
 | 
						|
	    
 | 
						|
	    cl->returnBuf = temp;
 | 
						|
	    cl->returnBufSize = worst_case_size;
 | 
						|
	}
 | 
						|
	
 | 
						|
	temp_buf = (intptr_t) cl->returnBuf;
 | 
						|
	temp_buf = (temp_buf + mask) & ~mask;
 | 
						|
	buffer = (void *) temp_buf;
 | 
						|
    }
 | 
						|
 | 
						|
    return buffer;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Send a GLX reply to the client.
 | 
						|
 *
 | 
						|
 * Technically speaking, there are several different ways to encode a GLX
 | 
						|
 * reply.  The primary difference is whether or not certain fields (e.g.,
 | 
						|
 * retval, size, and "pad3") are set.  This function gets around that by
 | 
						|
 * always setting all of the fields to "reasonable" values.  This does no
 | 
						|
 * harm to clients, but it does make the server-side code much more compact.
 | 
						|
 */
 | 
						|
void
 | 
						|
__glXSendReply( ClientPtr client, const void * data, size_t elements,
 | 
						|
    size_t element_size, GLboolean always_array, CARD32 retval )
 | 
						|
{
 | 
						|
    size_t reply_ints = 0;
 | 
						|
 | 
						|
    if ( __glXErrorOccured() ) {
 | 
						|
        elements = 0;
 | 
						|
    }
 | 
						|
    else if ( (elements > 1) || always_array ) {
 | 
						|
        reply_ints = bytes_to_int32(elements * element_size);
 | 
						|
    }
 | 
						|
 | 
						|
    __glXReply.length =         reply_ints;
 | 
						|
    __glXReply.type =           X_Reply;
 | 
						|
    __glXReply.sequenceNumber = client->sequence;
 | 
						|
    __glXReply.size =           elements;
 | 
						|
    __glXReply.retval =         retval;
 | 
						|
 | 
						|
 | 
						|
    /* It is faster on almost always every architecture to just copy the 8
 | 
						|
     * bytes, even when not necessary, than check to see of the value of
 | 
						|
     * elements requires it.  Copying the data when not needed will do no
 | 
						|
     * harm.
 | 
						|
     */
 | 
						|
 | 
						|
    (void) memcpy( & __glXReply.pad3, data, 8 );
 | 
						|
    WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply );
 | 
						|
 | 
						|
    if ( reply_ints != 0 ) {
 | 
						|
        WriteToClient( client, reply_ints * 4, (char *) data );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Send a GLX reply to the client.
 | 
						|
 *
 | 
						|
 * Technically speaking, there are several different ways to encode a GLX
 | 
						|
 * reply.  The primary difference is whether or not certain fields (e.g.,
 | 
						|
 * retval, size, and "pad3") are set.  This function gets around that by
 | 
						|
 * always setting all of the fields to "reasonable" values.  This does no
 | 
						|
 * harm to clients, but it does make the server-side code much more compact.
 | 
						|
 *
 | 
						|
 * \warning
 | 
						|
 * This function assumes that values stored in \c data will be byte-swapped
 | 
						|
 * by the caller if necessary.
 | 
						|
 */
 | 
						|
void
 | 
						|
__glXSendReplySwap( ClientPtr client, const void * data, size_t elements,
 | 
						|
    size_t element_size, GLboolean always_array, CARD32 retval )
 | 
						|
{
 | 
						|
    size_t reply_ints = 0;
 | 
						|
 | 
						|
    if ( __glXErrorOccured() ) {
 | 
						|
        elements = 0;
 | 
						|
    }
 | 
						|
    else if ( (elements > 1) || always_array ) {
 | 
						|
        reply_ints = bytes_to_int32(elements * element_size);
 | 
						|
    }
 | 
						|
 | 
						|
    __glXReply.length =         bswap_32( reply_ints );
 | 
						|
    __glXReply.type =           X_Reply;
 | 
						|
    __glXReply.sequenceNumber = bswap_16( client->sequence );
 | 
						|
    __glXReply.size =           bswap_32( elements );
 | 
						|
    __glXReply.retval =         bswap_32( retval );
 | 
						|
 | 
						|
 | 
						|
    /* It is faster on almost always every architecture to just copy the 8
 | 
						|
     * bytes, even when not necessary, than check to see of the value of
 | 
						|
     * elements requires it.  Copying the data when not needed will do no
 | 
						|
     * harm.
 | 
						|
     */
 | 
						|
 | 
						|
    (void) memcpy( & __glXReply.pad3, data, 8 );
 | 
						|
    WriteToClient( client, sz_xGLXSingleReply, (char *) & __glXReply );
 | 
						|
 | 
						|
    if ( reply_ints != 0 ) {
 | 
						|
        WriteToClient( client, reply_ints * 4, (char *) data );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
get_decode_index(const struct __glXDispatchInfo *dispatch_info,
 | 
						|
		 unsigned opcode)
 | 
						|
{
 | 
						|
    int remaining_bits;
 | 
						|
    int next_remain;
 | 
						|
    const int_fast16_t * const tree = dispatch_info->dispatch_tree;
 | 
						|
    int_fast16_t index;
 | 
						|
 | 
						|
 | 
						|
    remaining_bits = dispatch_info->bits;
 | 
						|
    if (opcode >= (1U << remaining_bits)) {
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    
 | 
						|
    index = 0;
 | 
						|
    for (/* empty */; remaining_bits > 0; remaining_bits = next_remain) {
 | 
						|
	unsigned mask;
 | 
						|
	unsigned child_index;
 | 
						|
 | 
						|
 | 
						|
	/* Calculate the slice of bits used by this node.
 | 
						|
	 * 
 | 
						|
	 * If remaining_bits = 8 and tree[index] = 3, the mask of just the
 | 
						|
	 * remaining bits is 0x00ff and the mask for the remaining bits after
 | 
						|
	 * this node is 0x001f.  By taking 0x00ff & ~0x001f, we get 0x00e0.
 | 
						|
	 * This masks the 3 bits that we would want for this node.
 | 
						|
	 */
 | 
						|
 | 
						|
	next_remain = remaining_bits - tree[index];
 | 
						|
	mask = ((1 << remaining_bits) - 1) &
 | 
						|
	  ~((1 << next_remain) - 1);
 | 
						|
 | 
						|
 | 
						|
	/* Using the mask, calculate the index of the opcode in the node.
 | 
						|
	 * With that index, fetch the index of the next node.
 | 
						|
	 */
 | 
						|
 | 
						|
	child_index = (opcode & mask) >> next_remain;
 | 
						|
	index = tree[index + 1 + child_index];
 | 
						|
 | 
						|
 | 
						|
	/* If the next node is an empty leaf, the opcode is for a non-existant
 | 
						|
	 * function.  We're done.
 | 
						|
	 *
 | 
						|
	 * If the next node is a non-empty leaf, look up the function pointer
 | 
						|
	 * and return it.
 | 
						|
	 */
 | 
						|
 | 
						|
	if (index == EMPTY_LEAF) {
 | 
						|
	    return -1;
 | 
						|
	}
 | 
						|
	else if (IS_LEAF_INDEX(index)) {
 | 
						|
	    unsigned func_index;
 | 
						|
 | 
						|
 | 
						|
	    /* The value stored in the tree for a leaf node is the base of
 | 
						|
	     * the function pointers for that leaf node.  The offset for the
 | 
						|
	     * function for a particular opcode is the remaining bits in the
 | 
						|
	     * opcode.
 | 
						|
	     */
 | 
						|
 | 
						|
	    func_index = -index;
 | 
						|
	    func_index += opcode & ((1 << next_remain) - 1);
 | 
						|
	    return func_index;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    /* We should *never* get here!!!
 | 
						|
     */
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void *
 | 
						|
__glXGetProtocolDecodeFunction(const struct __glXDispatchInfo *dispatch_info,
 | 
						|
			       int opcode, int swapped_version)
 | 
						|
{
 | 
						|
    const int func_index = get_decode_index(dispatch_info, opcode);
 | 
						|
 | 
						|
    return (func_index < 0) 
 | 
						|
	? NULL 
 | 
						|
	: (void *) dispatch_info->dispatch_functions[func_index][swapped_version];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
__glXGetProtocolSizeData(const struct __glXDispatchInfo *dispatch_info,
 | 
						|
			 int opcode, __GLXrenderSizeData *data)
 | 
						|
{
 | 
						|
    if (dispatch_info->size_table != NULL) {
 | 
						|
	const int func_index = get_decode_index(dispatch_info, opcode);
 | 
						|
 | 
						|
	if ((func_index >= 0) 
 | 
						|
	    && (dispatch_info->size_table[func_index][0] != 0)) {
 | 
						|
	    const int var_offset = 
 | 
						|
		dispatch_info->size_table[func_index][1];
 | 
						|
 | 
						|
	    data->bytes = dispatch_info->size_table[func_index][0];
 | 
						|
	    data->varsize = (var_offset != ~0)
 | 
						|
		? dispatch_info->size_func_table[var_offset]
 | 
						|
		: NULL;
 | 
						|
 | 
						|
	    return 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    return -1;
 | 
						|
}
 |