xref: /OK3568_Linux_fs/external/xserver/glx/indirect_util.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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