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 }