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