1/*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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, sublicense,
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 including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. 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 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <GL/gl.h>
36#include "glxserver.h"
37#include "GL/glxproto.h"
38#include "unpack.h"
39#include "indirect_size.h"
40#include "indirect_reqsize.h"
41
42#define SWAPL(a) \
43  (((a & 0xff000000U)>>24) | ((a & 0xff0000U)>>8) | \
44   ((a & 0xff00U)<<8) | ((a & 0xffU)<<24))
45
46int __glXMap1dReqSize( const GLbyte *pc, Bool swap, int reqlen )
47{
48    GLenum target;
49    GLint order;
50
51    target = *(GLenum*) (pc + 16);
52    order = *(GLint*) (pc + 20);
53    if (swap) {
54	target = SWAPL( target );
55	order = SWAPL( order );
56    }
57    if (order < 1)
58        return -1;
59    return safe_mul(8, safe_mul(__glMap1d_size(target), order));
60}
61
62int __glXMap1fReqSize( const GLbyte *pc, Bool swap, int reqlen )
63{
64    GLenum target;
65    GLint order;
66
67    target = *(GLenum *)(pc + 0);
68    order = *(GLint *)(pc + 12);
69    if (swap) {
70	target = SWAPL( target );
71	order = SWAPL( order );
72    }
73    if (order < 1)
74        return -1;
75    return safe_mul(4, safe_mul(__glMap1f_size(target), order));
76}
77
78static int Map2Size(int k, int majorOrder, int minorOrder)
79{
80    if (majorOrder < 1 || minorOrder < 1)
81         return -1;
82    return safe_mul(k, safe_mul(majorOrder, minorOrder));
83}
84
85int __glXMap2dReqSize( const GLbyte *pc, Bool swap, int reqlen )
86{
87    GLenum target;
88    GLint uorder, vorder;
89
90    target = *(GLenum *)(pc + 32);
91    uorder = *(GLint *)(pc + 36);
92    vorder = *(GLint *)(pc + 40);
93    if (swap) {
94	target = SWAPL( target );
95	uorder = SWAPL( uorder );
96	vorder = SWAPL( vorder );
97    }
98    return safe_mul(8, Map2Size(__glMap2d_size(target), uorder, vorder));
99}
100
101int __glXMap2fReqSize( const GLbyte *pc, Bool swap, int reqlen )
102{
103    GLenum target;
104    GLint uorder, vorder;
105
106    target = *(GLenum *)(pc + 0);
107    uorder = *(GLint *)(pc + 12);
108    vorder = *(GLint *)(pc + 24);
109    if (swap) {
110	target = SWAPL( target );
111	uorder = SWAPL( uorder );
112	vorder = SWAPL( vorder );
113    }
114    return safe_mul(4, Map2Size(__glMap2f_size(target), uorder, vorder));
115}
116
117/**
118 * Calculate the size of an image.
119 *
120 * The size of an image sent to the server from the client or sent from the
121 * server to the client is calculated.  The size is based on the dimensions
122 * of the image, the type of pixel data, padding in the image, and the
123 * alignment requirements of the image.
124 *
125 * \param format       Format of the pixels.  Same as the \c format parameter
126 *                     to \c glTexImage1D
127 * \param type         Type of the pixel data.  Same as the \c type parameter
128 *                     to \c glTexImage1D
129 * \param target       Typically the texture target of the image.  If the
130 *                     target is one of \c GL_PROXY_*, the size returned is
131 *                     always zero. For uses that do not have a texture target
132 *                     (e.g, glDrawPixels), zero should be specified.
133 * \param w            Width of the image data.  Must be >= 1.
134 * \param h            Height of the image data.  Must be >= 1, even for 1D
135 *                     images.
136 * \param d            Depth of the image data.  Must be >= 1, even for 1D or
137 *                     2D images.
138 * \param imageHeight  If non-zero, defines the true height of a volumetric
139 *                     image.  This value will be used instead of \c h for
140 *                     calculating the size of the image.
141 * \param rowLength    If non-zero, defines the true width of an image.  This
142 *                     value will be used instead of \c w for calculating the
143 *                     size of the image.
144 * \param skipImages   Number of extra layers of image data in a volumtric
145 *                     image that are to be skipped before the real data.
146 * \param skipRows     Number of extra rows of image data in an image that are
147 *                     to be skipped before the real data.
148 * \param alignment    Specifies the alignment for the start of each pixel row
149 *                     in memory.  This value must be one of 1, 2, 4, or 8.
150 *
151 * \returns
152 * The size of the image is returned.  If the specified \c format and \c type
153 * are invalid, -1 is returned.  If \c target is one of \c GL_PROXY_*, zero
154 * is returned.
155 */
156int __glXImageSize( GLenum format, GLenum type, GLenum target,
157		    GLsizei w, GLsizei h, GLsizei d,
158		    GLint imageHeight, GLint rowLength,
159		    GLint skipImages, GLint skipRows, GLint alignment )
160{
161    GLint bytesPerElement, elementsPerGroup, groupsPerRow;
162    GLint groupSize, rowSize, padding, imageSize;
163
164    if (w == 0 || h == 0 || d == 0)
165        return 0;
166
167    if (w < 0 || h < 0 || d < 0 ||
168	(type == GL_BITMAP &&
169	 (format != GL_COLOR_INDEX && format != GL_STENCIL_INDEX))) {
170	return -1;
171    }
172
173    /* proxy targets have no data */
174    switch( target ) {
175    case GL_PROXY_TEXTURE_1D:
176    case GL_PROXY_TEXTURE_2D:
177    case GL_PROXY_TEXTURE_3D:
178    case GL_PROXY_TEXTURE_4D_SGIS:
179    case GL_PROXY_TEXTURE_CUBE_MAP:
180    case GL_PROXY_TEXTURE_RECTANGLE_ARB:
181    case GL_PROXY_HISTOGRAM:
182    case GL_PROXY_COLOR_TABLE:
183    case GL_PROXY_TEXTURE_COLOR_TABLE_SGI:
184    case GL_PROXY_POST_CONVOLUTION_COLOR_TABLE:
185    case GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE:
186    case GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP:
187	return 0;
188    }
189
190    /* real data has to have real sizes */
191    if (imageHeight < 0 || rowLength < 0 || skipImages < 0 || skipRows < 0)
192        return -1;
193    if (alignment != 1 && alignment != 2 && alignment != 4 && alignment != 8)
194        return -1;
195
196    if (type == GL_BITMAP) {
197	if (rowLength > 0) {
198	    groupsPerRow = rowLength;
199	} else {
200	    groupsPerRow = w;
201	}
202	rowSize = bits_to_bytes(groupsPerRow);
203        if (rowSize < 0)
204            return -1;
205	padding = (rowSize % alignment);
206	if (padding) {
207	    rowSize += alignment - padding;
208	}
209
210        return safe_mul(safe_add(h, skipRows), rowSize);
211    } else {
212	switch(format) {
213	  case GL_COLOR_INDEX:
214	  case GL_STENCIL_INDEX:
215	  case GL_DEPTH_COMPONENT:
216	  case GL_RED:
217	  case GL_GREEN:
218	  case GL_BLUE:
219	  case GL_ALPHA:
220	  case GL_LUMINANCE:
221	  case GL_INTENSITY:
222          case GL_RED_INTEGER_EXT:
223          case GL_GREEN_INTEGER_EXT:
224          case GL_BLUE_INTEGER_EXT:
225          case GL_ALPHA_INTEGER_EXT:
226          case GL_LUMINANCE_INTEGER_EXT:
227	    elementsPerGroup = 1;
228	    break;
229	  case GL_422_EXT:
230	  case GL_422_REV_EXT:
231	  case GL_422_AVERAGE_EXT:
232	  case GL_422_REV_AVERAGE_EXT:
233	  case GL_DEPTH_STENCIL_NV:
234	  case GL_DEPTH_STENCIL_MESA:
235	  case GL_YCBCR_MESA:
236	  case GL_LUMINANCE_ALPHA:
237          case GL_LUMINANCE_ALPHA_INTEGER_EXT:
238	    elementsPerGroup = 2;
239	    break;
240	  case GL_RGB:
241	  case GL_BGR:
242          case GL_RGB_INTEGER_EXT:
243          case GL_BGR_INTEGER_EXT:
244	    elementsPerGroup = 3;
245	    break;
246	  case GL_RGBA:
247	  case GL_BGRA:
248          case GL_RGBA_INTEGER_EXT:
249          case GL_BGRA_INTEGER_EXT:
250	  case GL_ABGR_EXT:
251	    elementsPerGroup = 4;
252	    break;
253	  default:
254	    return -1;
255	}
256	switch(type) {
257	  case GL_UNSIGNED_BYTE:
258	  case GL_BYTE:
259	    bytesPerElement = 1;
260	    break;
261	  case GL_UNSIGNED_BYTE_3_3_2:
262	  case GL_UNSIGNED_BYTE_2_3_3_REV:
263	    bytesPerElement = 1;
264	    elementsPerGroup = 1;
265	    break;
266	  case GL_UNSIGNED_SHORT:
267	  case GL_SHORT:
268	    bytesPerElement = 2;
269	    break;
270	  case GL_UNSIGNED_SHORT_5_6_5:
271	  case GL_UNSIGNED_SHORT_5_6_5_REV:
272	  case GL_UNSIGNED_SHORT_4_4_4_4:
273 	  case GL_UNSIGNED_SHORT_4_4_4_4_REV:
274	  case GL_UNSIGNED_SHORT_5_5_5_1:
275	  case GL_UNSIGNED_SHORT_1_5_5_5_REV:
276	  case GL_UNSIGNED_SHORT_8_8_APPLE:
277	  case GL_UNSIGNED_SHORT_8_8_REV_APPLE:
278	  case GL_UNSIGNED_SHORT_15_1_MESA:
279	  case GL_UNSIGNED_SHORT_1_15_REV_MESA:
280	    bytesPerElement = 2;
281	    elementsPerGroup = 1;
282	    break;
283	  case GL_INT:
284	  case GL_UNSIGNED_INT:
285	  case GL_FLOAT:
286	    bytesPerElement = 4;
287	    break;
288	  case GL_UNSIGNED_INT_8_8_8_8:
289	  case GL_UNSIGNED_INT_8_8_8_8_REV:
290	  case GL_UNSIGNED_INT_10_10_10_2:
291	  case GL_UNSIGNED_INT_2_10_10_10_REV:
292	  case GL_UNSIGNED_INT_24_8_NV:
293	  case GL_UNSIGNED_INT_24_8_MESA:
294	  case GL_UNSIGNED_INT_8_24_REV_MESA:
295	    bytesPerElement = 4;
296	    elementsPerGroup = 1;
297	    break;
298	  default:
299	    return -1;
300	}
301        /* known safe by the switches above, not checked */
302	groupSize = bytesPerElement * elementsPerGroup;
303	if (rowLength > 0) {
304	    groupsPerRow = rowLength;
305	} else {
306	    groupsPerRow = w;
307	}
308        if ((rowSize = safe_mul(groupsPerRow, groupSize)) < 0)
309            return -1;
310	padding = (rowSize % alignment);
311	if (padding) {
312	    rowSize += alignment - padding;
313	}
314
315        if (imageHeight > 0)
316            h = imageHeight;
317        h = safe_add(h, skipRows);
318
319        imageSize = safe_mul(h, rowSize);
320
321        return safe_mul(safe_add(d, skipImages), imageSize);
322    }
323}
324
325
326/* XXX this is used elsewhere - should it be exported from glxserver.h? */
327int __glXTypeSize(GLenum enm)
328{
329  switch(enm) {
330    case GL_BYTE:		return sizeof(GLbyte);
331    case GL_UNSIGNED_BYTE:	return sizeof(GLubyte);
332    case GL_SHORT:		return sizeof(GLshort);
333    case GL_UNSIGNED_SHORT:	return sizeof(GLushort);
334    case GL_INT:		return sizeof(GLint);
335    case GL_UNSIGNED_INT:	return sizeof(GLint);
336    case GL_FLOAT:		return sizeof(GLfloat);
337    case GL_DOUBLE:		return sizeof(GLdouble);
338    default:			return -1;
339  }
340}
341
342int __glXDrawArraysReqSize( const GLbyte *pc, Bool swap, int reqlen )
343{
344    __GLXdispatchDrawArraysHeader *hdr = (__GLXdispatchDrawArraysHeader *) pc;
345    __GLXdispatchDrawArraysComponentHeader *compHeader;
346    GLint numVertexes = hdr->numVertexes;
347    GLint numComponents = hdr->numComponents;
348    GLint arrayElementSize = 0;
349    GLint x, size;
350    int i;
351
352    if (swap) {
353	numVertexes = SWAPL( numVertexes );
354	numComponents = SWAPL( numComponents );
355    }
356
357    pc += sizeof(__GLXdispatchDrawArraysHeader);
358    reqlen -= sizeof(__GLXdispatchDrawArraysHeader);
359
360    size = safe_mul(sizeof(__GLXdispatchDrawArraysComponentHeader),
361                    numComponents);
362    if (size < 0 || reqlen < 0 || reqlen < size)
363        return -1;
364
365    compHeader = (__GLXdispatchDrawArraysComponentHeader *) pc;
366
367    for (i=0; i<numComponents; i++) {
368	GLenum datatype = compHeader[i].datatype;
369	GLint numVals = compHeader[i].numVals;
370	GLint component = compHeader[i].component;
371
372	if (swap) {
373	    datatype = SWAPL( datatype );
374	    numVals = SWAPL( numVals );
375	    component = SWAPL( component );
376	}
377
378	switch (component) {
379	  case GL_VERTEX_ARRAY:
380	  case GL_COLOR_ARRAY:
381	  case GL_TEXTURE_COORD_ARRAY:
382	    break;
383	  case GL_SECONDARY_COLOR_ARRAY:
384	  case GL_NORMAL_ARRAY:
385	    if (numVals != 3) {
386		/* bad size */
387		return -1;
388	    }
389	    break;
390	  case GL_FOG_COORD_ARRAY:
391	  case GL_INDEX_ARRAY:
392	    if (numVals != 1) {
393		/* bad size */
394		return -1;
395	    }
396	    break;
397	  case GL_EDGE_FLAG_ARRAY:
398	    if ((numVals != 1) && (datatype != GL_UNSIGNED_BYTE)) {
399		/* bad size or bad type */
400		return -1;
401	    }
402	    break;
403	  default:
404	    /* unknown component type */
405	    return -1;
406	}
407
408	arrayElementSize += __GLX_PAD(numVals * __glXTypeSize(datatype));
409
410	pc += sizeof(__GLXdispatchDrawArraysComponentHeader);
411    }
412
413    return safe_add(size, safe_mul(numVertexes, arrayElementSize));
414}
415
416int __glXSeparableFilter2DReqSize( const GLbyte *pc, Bool swap, int reqlen )
417{
418    __GLXdispatchConvolutionFilterHeader *hdr =
419			(__GLXdispatchConvolutionFilterHeader *) pc;
420
421    GLint image1size, image2size;
422    GLenum format = hdr->format;
423    GLenum type = hdr->type;
424    GLint w = hdr->width;
425    GLint h = hdr->height;
426    GLint rowLength = hdr->rowLength;
427    GLint alignment = hdr->alignment;
428
429    if (swap) {
430	format = SWAPL( format );
431	type = SWAPL( type );
432	w = SWAPL( w );
433	h = SWAPL( h );
434	rowLength = SWAPL( rowLength );
435	alignment = SWAPL( alignment );
436    }
437
438    /* XXX Should rowLength be used for either or both image? */
439    image1size = __glXImageSize( format, type, 0, w, 1, 1,
440				 0, rowLength, 0, 0, alignment );
441    image2size = __glXImageSize( format, type, 0, h, 1, 1,
442				 0, rowLength, 0, 0, alignment );
443
444    return safe_add(safe_pad(image1size), image2size);
445}
446