1 /*
2  * Copyright (c) 2002-2008 LWJGL Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'LWJGL' nor the names of
17  *   its contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.lwjgl.opengl;
33 
34 import org.lwjgl.BufferUtils;
35 import org.lwjgl.LWJGLUtil;
36 
37 import java.nio.Buffer;
38 import java.nio.FloatBuffer;
39 
40 import static org.lwjgl.opengl.ARBBufferObject.*;
41 import static org.lwjgl.opengl.ATIVertexArrayObject.*;
42 import static org.lwjgl.opengl.EXTAbgr.*;
43 import static org.lwjgl.opengl.EXTBgra.*;
44 import static org.lwjgl.opengl.EXTDirectStateAccess.*;
45 import static org.lwjgl.opengl.GL11.*;
46 import static org.lwjgl.opengl.GL13.*;
47 import static org.lwjgl.opengl.GL15.*;
48 import static org.lwjgl.opengl.NVPathRendering.*;
49 
50 /**
51  * A class to check buffer boundaries in GL methods. Many GL
52  * methods read data from the GL into a native Buffer at its current position. If there is unsufficient space in the buffer when
53  * the call is made then a buffer overflow would otherwise occur and cause unexpected behaviour, a crash, or worse, a security
54  * risk. Therefore in those methods where GL reads data back into a buffer, we will call a bounds check method from this class
55  * to ensure that there is sufficient space in the buffer.
56  * <p/>
57  * Thrown by the debug build library of the LWJGL if any OpenGL operation causes an error.
58  *
59  * @author cix_foo <cix_foo@users.sourceforge.net>
60  * @version $Revision$
61  *          $Id$
62  */
63 class GLChecks {
64 
65 	/** Static methods only! */
GLChecks()66 	private GLChecks() {
67 	}
68 
69 	/** Helper method to ensure that array buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
ensureArrayVBOdisabled(ContextCapabilities caps)70 	static void ensureArrayVBOdisabled(ContextCapabilities caps) {
71 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).arrayBuffer != 0 )
72 			throw new OpenGLException("Cannot use Buffers when Array Buffer Object is enabled");
73 	}
74 
75 	/** Helper method to ensure that array buffer objects are enabled. If they are disabled, we'll throw an OpenGLException */
ensureArrayVBOenabled(ContextCapabilities caps)76 	static void ensureArrayVBOenabled(ContextCapabilities caps) {
77 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).arrayBuffer == 0 )
78 			throw new OpenGLException("Cannot use offsets when Array Buffer Object is disabled");
79 	}
80 
81 	/** Helper method to ensure that element array buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
ensureElementVBOdisabled(ContextCapabilities caps)82 	static void ensureElementVBOdisabled(ContextCapabilities caps) {
83 		if ( LWJGLUtil.CHECKS && StateTracker.getElementArrayBufferBound(caps) != 0 )
84 			throw new OpenGLException("Cannot use Buffers when Element Array Buffer Object is enabled");
85 	}
86 
87 	/** Helper method to ensure that element array buffer objects are enabled. If they are disabled, we'll throw an OpenGLException */
ensureElementVBOenabled(ContextCapabilities caps)88 	static void ensureElementVBOenabled(ContextCapabilities caps) {
89 		if ( LWJGLUtil.CHECKS && StateTracker.getElementArrayBufferBound(caps) == 0 )
90 			throw new OpenGLException("Cannot use offsets when Element Array Buffer Object is disabled");
91 	}
92 
93 	/** Helper method to ensure that array buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
ensureIndirectBOdisabled(ContextCapabilities caps)94 	static void ensureIndirectBOdisabled(ContextCapabilities caps) {
95 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).indirectBuffer != 0 )
96 			throw new OpenGLException("Cannot use Buffers when Draw Indirect Object is enabled");
97 	}
98 
99 	/** Helper method to ensure that array buffer objects are enabled. If they are disabled, we'll throw an OpenGLException */
ensureIndirectBOenabled(ContextCapabilities caps)100 	static void ensureIndirectBOenabled(ContextCapabilities caps) {
101 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).indirectBuffer == 0 )
102 			throw new OpenGLException("Cannot use offsets when Draw Indirect Object is disabled");
103 	}
104 
105 	/** Helper method to ensure that pixel pack buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
ensurePackPBOdisabled(ContextCapabilities caps)106 	static void ensurePackPBOdisabled(ContextCapabilities caps) {
107 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).pixelPackBuffer != 0 )
108 			throw new OpenGLException("Cannot use Buffers when Pixel Pack Buffer Object is enabled");
109 	}
110 
111 	/** Helper method to ensure that pixel pack buffer objects are enabled. If they are disabled, we'll throw an OpenGLException */
ensurePackPBOenabled(ContextCapabilities caps)112 	static void ensurePackPBOenabled(ContextCapabilities caps) {
113 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).pixelPackBuffer == 0 )
114 			throw new OpenGLException("Cannot use offsets when Pixel Pack Buffer Object is disabled");
115 	}
116 
117 	/** Helper method to ensure that pixel unpack buffer objects are disabled. If they are enabled, we'll throw an OpenGLException */
ensureUnpackPBOdisabled(ContextCapabilities caps)118 	static void ensureUnpackPBOdisabled(ContextCapabilities caps) {
119 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).pixelUnpackBuffer != 0 )
120 			throw new OpenGLException("Cannot use Buffers when Pixel Unpack Buffer Object is enabled");
121 	}
122 
123 	/** Helper method to ensure that pixel unpack buffer objects are enabled. If they are disabled, we'll throw an OpenGLException */
ensureUnpackPBOenabled(ContextCapabilities caps)124 	static void ensureUnpackPBOenabled(ContextCapabilities caps) {
125 		if ( LWJGLUtil.CHECKS && StateTracker.getReferences(caps).pixelUnpackBuffer == 0 )
126 			throw new OpenGLException("Cannot use offsets when Pixel Unpack Buffer Object is disabled");
127 	}
128 
129 	/**
130 	 * Calculate the storage required for an image in elements
131 	 *
132 	 * @param format The format of the image (example: GL_RGBA)
133 	 * @param type   The type of the image elements (example: GL_UNSIGNED_BYTE)
134 	 * @param width  The width of the image
135 	 * @param height The height of the image (1 for 1D images)
136 	 * @param depth  The depth of the image (1 for 2D images)
137 	 *
138 	 * @return the size, in elements, of the image
139 	 */
calculateImageStorage(Buffer buffer, int format, int type, int width, int height, int depth)140 	static int calculateImageStorage(Buffer buffer, int format, int type, int width, int height, int depth) {
141 		return LWJGLUtil.CHECKS ? calculateImageStorage(format, type, width, height, depth) >> BufferUtils.getElementSizeExponent(buffer) : 0;
142 	}
143 
calculateTexImage1DStorage(Buffer buffer, int format, int type, int width)144 	static int calculateTexImage1DStorage(Buffer buffer, int format, int type, int width) {
145 		return LWJGLUtil.CHECKS ? calculateTexImage1DStorage(format, type, width) >> BufferUtils.getElementSizeExponent(buffer) : 0;
146 	}
147 
calculateTexImage2DStorage(Buffer buffer, int format, int type, int width, int height)148 	static int calculateTexImage2DStorage(Buffer buffer, int format, int type, int width, int height) {
149 		return LWJGLUtil.CHECKS ? calculateTexImage2DStorage(format, type, width, height) >> BufferUtils.getElementSizeExponent(buffer) : 0;
150 	}
151 
calculateTexImage3DStorage(Buffer buffer, int format, int type, int width, int height, int depth)152 	static int calculateTexImage3DStorage(Buffer buffer, int format, int type, int width, int height, int depth) {
153 		return LWJGLUtil.CHECKS ? calculateTexImage3DStorage(format, type, width, height, depth) >> BufferUtils.getElementSizeExponent(buffer) : 0;
154 	}
155 
156 	/**
157 	 * Calculate the storage required for an image in bytes.
158 	 *
159 	 * @param format The format of the image (example: GL_RGBA)
160 	 * @param type   The type of the image elements (example: GL_UNSIGNED_BYTE)
161 	 * @param width  The width of the image
162 	 * @param height The height of the image (1 for 1D images)
163 	 * @param depth  The depth of the image (1 for 2D images)
164 	 *
165 	 * @return the size, in bytes, of the image
166 	 */
calculateImageStorage(int format, int type, int width, int height, int depth)167 	private static int calculateImageStorage(int format, int type, int width, int height, int depth) {
168 		return calculateBytesPerPixel(format, type) * width * height * depth;
169 	}
170 
calculateTexImage1DStorage(int format, int type, int width)171 	private static int calculateTexImage1DStorage(int format, int type, int width) {
172 		return calculateBytesPerPixel(format, type) * width;
173 	}
174 
calculateTexImage2DStorage(int format, int type, int width, int height)175 	private static int calculateTexImage2DStorage(int format, int type, int width, int height) {
176 		return calculateTexImage1DStorage(format, type, width) * height;
177 	}
178 
calculateTexImage3DStorage(int format, int type, int width, int height, int depth)179 	private static int calculateTexImage3DStorage(int format, int type, int width, int height, int depth) {
180 		return calculateTexImage2DStorage(format, type, width, height) * depth;
181 	}
182 
calculateBytesPerPixel(int format, int type)183 	private static int calculateBytesPerPixel(int format, int type) {
184 		int bpe;
185 		switch ( type ) {
186 			case GL_UNSIGNED_BYTE:
187 			case GL_BYTE:
188 				bpe = 1;
189 				break;
190 			case GL_UNSIGNED_SHORT:
191 			case GL_SHORT:
192 				bpe = 2;
193 				break;
194 			case GL_UNSIGNED_INT:
195 			case GL_INT:
196 			case GL_FLOAT:
197 				bpe = 4;
198 				break;
199 			default:
200 				// TODO: Add more types (like the GL12 types GL_UNSIGNED_INT_8_8_8_8
201 				return 0;
202 			//		throw new IllegalArgumentException("Unknown type " + type);
203 		}
204 		int epp;
205 		switch ( format ) {
206 			case GL_LUMINANCE:
207 			case GL_ALPHA:
208 				epp = 1;
209 				break;
210 
211 			case GL_LUMINANCE_ALPHA:
212 				epp = 2;
213 				break;
214 			case GL_RGB:
215 			case GL_BGR_EXT:
216 				epp = 3;
217 				break;
218 			case GL_RGBA:
219 			case GL_ABGR_EXT:
220 			case GL_BGRA_EXT:
221 				epp = 4;
222 				break;
223 			default:
224 				// TODO: Add more formats. Assuming 4 is too wasteful on buffer sizes where e.g. 1 is enough (like GL_DEPTH_COMPONENT)
225 				return 0;
226 /*				// Assume 4 elements per pixel
227 				epp = 4;*/
228 		}
229 
230 		return bpe * epp;
231 	}
232 
233 	// NV_path_rendering checks
234 
calculateBytesPerCharCode(int type)235 	static int calculateBytesPerCharCode(int type) {
236 		switch ( type ) {
237 			case GL_UNSIGNED_BYTE:
238 			case GL_UTF8_NV:
239 				return 1;
240 			case GL_UNSIGNED_SHORT:
241 			case GL_2_BYTES:
242 			case GL_UTF16_NV:
243 				return 2;
244 			case GL_3_BYTES:
245 				return 3;
246 			case GL_4_BYTES:
247 				return 4;
248 			default:
249 				throw new IllegalArgumentException("Unsupported charcode type: " + type);
250 		}
251 	}
252 
calculateBytesPerPathName(int pathNameType)253 	static int calculateBytesPerPathName(int pathNameType) {
254 		switch ( pathNameType ) {
255 			case GL_BYTE:
256 			case GL_UNSIGNED_BYTE:
257 			case GL_UTF8_NV:
258 				return 1;
259 			case GL_SHORT:
260 			case GL_UNSIGNED_SHORT:
261 			case GL_2_BYTES:
262 			case GL_UTF16_NV:
263 				return 2;
264 			case GL_3_BYTES:
265 				return 3;
266 			case GL_INT:
267 			case GL_UNSIGNED_INT:
268 			case GL_FLOAT:
269 			case GL_4_BYTES:
270 				return 4;
271 			default:
272 				throw new IllegalArgumentException("Unsupported path name type: " + pathNameType);
273 		}
274 	}
275 
calculateTransformPathValues(int transformType)276 	static int calculateTransformPathValues(int transformType) {
277 		switch ( transformType ) {
278 			case GL_NONE:
279 				return 0;
280 			case GL_TRANSLATE_X_NV:
281 			case GL_TRANSLATE_Y_NV:
282 				return 1;
283 			case GL_TRANSLATE_2D_NV:
284 				return 2;
285 			case GL_TRANSLATE_3D_NV:
286 				return 3;
287 			case GL_AFFINE_2D_NV:
288 			case GL_TRANSPOSE_AFFINE_2D_NV:
289 				return 6;
290 			case GL_AFFINE_3D_NV:
291 			case GL_TRANSPOSE_AFFINE_3D_NV:
292 				return 12;
293 			default:
294 				throw new IllegalArgumentException("Unsupported transform type: " + transformType);
295 		}
296 	}
297 
calculatePathColorGenModeElements(int genMode)298 	static int calculatePathColorGenModeElements(int genMode) {
299 		switch ( genMode ) {
300 			case GL_NONE:
301 				return 0;
302 			case GL_CONSTANT:
303 				return 1;
304 			case GL_OBJECT_LINEAR:
305 			case GL_PATH_OBJECT_BOUNDING_BOX_NV:
306 				return 3;
307 			case GL_EYE_LINEAR:
308 				return 4;
309 			default:
310 				throw new IllegalArgumentException(String.format("Unsupported genMode specified: 0x%X", genMode));
311 		}
312 	}
313 
calculatePathColorGenFormatComponents(int colorFormat)314 	static int calculatePathColorGenFormatComponents(int colorFormat) {
315 		switch ( colorFormat ) {
316 			case GL_LUMINANCE:
317 			case GL_INTENSITY:
318 			case GL_ALPHA:
319 				return 1;
320 			case GL_LUMINANCE_ALPHA:
321 				return 2;
322 			case GL_RGB:
323 				return 3;
324 			case GL_RGBA:
325 				return 4;
326 			default:
327 				throw new IllegalArgumentException(String.format("Unsupported colorFormat specified: 0x%X", colorFormat));
328 		}
329 	}
330 
calculateMetricsSize(int metricQueryMask, int stride)331 	static int calculateMetricsSize(int metricQueryMask, int stride) {
332 		if ( LWJGLUtil.DEBUG && (stride < 0 || (stride % 4) != 0) )
333 			throw new IllegalArgumentException("Invalid stride value: " + stride);
334 
335 		final int metrics = Integer.bitCount(metricQueryMask);
336 
337 		if ( LWJGLUtil.DEBUG && (stride >> 2) < metrics )
338 			throw new IllegalArgumentException("The queried metrics do not fit in the specified stride: " + stride);
339 
340 		return stride == 0 ? metrics : (stride >> 2);
341 	}
342 
343 }