xenocara/xserver/glx/indirect_util.c

294 lines
8.9 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 = realloc(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, &__glXReply);
if (reply_ints != 0) {
WriteToClient(client, reply_ints * 4, 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, &__glXReply);
if (reply_ints != 0) {
WriteToClient(client, reply_ints * 4, 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;
}