1Name 2 3 EXT_vertex_attrib_64bit 4 5Name Strings 6 7 GL_EXT_vertex_attrib_64bit 8 9Contact 10 11 Graham Sellers, AMD (graham.sellers 'at' amd.com) 12 Pat Brown, NVIDIA (pbrown 'at' nvidia.com) 13 14Contributors 15 16 Barthold Lichtenbelt, NVIDIA 17 Bill Licea-Kane, AMD 18 Eric Werness, NVIDIA 19 Graham Sellers, AMD 20 Greg Roth, NVIDIA 21 Jeff Bolz, NVIDIA 22 Nick Haemel, AMD 23 Pierre Boudier, AMD 24 Piers Daniell, NVIDIA 25 26Status 27 28 Shipping. 29 30Version 31 32 Last Modified Date: 03/21/2010 33 Revision: 5 34 35Number 36 37 387 38 39Dependencies 40 41 This extension is written against the OpenGL 3.2 specification 42 (Compatibility Profile). 43 44 This extension is written against version 1.50 (revision 09) of the OpenGL 45 Shading Language Specification. 46 47 OpenGL 3.0 and GLSL 1.30 are required. 48 49 ARB_gpu_shader_fp64 (or equivalent functionality) is required. 50 51 This extension interacts with OpenGL 3.1 implementations not supporting 52 ARB_compatibility and with the core profile of OpenGL 3.2. 53 54 This extension interacts with EXT_direct_state_access. 55 56 This extension interacts with NV_gpu_shader5. 57 58 This extension interacts with NV_vertex_attrib_integer_64bit. 59 60Overview 61 62 This extension provides OpenGL shading language support for vertex shader 63 inputs with 64-bit floating-point components and OpenGL API support for 64 specifying the value of those inputs using vertex array or immediate mode 65 entry points. This builds on the support for general-purpose support for 66 64-bit floating-point values in the ARB_gpu_shader_fp64 extension. 67 68 This extension provides a new class of vertex attribute functions, 69 beginning with "VertexAttribL" ("L" for "long"), that can be used to 70 specify attributes with 64-bit floating-point components. This extension 71 provides no automatic type conversion between attribute and shader 72 variables; single-precision attributes are not automatically converted to 73 double-precision or vice versa. For shader variables with 64-bit 74 component types, the "VertexAttribL" functions must be used to specify 75 attribute values. For other shader variables, the "VertexAttribL" 76 functions must not be used. If a vertex attribute is specified using the 77 wrong attribute function, the values of the corresponding shader input are 78 undefined. This approach requiring matching types is identical to that 79 used for the "VertexAttribI" functions provided by OpenGL 3.0 and the 80 EXT_gpu_shader4 extension. 81 82 Additionally, some vertex shader inputs using the wider 64-bit components 83 may count double against the implementation-dependent limit on the number 84 of vertex shader attribute vectors. A 64-bit scalar or a two-component 85 vector consumes only a single generic vertex attribute; three- and 86 four-component "long" may count as two. This approach is similar to the 87 one used in the current GL where matrix attributes consume multiple 88 attributes. 89 90 Note that 64-bit generic vertex attributes were nominally supported 91 beginning with the introduction of vertex shaders in OpenGL 2.0. However, 92 the OpenGL Shading Language at the time had no support for 64-bit data 93 types, so any such values were automatically converted to 32-bit. 94 95 Support for 64-bit floating-point vertex attributes in this extension can 96 be combined with other extensions. In particular, this extension provides 97 an entry point that can be used with EXT_direct_state_access to directly 98 set state for any vertex array object. Also, the related 99 NV_vertex_attrib_integer_64bit extension provides an entry point to 100 specify bindless vertex attribute arrays with 64-bit components, integer 101 or floating-point. 102 103 104New Procedures and Functions 105 106 void VertexAttribL1dEXT(uint index, double x); 107 void VertexAttribL2dEXT(uint index, double x, double y); 108 void VertexAttribL3dEXT(uint index, double x, double y, double z); 109 void VertexAttribL4dEXT(uint index, double x, double y, double z, double w); 110 void VertexAttribL1dvEXT(uint index, const double *v); 111 void VertexAttribL2dvEXT(uint index, const double *v); 112 void VertexAttribL3dvEXT(uint index, const double *v); 113 void VertexAttribL4dvEXT(uint index, const double *v); 114 115 void VertexAttribLPointerEXT(uint index, int size, enum type, sizei stride, 116 const void *pointer); 117 118 void GetVertexAttribLdvEXT(uint index, enum pname, double *params); 119 120 void VertexArrayVertexAttribLOffsetEXT(uint vaobj, uint buffer, 121 uint index, int size, 122 enum type, sizei stride, 123 intptr offset); 124 125 (note: VertexArrayVertexAttribLOffsetEXT is provided only if 126 EXT_direct_state_access_memory is supported.) 127 128New Tokens 129 130 Returned in the <type> parameter of GetActiveAttrib: 131 132 DOUBLE 133 DOUBLE_VEC2_EXT 0x8FFC 134 DOUBLE_VEC3_EXT 0x8FFD 135 DOUBLE_VEC4_EXT 0x8FFE 136 DOUBLE_MAT2_EXT 0x8F46 137 DOUBLE_MAT3_EXT 0x8F47 138 DOUBLE_MAT4_EXT 0x8F48 139 DOUBLE_MAT2x3_EXT 0x8F49 140 DOUBLE_MAT2x4_EXT 0x8F4A 141 DOUBLE_MAT3x2_EXT 0x8F4B 142 DOUBLE_MAT3x4_EXT 0x8F4C 143 DOUBLE_MAT4x2_EXT 0x8F4D 144 DOUBLE_MAT4x3_EXT 0x8F4E 145 146 Note: These enums are defined in ARB_gpu_shader_fp64, which is required 147 by this extension. They are included here only for completeness. 148 149Additions to Chapter 2 of the OpenGL 3.2 (Compatibility Profile) Specification 150(OpenGL Operation) 151 152 Modify Section 2.7, Vertex Specification (p. 24) 153 154 (delete third paragraph, p. 33, beginning with "The resulting attribute 155 values are undefined") 156 157 (rework the description of the VertexAttribI* commands, and add support 158 for new VertexAttribL* commands, p. 33) 159 160 To load values into a generic shader attribute declared as a signed or 161 unsigned integer or integer vector, use the commands 162 163 void VertexAttribI{1,2,3,4}{i,ui}( uint index, T values ); 164 void VertexAttribI{1,2,3,4}{i,ui}v( uint index, T values ); 165 void VertexAttribI4{b,s,ub,us}v( uint index, T values ); 166 167 These commands specify values that are extended to full signed or unsigned 168 integers, then loaded into the generic attribute at slot index in the same 169 fashion as described above. 170 171 To load values into a generic shader attribute declared as a double, or 172 into vectors or matrices thereof, use the commands 173 174 void VertexAttribL{1,2,3,4}dEXT(uint index, T values); 175 void VertexAttribL{1,2,3,4}dvEXT(uint index, T values); 176 177 These commands specify one, two, three or four values. Note that attribute 178 variables declared with "double" types must be loaded with 179 VertexAttribL*d{v}EXT; loading attributes with VertexAttrib*d{v} will 180 produce undefined results. 181 182 For all VertexAttrib* commands, the error INVALID_VALUE is generated if 183 <index> is greater than or equal to MAX_VERTEX_ATTRIBS. 184 185 The full set of VertexAttrib* commands specify generic attributes with 186 components one of six data types: 187 188 * floating-point values (VertexAttrib*), 189 * signed or unsigned integers (VertexAttribI*), and 190 * double-precision floating-point values (VertexAttribL*d*) 191 192 The values loaded into a shader attribute variable bound to generic 193 attribute <index> are undefined if the data type of the attribute 194 components specified by the most recent VertexAttrib* command do not match 195 the data type of the variable. 196 197 198 Modify Section 2.8, Vertex Arrays, p. 34 199 200 (insert new paragraph after first paragraph, p. 37) 201 202 The command 203 204 void VertexAttribLPointerEXT(uint index, int size, enum type, 205 sizei stride, const void *pointer); 206 207 specifies state for a generic vertex attribute array associated with a 208 shader attribute variable declared with 64-bit double precision components. 209 <type> must be DOUBLE. <index>, <size>, and <stride> behave as defined in 210 all other vertex commands; <size> may be one, two, three or four. 211 212 Each component of an array specified by VertexAttribLPointerEXT will be 213 encoded into one or more generic attribute components as specified for the 214 VertexAttribL* commands in Section 2.7. The error INVALID_VALUE is 215 generated if <index> is greater than or equal to MAX_VERTEX_ATTRIBS. 216 217 218 (modify pseudo-code, p. 38, to handle VertexAttribLPointerEXT) 219 220 ... 221 for (j = 1; j < genericAttributes; j++) { 222 if (generic vertex attribute j array enabled) { 223 if (generic attribute j array set by VertexAttribLPointerEXT) { 224 VertexAttribL[size][type]v(j, generic vertex attribute j 225 array element i); 226 } else if (generic attribute j array set by VertexAttribIPointer) { 227 VertexAttribI[size][type]v(j, generic vertex attribute j 228 array element i); 229 } else if (generic vertex attribute j array normalization flag 230 is set, and type is not FLOAT or DOUBLE) { 231 VertexAttrib[size]N[type]v(j, generic vertex attribute j 232 array element i); 233 } else { 234 VertexAttrib[size][type]v(j, generic vertex attribute j 235 array element i); 236 } 237 } 238 } 239 240 if (generic attribute 0 array enabled) { 241 if (generic attribute 0 array set by VertexAttribLPointers) { 242 VertexAttribL[size][type]v(0, generic vertex attribute 0 243 array element i); 244 } else if (generic attribute 0 array set by VertexAttribIPointer) { 245 VertexAttribI[size][type]v(0, generic vertex attribute 0 246 array element i); 247 } else if (generic vertex attribute 0 array normalization flag 248 is set, and type is not FLOAT or DOUBLE) { 249 VertexAttrib[size]N[type]v(0, generic vertex attribute 0 250 array element i); 251 } else { 252 VertexAttrib[size][type]v(0, generic vertex attribute 0 253 array element i); 254 } 255 } else if (vertex array enabled) { 256 ... 257 258 259 Modify the "Add to the end of Section 2.10 (Vertex Array Objects)" section 260 of EXT_direct_state_access 261 262 (add a new function prototype to the initial list of commands) 263 264 void VertexArrayVertexAttribLOffsetEXT(uint vaobj, uint buffer, 265 uint index, int size, 266 enum type, sizei stride, 267 intptr offset); 268 269 (No edits are made to the language added in this section. The same 270 general rules described in EXT_direct_state_access apply here -- <vaobj> 271 identifies a vertex array object used instead of the currently bound one, 272 <buffer> is used in place of the buffer object bound to ARRAY_BUFFER, and 273 the command otherwise behaves like VertexAttribLPointerEXT with <pointer> 274 set to <offset>.) 275 276 277 Modify Section 2.14.3, Vertex Attributes, p. 86 278 279 (replace last paragraph, p. 86) 280 281 When an attribute variable declared using one of the scalar or vector data 282 types enumerated in Table X.1 and is bound to a generic attribute index 283 <i>, its value(s) are taken from the components of generic attribute <i>. 284 Scalars are extracted from the x component; two-, three-, and 285 four-component vectors are extracted from the, (x, y), (x, y, z), or (x, 286 y, z, w) components, respectively. 287 288 Data type Command 289 ------------------------------- ---------------------------------- 290 int int8_t int16_t int32_t VertexAttribI1i 291 ivec2 i8vec2 i16vec2 i32vec2 VertexAttribI2i 292 ivec3 i8vec3 i16vec3 i32vec3 VertexAttribI3i 293 ivec4 i8vec4 i16vec4 i32vec4 VertexAttribI4i 294 295 uint uint8_t uint16_t uint32_t VertexAttribI1ui 296 ivec2 i8vec2 i16vec2 u32vec2 VertexAttribI2ui 297 ivec3 i8vec3 i16vec3 u32vec3 VertexAttribI3ui 298 uvec4 u8vec4 u16vec4 u32vec4 VertexAttribI4ui 299 300 float float16_t float32_t VertexAttrib1{f,b,s,i,ub,us,ui,d} 301 vec2 f16vec2 f32vec2 VertexAttrib2{f,b,s,i,ub,us,ui,d} 302 vec3 f16vec3 f32vec3 VertexAttrib3{f,b,s,i,ub,us,ui,d} 303 vec4 f16vec4 f32vec4 VertexAttrib4{f,b,s,i,ub,us,ui,d} 304 305 double float64_t VertexAttribL1dEXT 306 dvec2 f64vec2 VertexAttribL2dEXT 307 dvec3 f64vec3 VertexAttribL3dEXT 308 dvec4 f64vec4 VertexAttribL4dEXT 309 310 311 Table X.1: Scalar and vector vertex attribute types and VertexAttrib* 312 commands used to set the values of the corresponding generic attribute. 313 314 For the 64-bit double precision types listed in Table X.1, no default 315 attribute values are provided if the values of the vertex attribute variable 316 are specified with fewer components than required for the attribute 317 variable. For example, the fourth component of a variable of type dvec4 318 will be undefined if specified using VertexAttribL3dvEXT or using a vertex 319 array specified with VertexAttribLPointerEXT and a size of three. 320 321 322 (modify the second paragraph, p. 87) ... exceeds MAX_VERTEX_ATTRIBS. For 323 the purposes of this comparison, attribute variables of the type dvec3, 324 dvec4, dmat2x3, dmat2x4, dmat3, dmat3x4, dmat4x3, and dmat4 may count as 325 consuming twice as many attributes as equivalent single-precision types. 326 327 (extend the list of types in the first paragraph, p. 88) 328 ... UNSIGNED_INT_VEC3, UNSIGNED_INT_VEC4, DOUBLE, DOUBLE_VEC2, 329 DOUBLE_VEC3, DOUBLE_VEC4, DOUBLE_MAT2, DOUBLE_MAT3, DOUBLE_MAT4, 330 DOUBLE_MAT2x3, DOUBLE_MAT2x4, DOUBLE_MAT3x2, DOUBLE_MAT3x4, DOUBLE_MAT4x2, 331 or DOUBLE_MAT4x3. 332 333 (add the following entries to table 2.13: OpenGL Shading Language type 334 tokens returned by GetActiveUniform and GetActiveUniformsiv, and 335 corresponding shading language keywords declaring each such type., p. 96) 336 337 Type Name Token | Keyword 338 --------------------------------- 339 DOUBLE | double 340 DOUBLE_VEC2 | dvec2 341 DOUBLE_VEC3 | dvec3 342 DOUBLE_VEC4 | dvec4 343 DOUBLE_MAT2 | dmat2 344 DOUBLE_MAT3 | dmat3 345 DOUBLE_MAT4 | dmat4 346 DOUBLE_MAT2x3 | dmat2x3 347 DOUBLE_MAT2x4 | dmat2x4 348 DOUBLE_MAT3x2 | dmat3x2 349 DOUBLE_MAT3x4 | dmat3x4 350 DOUBLE_MAT4x2 | dmat4x2 351 DOUBLE_MAT4x3 | dmat4x3 352 353Additions to Chapter 3 of the OpenGL 3.2 (Compatibility Profile) Specification 354(Rasterization) 355 356 None. 357 358Additions to Chapter 4 of the OpenGL 3.2 (Compatibility Profile) Specification 359(Per-Fragment Operations and the Frame Buffer) 360 361 None. 362 363Additions to Chapter 5 of the OpenGL 3.2 (Compatibility Profile) Specification 364(Special Functions) 365 366 Modify Section 5.4.1, Commands Not Usable in Display Lists, p. 358 367 368 (add to "Vertex arrays" list) VertexAttribLPointerEXT, and 369 VertexAttribVertexAttribLOffsetEXT. 370 371 (note: GetVertexAttribL* commands are also not allowed in display lists, 372 but is already covered by blanket language in "Other queries") 373 374 375Additions to Chapter 6 of the OpenGL 3.2 (Compatibility Profile) Specification 376(State and State Requests) 377 378 Modify Section 6.1.15, Shader and Program Queries, p. 384 379 380 (add to the last list of commands, p. 387) 381 382 void GetVertexAttribLdvEXT(uint index, enum pname, double *params); 383 384 (modify the third paragraph, p. 388) The query CURRENT_VERTEX_ATTRIB 385 returns the current value for the generic attribute 386 <index>. GetVertexAttribdv and GetVertexAttribfv read and return the 387 current attribute values as four single-precision floating-point values; 388 GetVertexAttribiv reads them as floating-point values and converts them to 389 four integer values; GetVertexAttribIiv reads and returns them as signed 390 integers; GetVertexAttribIuiv reads and returns them as four unsigned 391 integers; GetVertexAttribLdv reads and returns them as four double-precision 392 floating-point values. The results of the query are undefined if the 393 current attribute values are read using one data type but were specified 394 using a different one. The error INVALID_OPERATION is generated if index 395 is zero, as there is no current value for generic attribute zero. 396 397 398Additions to Appendix A of the OpenGL 3.2 (Compatibility Profile) 399Specification (Invariance) 400 401 None. 402 403Additions to the AGL/GLX/WGL Specifications 404 405 None. 406 407Modifications to The OpenGL Shading Language Specification, Version 1.50 408(Revision 09) 409 410 Including the following line in a shader can be used to control the 411 language features described in this extension: 412 413 #extension GL_EXT_vertex_attrib_64bit : <behavior> 414 415 where <behavior> is as specified in section 3.3. 416 417 New preprocessor #defines are added to the OpenGL Shading Language: 418 419 #define GL_EXT_vertex_attrib_64bit 1 420 421 422 Modify Section 4.3.4, Inputs, p. 31 423 424 (modify third paragraph of the section, p. 31, allowing double-precision 425 vertex shader inputs) ... Vertex shader inputs can only be single- or 426 double-precision floating-point scalars, vectors, or matrices, or signed 427 and unsigned integers and integer vectors. Vertex shader inputs can also 428 form arrays of these types, but not structures. 429 430 431GLX Protocol 432 433 !!! TBD !!! 434 435Dependencies on OpenGL 3.1 and OpenGL 3.2 436 437 When using an OpenGL 3.1 context without support for the ARB_compatibility 438 extension or the core profile of OpenGL 3.2, remove the pseudocode 439 describing the operation of ArrayElement. The core profile specifies 440 commands like DrawArrays and DrawElements more concisely. Additionally, 441 remove edits relevant to (deleted) display list functionality. 442 443Dependencies on EXT_direct_state_access 444 445 If EXT_direct_state_access is not supported, references to the function 446 VertexArrayVertexAttribLOffsetEXT should be removed. 447 448Dependencies on NV_gpu_shader5 449 450 If NV_gpu_shader5 is not supported, references to the sized data types 451 provided by these extensions (e.g., int8_t, float16_t, u16vec4, f64vec2) 452 in Table X.1 should be removed. The full set of types in the table is 453 provided for completeness. 454 455Dependencies on NV_vertex_attrib_integer_64bit 456 457 The extension NV_vertex_attrib_integer_64bit provides similar 458 VertexAttribL* support for 64-bit signed and unsigned integer vertex 459 shader inputs. That extension also uses the VertexAttribLPointerEXT 460 function to specify 64-bit integer vertex attribute arrays. 461 462 Even if an application only uses 64-bit floating-point values in their 463 vertex shader, NV_vertex_attrib_integer_64bit may still be useful. That 464 extension also provides the VertexAttribLFormatNV function, which allows 465 the "bindless" vertex attribute array support provided by the 466 NV_vertex_buffer_unified_memory extension to be used with 64-bit 467 components, integer or floating-point. 468 469Errors 470 471 For all VertexAttrib*EXT commands, the error INVALID_VALUE is generated if 472 <index> is greater than or equal to MAX_VERTEX_ATTRIBS. 473 474 For VertexAttribLPointerEXT, VertexAttribLFormatEXT, and 475 VertexArrayVertexAttribLOffsetEXT, the error INVALID_VALUE is generated if 476 <index> is greater than or equal to MAX_VERTEX_ATTRIBS. 477 478New State 479 480 None. 481 482New Implementation Dependent State 483 484 None. 485 486Issues 487 488 (1) Should we allow 64-bit double-precision vertex attributes in the OpenGL 489 API? If so, how should we handle 64-bit double-precision values? 490 491 RESOLVED: Yes, we will allow vertex shader inputs to have any scalar 492 or vector type, including sized types. Doubles appear to the API as any 493 other type. The new 'L' versions of the entry points are added to 494 distinguish 64-bit attributes from existing DOUBLE support, where doubles 495 are down-converted to floats. 496 497 (2) How does the handling of 64-bit vertex attribute components in this 498 extension interact with the existing vertex attribute functions that 499 support doubles? 500 501 UNRESOLVED: While it is possible for fixed-function pipeline 502 implementations to operate directly on doubles, most (if not all) such 503 implementations simply convert doubles to floats. The OpenGL Shading 504 Language has not supported double-precision types to date, so all 505 previous shading language inputs needed to be converted to float by 506 necessity. 507 508 While it would be possible to support the existing double-precision 509 vertex APIs (e.g., VertexAttrib4dv) to feed shading language variables 510 with double-precision types, any such approach involves the prohibitive 511 dynamic typing overhead discussed above. As a result, we chose to 512 create a parallel VertexAttribL* API. 513 514 A similar approach was chosen for the integer attributes in OpenGL 3.0, 515 where there was a pre-existing set of vertex APIs that accepted integers 516 that were converted to floating-point values via straight value 517 conversion or normalization. Re-using existing integer APIs to feed the 518 (new) integer variable types would have required similarly expensive 519 dynamic typing. 520 521 (3) How should we handle vertex attributes for three- and four-component 522 vectors with double-precision components? How do we support these 523 with vertex arrays? 524 525 RESOLVED: Double-precision attributes may end up consuming twice as 526 many 'slots' as their single precision counterparts. Counting rules are 527 spelled out in this document. The actual allocation of these slots is 528 virtualized by the driver and at the API level, they appear as 529 attributes of any other type would. 530 531 Note that implementations are permitted (but not required) to count 532 double-precision vertex shader inputs as consuming no more input vectors 533 than corresponding single-precision types. 534 535 (4) Are default values supported for vertex attributes with 64-bit 536 components? 537 538 RESOLVED: No. With existing APIs, calling VertexAttrib3f() defines a 539 FOUR-component vector where the fourth component assumes the value 1.0. 540 No such defaults are provided for 64-bit components; if you load the 541 values of an attribute of type "dvec4" with VertexAttribL3dv(), the 542 value of the fourth component of the attribute variable will be 543 undefined. 544 545 The APIs for loading 64-bit vertex attributes were designed to limit the 546 amount of data type conversion required of the implementation; providing 547 new type-dependent default values runs contrary to that design. 548 549 Note that the original defaults were present in part to accommodate 550 fixed-function vertex and fragment processing, where certain operations 551 were defined in the most general form but reasonable defaults allowed 552 targeted optimizations. For example, vertex transformations were 553 defined to operate on four-component object coordinates, even though 554 four-component input positions are relatively rare. Specifying a 555 default W value of 1.0 allows for a fully-general implementation that 556 doesn't need to do special cases based on the input position, but can 557 still choose to do so as an optimization. Programmable shaders, on the 558 other hand, can easily be written to ignore irrelevant components and 559 substitute constants themselves. 560 561 (5) Should this have a separate extension string entry or be simply 562 implied by extensions such as ARB_gpu_shader5 or ARB_gpu_shader_fp64? 563 564 RESOLVED: Treat as a separate extension, since there may be several 565 such extensions with varying capabilities. 566 567 Additionally, we provide a separate GLSL "#extension" identifier for 568 this extension because ARB_gpu_shader_fp64 was adopted without support 569 for vertex inputs with 64-bit components. 570 571 (6) How does this extension provide 64-bit vertex attribute components for 572 assembly programs supported by NV_gpu_program5? 573 574 RESOLVED: NV_gpu_program5 allows programs to declare input variables 575 with 64-bit components using the "LONG ATTRIB" declaration syntax. 576 These inputs will be matched up against corresponding vertex attributes 577 in the same manner as with GLSL. Also, as with GLSL, the values of each 578 vertex program input must be specified with the correct API function 579 (VertexAttrib* vs. VertexAttribL*). 580 581 582Revision History 583 584 Rev. Date Author Changes 585 ---- -------- -------- ----------------------------------------- 586 5 03/21/10 pbrown Minor wording updates to the spec overview, 587 dependencies, issues, and body. 588 589 4 01/29/10 pbrown Update extension to accomodate the removal of 590 fp64 vertex inputs from ARB_gpu_shader_fp64 (bug 591 5953). The API support for enumerating fp64 592 inputs and the GLSL support allowing fp64 vertex 593 inputs now belongs to this extension. For the 594 GLSL support, we add a "#extension" token to 595 specify that fp64 vertex inputs should be 596 allowed. Also, update several issues. 597 598 3 gsellers Updates based on discussion 599 600 2 gsellers EXT'ify. 601 602 1 pbrown Internal revisions. 603 604 605