Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | ||
48 | extern xGLXSingleReply __glXReply; | |
49 | ||
50 | GLint | |
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 | */ | |
71 | void * | |
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 unsigned mask = alignment - 1; | |
77 | ||
78 | if (local_size < required_size) { | |
79 | const size_t worst_case_size = required_size + alignment; | |
80 | intptr_t temp_buf; | |
81 | ||
82 | if (cl->returnBufSize < worst_case_size) { | |
83 | void *temp = realloc(cl->returnBuf, worst_case_size); | |
84 | ||
85 | if (temp == NULL) { | |
86 | return NULL; | |
87 | } | |
88 | ||
89 | cl->returnBuf = temp; | |
90 | cl->returnBufSize = worst_case_size; | |
91 | } | |
92 | ||
93 | temp_buf = (intptr_t) cl->returnBuf; | |
94 | temp_buf = (temp_buf + mask) & ~mask; | |
95 | buffer = (void *) temp_buf; | |
96 | } | |
97 | ||
98 | return buffer; | |
99 | } | |
100 | ||
101 | /** | |
102 | * Send a GLX reply to the client. | |
103 | * | |
104 | * Technically speaking, there are several different ways to encode a GLX | |
105 | * reply. The primary difference is whether or not certain fields (e.g., | |
106 | * retval, size, and "pad3") are set. This function gets around that by | |
107 | * always setting all of the fields to "reasonable" values. This does no | |
108 | * harm to clients, but it does make the server-side code much more compact. | |
109 | */ | |
110 | void | |
111 | __glXSendReply(ClientPtr client, const void *data, size_t elements, | |
112 | size_t element_size, GLboolean always_array, CARD32 retval) | |
113 | { | |
114 | size_t reply_ints = 0; | |
115 | ||
116 | if (__glXErrorOccured()) { | |
117 | elements = 0; | |
118 | } | |
119 | else if ((elements > 1) || always_array) { | |
120 | reply_ints = bytes_to_int32(elements * element_size); | |
121 | } | |
122 | ||
123 | __glXReply.length = reply_ints; | |
124 | __glXReply.type = X_Reply; | |
125 | __glXReply.sequenceNumber = client->sequence; | |
126 | __glXReply.size = elements; | |
127 | __glXReply.retval = retval; | |
128 | ||
129 | /* It is faster on almost always every architecture to just copy the 8 | |
130 | * bytes, even when not necessary, than check to see of the value of | |
131 | * elements requires it. Copying the data when not needed will do no | |
132 | * harm. | |
133 | */ | |
134 | ||
135 | (void) memcpy(&__glXReply.pad3, data, 8); | |
136 | WriteToClient(client, sz_xGLXSingleReply, &__glXReply); | |
137 | ||
138 | if (reply_ints != 0) { | |
139 | WriteToClient(client, reply_ints * 4, data); | |
140 | } | |
141 | } | |
142 | ||
143 | /** | |
144 | * Send a GLX reply to the client. | |
145 | * | |
146 | * Technically speaking, there are several different ways to encode a GLX | |
147 | * reply. The primary difference is whether or not certain fields (e.g., | |
148 | * retval, size, and "pad3") are set. This function gets around that by | |
149 | * always setting all of the fields to "reasonable" values. This does no | |
150 | * harm to clients, but it does make the server-side code much more compact. | |
151 | * | |
152 | * \warning | |
153 | * This function assumes that values stored in \c data will be byte-swapped | |
154 | * by the caller if necessary. | |
155 | */ | |
156 | void | |
157 | __glXSendReplySwap(ClientPtr client, const void *data, size_t elements, | |
158 | size_t element_size, GLboolean always_array, CARD32 retval) | |
159 | { | |
160 | size_t reply_ints = 0; | |
161 | ||
162 | if (__glXErrorOccured()) { | |
163 | elements = 0; | |
164 | } | |
165 | else if ((elements > 1) || always_array) { | |
166 | reply_ints = bytes_to_int32(elements * element_size); | |
167 | } | |
168 | ||
169 | __glXReply.length = bswap_32(reply_ints); | |
170 | __glXReply.type = X_Reply; | |
171 | __glXReply.sequenceNumber = bswap_16(client->sequence); | |
172 | __glXReply.size = bswap_32(elements); | |
173 | __glXReply.retval = bswap_32(retval); | |
174 | ||
175 | /* It is faster on almost always every architecture to just copy the 8 | |
176 | * bytes, even when not necessary, than check to see of the value of | |
177 | * elements requires it. Copying the data when not needed will do no | |
178 | * harm. | |
179 | */ | |
180 | ||
181 | (void) memcpy(&__glXReply.pad3, data, 8); | |
182 | WriteToClient(client, sz_xGLXSingleReply, &__glXReply); | |
183 | ||
184 | if (reply_ints != 0) { | |
185 | WriteToClient(client, reply_ints * 4, data); | |
186 | } | |
187 | } | |
188 | ||
189 | static int | |
190 | get_decode_index(const struct __glXDispatchInfo *dispatch_info, unsigned opcode) | |
191 | { | |
192 | int remaining_bits; | |
193 | int next_remain; | |
194 | const int_fast16_t *const tree = dispatch_info->dispatch_tree; | |
195 | int_fast16_t index; | |
196 | ||
197 | remaining_bits = dispatch_info->bits; | |
198 | if (opcode >= (1U << remaining_bits)) { | |
199 | return -1; | |
200 | } | |
201 | ||
202 | index = 0; | |
203 | for ( /* empty */ ; remaining_bits > 0; remaining_bits = next_remain) { | |
204 | unsigned mask; | |
205 | unsigned child_index; | |
206 | ||
207 | /* Calculate the slice of bits used by this node. | |
208 | * | |
209 | * If remaining_bits = 8 and tree[index] = 3, the mask of just the | |
210 | * remaining bits is 0x00ff and the mask for the remaining bits after | |
211 | * this node is 0x001f. By taking 0x00ff & ~0x001f, we get 0x00e0. | |
212 | * This masks the 3 bits that we would want for this node. | |
213 | */ | |
214 | ||
215 | next_remain = remaining_bits - tree[index]; | |
216 | mask = ((1 << remaining_bits) - 1) & ~((1 << next_remain) - 1); | |
217 | ||
218 | /* Using the mask, calculate the index of the opcode in the node. | |
219 | * With that index, fetch the index of the next node. | |
220 | */ | |
221 | ||
222 | child_index = (opcode & mask) >> next_remain; | |
223 | index = tree[index + 1 + child_index]; | |
224 | ||
225 | /* If the next node is an empty leaf, the opcode is for a non-existant | |
226 | * function. We're done. | |
227 | * | |
228 | * If the next node is a non-empty leaf, look up the function pointer | |
229 | * and return it. | |
230 | */ | |
231 | ||
232 | if (index == EMPTY_LEAF) { | |
233 | return -1; | |
234 | } | |
235 | else if (IS_LEAF_INDEX(index)) { | |
236 | unsigned func_index; | |
237 | ||
238 | /* The value stored in the tree for a leaf node is the base of | |
239 | * the function pointers for that leaf node. The offset for the | |
240 | * function for a particular opcode is the remaining bits in the | |
241 | * opcode. | |
242 | */ | |
243 | ||
244 | func_index = -index; | |
245 | func_index += opcode & ((1 << next_remain) - 1); | |
246 | return func_index; | |
247 | } | |
248 | } | |
249 | ||
250 | /* We should *never* get here!!! | |
251 | */ | |
252 | return -1; | |
253 | } | |
254 | ||
255 | void * | |
256 | __glXGetProtocolDecodeFunction(const struct __glXDispatchInfo *dispatch_info, | |
257 | int opcode, int swapped_version) | |
258 | { | |
259 | const int func_index = get_decode_index(dispatch_info, opcode); | |
260 | ||
261 | return (func_index < 0) | |
262 | ? NULL | |
263 | : (void *) dispatch_info-> | |
264 | dispatch_functions[func_index][swapped_version]; | |
265 | } | |
266 | ||
267 | int | |
268 | __glXGetProtocolSizeData(const struct __glXDispatchInfo *dispatch_info, | |
269 | int opcode, __GLXrenderSizeData * data) | |
270 | { | |
271 | if (dispatch_info->size_table != NULL) { | |
272 | const int func_index = get_decode_index(dispatch_info, opcode); | |
273 | ||
274 | if ((func_index >= 0) | |
275 | && (dispatch_info->size_table[func_index][0] != 0)) { | |
276 | const int var_offset = dispatch_info->size_table[func_index][1]; | |
277 | ||
278 | data->bytes = dispatch_info->size_table[func_index][0]; | |
279 | data->varsize = (var_offset != ~0) | |
280 | ? dispatch_info->size_func_table[var_offset] | |
281 | : NULL; | |
282 | ||
283 | return 0; | |
284 | } | |
285 | } | |
286 | ||
287 | return -1; | |
288 | } |