indirect_util.c revision f7df2e56
1/*
2 * (C) Copyright IBM Corporation 2005
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
19 * IBM,
20 * AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#ifdef HAVE_DIX_CONFIG_H
27#include <dix-config.h>
28#endif
29
30#include <string.h>
31
32#include <X11/Xmd.h>
33#include <GL/gl.h>
34#include <GL/glxproto.h>
35#include <inttypes.h>
36#include "indirect_size.h"
37#include "indirect_size_get.h"
38#include "indirect_dispatch.h"
39#include "glxserver.h"
40#include "glxbyteorder.h"
41#include "singlesize.h"
42#include "glxext.h"
43#include "indirect_table.h"
44#include "indirect_util.h"
45
46#define __GLX_PAD(a) (((a)+3)&~3)
47
48extern xGLXSingleReply __glXReply;
49
50GLint
51__glGetBooleanv_variable_size(GLenum e)
52{
53    if (e == GL_COMPRESSED_TEXTURE_FORMATS) {
54        GLint temp;
55
56        glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &temp);
57        return temp;
58    }
59    else {
60        return 0;
61    }
62}
63
64/**
65 * Get a properly aligned buffer to hold reply data.
66 *
67 * \warning
68 * This function assumes that \c local_buffer is already properly aligned.
69 * It also assumes that \c alignment is a power of two.
70 */
71void *
72__glXGetAnswerBuffer(__GLXclientState * cl, size_t required_size,
73                     void *local_buffer, size_t local_size, unsigned alignment)
74{
75    void *buffer = local_buffer;
76    const intptr_t mask = alignment - 1;
77
78    if (local_size < required_size) {
79        size_t worst_case_size;
80        intptr_t temp_buf;
81
82        if (required_size < SIZE_MAX - alignment)
83            worst_case_size = required_size + alignment;
84        else
85            return NULL;
86
87        if (cl->returnBufSize < worst_case_size) {
88            void *temp = realloc(cl->returnBuf, worst_case_size);
89
90            if (temp == NULL) {
91                return NULL;
92            }
93
94            cl->returnBuf = temp;
95            cl->returnBufSize = worst_case_size;
96        }
97
98        temp_buf = (intptr_t) cl->returnBuf;
99        temp_buf = (temp_buf + mask) & ~mask;
100        buffer = (void *) temp_buf;
101    }
102
103    return buffer;
104}
105
106/**
107 * Send a GLX reply to the client.
108 *
109 * Technically speaking, there are several different ways to encode a GLX
110 * reply.  The primary difference is whether or not certain fields (e.g.,
111 * retval, size, and "pad3") are set.  This function gets around that by
112 * always setting all of the fields to "reasonable" values.  This does no
113 * harm to clients, but it does make the server-side code much more compact.
114 */
115void
116__glXSendReply(ClientPtr client, const void *data, size_t elements,
117               size_t element_size, GLboolean always_array, CARD32 retval)
118{
119    size_t reply_ints = 0;
120
121    if (__glXErrorOccured()) {
122        elements = 0;
123    }
124    else if ((elements > 1) || always_array) {
125        reply_ints = bytes_to_int32(elements * element_size);
126    }
127
128    __glXReply.length = reply_ints;
129    __glXReply.type = X_Reply;
130    __glXReply.sequenceNumber = client->sequence;
131    __glXReply.size = elements;
132    __glXReply.retval = retval;
133
134    /* It is faster on almost always every architecture to just copy the 8
135     * bytes, even when not necessary, than check to see of the value of
136     * elements requires it.  Copying the data when not needed will do no
137     * harm.
138     */
139
140    (void) memcpy(&__glXReply.pad3, data, 8);
141    WriteToClient(client, sz_xGLXSingleReply, &__glXReply);
142
143    if (reply_ints != 0) {
144        WriteToClient(client, reply_ints * 4, data);
145    }
146}
147
148/**
149 * Send a GLX reply to the client.
150 *
151 * Technically speaking, there are several different ways to encode a GLX
152 * reply.  The primary difference is whether or not certain fields (e.g.,
153 * retval, size, and "pad3") are set.  This function gets around that by
154 * always setting all of the fields to "reasonable" values.  This does no
155 * harm to clients, but it does make the server-side code much more compact.
156 *
157 * \warning
158 * This function assumes that values stored in \c data will be byte-swapped
159 * by the caller if necessary.
160 */
161void
162__glXSendReplySwap(ClientPtr client, const void *data, size_t elements,
163                   size_t element_size, GLboolean always_array, CARD32 retval)
164{
165    size_t reply_ints = 0;
166
167    if (__glXErrorOccured()) {
168        elements = 0;
169    }
170    else if ((elements > 1) || always_array) {
171        reply_ints = bytes_to_int32(elements * element_size);
172    }
173
174    __glXReply.length = bswap_32(reply_ints);
175    __glXReply.type = X_Reply;
176    __glXReply.sequenceNumber = bswap_16(client->sequence);
177    __glXReply.size = bswap_32(elements);
178    __glXReply.retval = bswap_32(retval);
179
180    /* It is faster on almost always every architecture to just copy the 8
181     * bytes, even when not necessary, than check to see of the value of
182     * elements requires it.  Copying the data when not needed will do no
183     * harm.
184     */
185
186    (void) memcpy(&__glXReply.pad3, data, 8);
187    WriteToClient(client, sz_xGLXSingleReply, &__glXReply);
188
189    if (reply_ints != 0) {
190        WriteToClient(client, reply_ints * 4, data);
191    }
192}
193
194static int
195get_decode_index(const struct __glXDispatchInfo *dispatch_info, unsigned opcode)
196{
197    int remaining_bits;
198    int next_remain;
199    const int_fast16_t *const tree = dispatch_info->dispatch_tree;
200    int_fast16_t index;
201
202    remaining_bits = dispatch_info->bits;
203    if (opcode >= (1U << remaining_bits)) {
204        return -1;
205    }
206
207    index = 0;
208    for ( /* empty */ ; remaining_bits > 0; remaining_bits = next_remain) {
209        unsigned mask;
210        unsigned child_index;
211
212        /* Calculate the slice of bits used by this node.
213         *
214         * If remaining_bits = 8 and tree[index] = 3, the mask of just the
215         * remaining bits is 0x00ff and the mask for the remaining bits after
216         * this node is 0x001f.  By taking 0x00ff & ~0x001f, we get 0x00e0.
217         * This masks the 3 bits that we would want for this node.
218         */
219
220        next_remain = remaining_bits - tree[index];
221        mask = ((1 << remaining_bits) - 1) & ~((1 << next_remain) - 1);
222
223        /* Using the mask, calculate the index of the opcode in the node.
224         * With that index, fetch the index of the next node.
225         */
226
227        child_index = (opcode & mask) >> next_remain;
228        index = tree[index + 1 + child_index];
229
230        /* If the next node is an empty leaf, the opcode is for a non-existant
231         * function.  We're done.
232         *
233         * If the next node is a non-empty leaf, look up the function pointer
234         * and return it.
235         */
236
237        if (index == EMPTY_LEAF) {
238            return -1;
239        }
240        else if (IS_LEAF_INDEX(index)) {
241            unsigned func_index;
242
243            /* The value stored in the tree for a leaf node is the base of
244             * the function pointers for that leaf node.  The offset for the
245             * function for a particular opcode is the remaining bits in the
246             * opcode.
247             */
248
249            func_index = -index;
250            func_index += opcode & ((1 << next_remain) - 1);
251            return func_index;
252        }
253    }
254
255    /* We should *never* get here!!!
256     */
257    return -1;
258}
259
260void *
261__glXGetProtocolDecodeFunction(const struct __glXDispatchInfo *dispatch_info,
262                               int opcode, int swapped_version)
263{
264    const int func_index = get_decode_index(dispatch_info, opcode);
265
266    return (func_index < 0)
267        ? NULL
268        : (void *) dispatch_info->
269        dispatch_functions[func_index][swapped_version];
270}
271
272int
273__glXGetProtocolSizeData(const struct __glXDispatchInfo *dispatch_info,
274                         int opcode, __GLXrenderSizeData * data)
275{
276    if (dispatch_info->size_table != NULL) {
277        const int func_index = get_decode_index(dispatch_info, opcode);
278
279        if ((func_index >= 0)
280            && (dispatch_info->size_table[func_index][0] != 0)) {
281            const int var_offset = dispatch_info->size_table[func_index][1];
282
283            data->bytes = dispatch_info->size_table[func_index][0];
284            data->varsize = (var_offset != ~0)
285                ? dispatch_info->size_func_table[var_offset]
286                : NULL;
287
288            return 0;
289        }
290    }
291
292    return -1;
293}
294